Deep linking
Universal Links and App Links explained: a setup guide for indie app makers
How Universal Links and App Links open your app from a normal https link: what goes in apple-app-site-association and assetlinks.json, how to set them up, and the traps that open the browser instead.
Universal Links on iPhone and App Links on Android are ordinary https links that open your app instead of the browser when the app is installed. Both work the same way: you publish a small JSON file on your domain, and you name that domain inside your app. That proves the app and the website belong together. When the app isn't installed, the link opens in the browser like any other web page.
Apple's file is called apple-app-site-association. Google's is assetlinks.json. This guide shows what goes in each, how to set them up, and the traps that catch most indie developers.
The two side by side
| Universal Links (iOS) | App Links (Android) | |
|---|---|---|
| File on your domain | /.well-known/apple-app-site-association | /.well-known/assetlinks.json |
| Identifies your app by | Team ID and bundle ID | Package name and SHA-256 signing fingerprint |
| Declared in the app | Associated Domains entitlement: applinks:yourdomain | An intent filter with android:autoVerify="true" |
| Who fetches the file | Apple's CDN, not the phone | The phone, through Android's verifier |
| App not installed | Opens in the browser | Opens in the browser |
| Official tester | Notes app long-press, swcutil (TN3155) | adb pm get-app-links, Google's Statement List tester |
Neither one sends people to the store when the app is missing. For that you need a smart link in front, or a web page with store badges. And neither one remembers where someone was going after they install. That's deferred deep linking, a separate problem.
Set up Universal Links
- Publish the file at
https://yourdomain/.well-known/apple-app-site-association, with no file extension. Apple requires HTTPS with a valid certificate and no redirects. - List your app and paths. Each
appIDsentry is your Team ID, a dot, and your bundle ID. Thecomponentslist says which paths open the app. Put exclusions first. - Add the entitlement. In Xcode, under Signing and Capabilities, add Associated Domains with
applinks:yourdomain. Use the domain only: no https, no path, no trailing slash. Each subdomain needs its own entry and its own file. See the entitlement reference. - Handle the link in your app. UIKit apps receive an
NSUserActivitywith the URL inwebpageURL. SwiftUI apps get it throughonOpenURL. Validate the URL before you act on it. Apple covers both in Supporting universal links in your app.
{
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.yourapp.ios"],
"components": [
{ "/": "/account/*", "exclude": true },
{ "/": "/*" }
]
}
]
}
}Since iOS 14, phones don't fetch this file from your server. Apple's CDN does, within 24 hours of a change, and devices check for updates about once a week after the app is installed. While you develop, add ?mode=developer to the entitlement to bypass the CDN on a device in developer mode.
Set up App Links
- Publish the file at
https://yourdomain/.well-known/assetlinks.json, served asapplication/jsonover HTTPS with no 301 or 302 redirects. - Use the right fingerprint. If Google Play signs your app, the fingerprint from your local keystore usually won't match what phones see. Copy the SHA-256 from Play Console, under App signing. It also shows a ready-made assetlinks.json snippet.
- Add the intent filter with
android:autoVerify="true", the VIEW action, the DEFAULT and BROWSABLE categories, and your https host. Don't add other schemes to the same filter, because that prevents verification. - Check verification with
adb shell pm get-app-links com.yourapp.android. The domain should show as verified. Google's Statement List tester checks the file from the outside.
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.yourapp.android",
"sha256_cert_fingerprints": ["14:6D:E9:83:...:5E"]
}
}]<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="links.yourapp.com" />
</intent-filter>Verification matters more since Android 12. If your app isn't verified for a domain, a web link opens in the user's default browser instead of offering your app. Google's verification guide has the adb commands to reset and re-run it while you test.
Traps that make links open the browser
- Typing the URL. On iPhone, a URL typed into the browser's address bar never opens the app. Test by pasting the link into Notes and tapping it.
- Same-domain links. If someone is already on your website in Safari and taps a link to the same domain, iOS keeps them in Safari. Links from a different domain open the app.
- Redirects in front of the file. Apple and Google both refuse the file if its URL redirects, for example from the bare domain to
www. Serve it directly on the exact host your links use. - In-app browsers. Links tapped inside Instagram, TikTok or other social apps often stay in that app's browser. Test there separately.
- The wrong build. The entitlement or intent filter has to be in the build that's installed, not only in your project.
If your file checks out but iPhones still open Safari, our Universal Links troubleshooting checklist goes through the next checks in order.
If you'd rather not host the files
You need a domain you control to publish these files. If your marketing site runs on a builder that won't serve files from /.well-known/, or you don't want to maintain them, a link service can host them for you.
On URX, Pro publishes apple-app-site-association for urx.si. Add your Team ID and bundle ID to your project, add applinks:urx.si to your app, and your urx.si/yourapp links open the app on iPhone. App Links need a domain your app can verify on its own, so they work on a custom domain such as links.yourapp.com, which comes with Growth. URX serves both files there. The link's Deep linking tab shows what Apple and Google see.
Whatever you use, the free AASA validator checks your file and Apple's CDN copy. To start with store routing and add deep links later, claim a free link. The deep-linking page explains each link type.
Questions people ask
What is the difference between Universal Links and App Links?
They do the same job on different systems. Universal Links are Apple's, verified with an apple-app-site-association file and the Associated Domains entitlement. App Links are Android's, verified with an assetlinks.json file and an intent filter with autoVerify. Both open your app from an https link when it's installed.
Where does the apple-app-site-association file go?
At https://yourdomain/.well-known/apple-app-site-association, with no file extension, over HTTPS with a valid certificate and no redirects. Each subdomain needs its own file.
Why do my Universal Links open Safari instead of the app?
Common causes are typing the URL into Safari's address bar, tapping a link to the same domain you're already browsing, a redirect on the file, an entitlement missing from the installed build, or Apple's CDN still holding an old copy of the file.
Which SHA-256 fingerprint goes in assetlinks.json?
If Google Play signs your app, use the app signing key fingerprint from Play Console, under App signing. The fingerprint of your local upload key usually won't match what users' phones see.
What happens if the app isn't installed?
Both open the link in the browser like a normal web page. Neither sends people to the store on its own, so put a smart link or a page with store badges at that address.
Sources and product references
Reviewed November 5, 2026. Platform guidance and product limits can change; use these references when you repeat a check.
- Apple: Supporting associated domains
- Apple: Associated Domains entitlement
- Apple: Supporting universal links in your app
- Apple: Allowing apps and websites to link to your content
- Apple TN3155: Debugging universal links
- Android: Configure assetlinks.json
- Android: Add App Links intent filters
- Android: Verify App Links
- Android 12 behavior changes: web intents
- Google: Statement List Generator and Tester
Start with the link, add the app later.
Store routing is free. On Pro, URX hosts the association file on urx.si so your links open your app on iPhone.
Claim your free linkClaim
your link.
Type the name you want. Then paste your store links and scan it with your phone.