Short answer: Universal links need three things: an Associated Domains entitlement in the app (applinks:example.com), an apple-app-site-association file at https://example.com/.well-known/apple-app-site-association naming the app, and code that handles the incoming URL. Test by tapping links from Notes, never by typing into Safari.
What is a universal link?
Universal link: an ordinary https URL on a domain you control that iOS opens directly in your app when the app is installed, and in the browser when it is not.
Unlike a custom URL scheme, a universal link is tied to a domain you prove you own, and it always has a web fallback. Apple says that if the person hasn't installed the app, "the system opens the URL in their default web browser".
Step 1: add the Associated Domains entitlement
In Xcode, open your target's Signing & Capabilities tab, add Associated Domains, and list each domain:
applinks:example.com
applinks:www.example.com
applinks:go.example.com
- Use the form
<service>:<fully qualified domain>. - Apple says: "Don't include path and query components or a trailing slash."
- Ports are not supported: "Domains in your applinks can't contain a port number."
- A wildcard such as
applinks:*.example.comcovers all subdomains, with the file served at the apex. - Each specific subdomain is separate. A file on
example.comdoes not coverapplinks:www.example.com. - Web browsers and apps with the web-browser entitlement "are not allowed to register universal links".
Step 2: write the AASA file
Create a file named apple-app-site-association, with no extension:
{
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.example.app"],
"components": [
{ "/": "/account/*", "exclude": true },
{ "/": "/product/*" },
{ "/": "/u/*" }
]
}
]
}
}
- App IDs are
<Application Identifier Prefix>.<Bundle Identifier>. - Rules are checked in order and "the first match wins", so exclusions go first.
- Use
components, not the legacypaths, and don't mix the two.
Check the file you publish with curl -I https://example.com/.well-known/apple-app-site-association and sudo swcutil verify on a Mac.
Step 3: host the file correctly
- Serve it at
https://<domain>/.well-known/apple-app-site-associationon every domain in the entitlement. - Use HTTPS "with a valid certificate and with no redirects". Apple says 301 and 302 responses are not supported.
- Allow all regions, IP addresses and user agents, so Apple's CDN can fetch it.
- Serve it as JSON. Apple's archived guide describes
application/json. - Keep it under 128 KB uncompressed, the limit in Apple's archived documentation.
Check delivery with curl -v and with Apple's user-agent test, curl -A "MyAgent-Bot/*" https://example.com/.well-known/apple-app-site-association. If the response is a redirect or a 403, Apple's CDN cannot use the file.
Step 4: handle the link in the app
When a universal link opens the app, iOS delivers the URL through an NSUserActivity. Your app reads the URL and routes to the right screen.
- Parse the path and query and map them to screens.
- Fall back to a sensible screen for URLs the app does not recognise.
- Route your own links internally. Apple says if your app uses
openmethods to open a universal link to your own website, "the link won't open in your app".
Why does a universal link open Safari?
Usually because of how the link was opened, not the file. The three common cases are typed links, same-domain taps and in-app browsers.
- Typed or pasted into Safari: never treated as a universal link. See typed links.
- Tapped on your own website: same-domain navigation continues in Safari. Use a separate link domain.
- Tapped inside a social app: Apple says support is "up to third-party web browsers".
- User choice: choosing to open a domain in the browser "will set the default behavior for your device".
Step 5: test on a device
Apple's CDN fetches your file within 24 hours, and devices check for updates about once a week after install. While setting up:
- Add
?mode=developerto the entitlement, for exampleapplinks:example.com?mode=developer. This bypasses the CDN on development-signed builds. - Turn on Developer Mode, then Settings > Developer > Universal Links > Associated Domains Development.
- Use Settings > Developer > Universal Links > Diagnostics to test a URL.
- Paste links into Notes, tap them, and long-press to see the app and browser options.
- On a Mac, run
sudo swcutil verify -d example.com -j apple-app-site-association -u https://example.com/product/1. - For a full picture, capture a sysdiagnose and read
swcutil_show.txt.Site/Fmwk Approval: approvedmeans the CDN fetched and matched the file.
Remove ?mode=developer before release. Then repeat the Notes and swcutil tests on a production build.