Short answer: Each details entry needs URL patterns. Without a components array (or the legacy paths array), or with an empty one, the entry claims no URLs and every link opens the browser. Add at least one rule, such as { "/": "/product/*" }.
What is happening
AASA components: the array of pattern dictionaries in a details entry that tells iOS which URLs open the app, matching on path (/), query (?) and fragment (#).
An entry with app IDs but no patterns is valid JSON and has the right app, but it applies to nothing. Apple's components reference describes each pattern key and its default, and a URL must match "all the components that a components object specifies".
sudo swcutil verifyon a Mac never printsPattern "..." matched.for any URL you test.- An empty
pathsarray in the legacy format has the same effect.
Why does this happen?
The rules are often left out while the file is set up "for later", or removed when someone tries to stop links opening the app. Templates that use placeholder arrays also cause it.
- Placeholder file:
"components": []left from a template. - Deliberate removal: emptying the rules to pause universal links, then forgetting to restore them.
- Wrong key:
componentorpathinstead ofcomponentsorpaths.
How to confirm it
- Fetch the file:
curl -s https://example.com/.well-known/apple-app-site-association. - Check every
detailsentry has a non-emptycomponentsarray (orpathsin the legacy format). - On a Mac, test a real URL with
sudo swcutil verify -d example.com -j apple-app-site-association -u https://example.com/product/1and look forPattern "..." matched.
How to fix it
- List the URL groups the app can show, for example product pages and user profiles.
- Write one
componentsrule per group, using*for any run of characters. - Add
excluderules for pages that must stay on the web, above the broader rules. Apple says "the first match wins". - Use
componentsonly, without apathskey in the same entry. - Deploy the file and reinstall the app on a test device.
{
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.example.app"],
"components": [
{ "/": "/account/billing", "exclude": true },
{ "/": "/product/*" },
{ "/": "/u/*" }
]
}
]
}
}
Each key in a rule has a default of * for /, ? and #, so a rule with only / matches any query and fragment. The universal links setup guide shows a working file, and path not matched covers rules that exist but miss some URLs.