How to Host the apple-app-site-association File
Put a JSON file named apple-app-site-association — no extension — at /.well-known/ on your domain, serve it over HTTPS with a JSON content type and no redirects, and add the Associated Domains entitlement to your app. That is the whole requirement. The reason it still goes wrong constantly is that every way of getting it wrong fails silently.
Published 2026-08-26 · Last updated 2026-08-26
Why a broken AASA file gives you no error
Since iOS 14, your file is not fetched by the device on every tap. Apple's CDN retrieves it when your app is installed or updated, and the device uses the cached result. If the file is wrong or briefly unreachable at that moment, the association is simply never established — links open in Safari, nothing is logged, and only the people who installed during that window are affected.
This is the single most important thing to understand about hosting this file, and it is also the detail most guides get wrong — you will often read that iOS fetches the file at link-tap time and falls back to Safari if the request is slow. That has not been true for years.
The practical consequences are worth spelling out. A deploy that briefly 404s the file does not roll back cleanly: everyone who installed during that window keeps a broken association until they update the app again. And because your own device already has a working association cached, you can be entirely unable to reproduce a bug that a fresh installer hits every time.
The actual requirements
Short list, and all of it is load-bearing. Anything missing here is a claim we could not verify against Apple's own documentation, which is why you will not find invented uptime or response-time targets on this page.
| Requirement | Detail |
|---|---|
| Exact path | /.well-known/apple-app-site-association — iOS has no discovery mechanism |
| No file extension | The filename is apple-app-site-association, not ….json |
| HTTPS | Valid certificate from a recognised CA; self-signed fails |
| JSON content type | application/json — an extensionless file is often mislabelled text/plain |
| No redirects | Not even www to non-www; serve a 200 directly |
| Publicly reachable | No auth, no IP allowlist, no WAF rule blocking unknown clients |
| Valid JSON | No trailing commas, no comments, no single quotes |
| One file per host | example.com and links.example.com each need their own |
One thing you do not need
The file does not have to be cryptographically signed. Apple required that in the earliest days of Universal Links and dropped it back in the iOS 9.3 era. If a tutorial tells you to sign it with your certificate, that tutorial is a decade old.
Writing the file
The modern format uses a components array, which supports path matching, query parameters, fragments and exclusions. The older paths array still works and is fine if you only need simple prefix matching.
{
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.yourcompany.yourapp"],
"components": [
{ "/": "/products/*" },
{ "/": "/articles/*" },
{ "/": "/admin/*", "exclude": true, "comment": "keep admin on the web" }
]
}
]
}
}ABCDE12345is your Apple Developer Team ID and the rest is your bundle identifier. Keep the rule list short — long, heavily-wildcarded configurations are hard to reason about and are a recurring source of "why does this one URL open Safari" bugs.
Serving it with the right headers
Because the filename has no extension, most web servers will not infer a JSON content type and will fall back to something like text/plain or an octet stream. You have to set it explicitly.
nginx
location = /.well-known/apple-app-site-association {
default_type application/json;
add_header Cache-Control "public, max-age=3600";
}Apache
<Files "apple-app-site-association">
ForceType application/json
</Files>Verify what you actually shipped
curl -sSI https://yourdomain.com/.well-known/apple-app-site-association
# Want: HTTP/2 200 and content-type: application/json
# Any 3xx is a failure, even a redirect you think is harmless.Or paste the domain into our AASA checker, which additionally parses the JSON and reports on the app IDs and path rules it finds.
Testing it on a real device
Turn on Associated Domains Development mode. On the device, Settings → Developer → Associated Domains Development, and append ?mode=developer to the entitlement while you are testing. This makes the device fetch your file directly instead of going through Apple's CDN, so a change you just deployed takes effect immediately rather than after a reinstall. Remove it before you ship.
Two things that look like bugs but are not: Universal Links are unreliable in the Simulator, and typing or pasting a URL into Safari's address bar never opens the app. That second one is deliberate on Apple's part. Test by tapping a link in Messages, Notes or Mail.
If a link opens Safari and you want to get back to app behaviour, pull down on the page — iOS shows a banner that lets you open it in the app and re-arms the association.
The mistakes that actually happen
A redirect in the way
A www to non-www rule, or an HTTP to HTTPS hop that also rewrites the path. Apple will not follow it. Serve a 200 at the exact URL.
Wrong content type
The extensionless filename means the server guesses, and it usually guesses wrong. Set it explicitly.
The file behind a WAF or allowlist
Security rules that block unfamiliar clients also block Apple. This one is common in enterprises where the security team was never told the file has to be publicly reachable.
A new subdomain nobody deployed to
Marketing launches a campaign on promo.example.com. There is no file there and no entitlement entry for it, so every link opens Safari.
Team ID and bundle ID mismatch
The appIDs entry has to match your entitlement exactly. A staging bundle ID in a production file silently breaks everything.
A certificate that expired
Universal Links stop being established at the next install or update, quietly, while your website looks fine to anyone who clicks through the browser warning.
Testing only on your own phone
Your device already has a working association cached. You cannot reproduce what a fresh installer sees without a clean install or developer mode.
Or don't host it yourself
Everything above is genuinely doable on your own infrastructure, and if you already control a domain with predictable deploys, doing it yourself is a reasonable choice. What you are taking on is the ongoing part: certificates, headers surviving a server config change, the file staying reachable through every deploy, and a new file every time someone launches a campaign on a new host.
DeepTap does that part. You pick a subdomain such as myapp.deeptap.io, enter your Bundle ID and Team ID, and the file is generated and served correctly from then on. There is no DNS to configure; custom branded domains are on the Pro plan. Android's assetlinks.json is handled the same way. From $5.99 a month.
Frequently asked questions
Where exactly does the apple-app-site-association file go?
At https://yourdomain.com/.well-known/apple-app-site-association. The filename has no extension — not .json — and the path is exact, because iOS has no discovery mechanism and will not look anywhere else. Older iOS versions also accepted the file at the domain root, but .well-known is the location to use today.
Does the file need to be cryptographically signed?
No. Apple required a signed file only in the very earliest days of Universal Links and dropped that requirement back in the iOS 9.3 era. A plain JSON document is correct. Guides that still tell you to sign it are years out of date.
Why did my Universal Links stop working with no error message?
Because that is the normal failure mode. Since iOS 14 the file is fetched by Apple’s CDN when your app is installed or updated, not on every tap. If the file is malformed, behind a redirect, served with the wrong content type, or briefly unreachable at that moment, the association simply does not get established. Links open in Safari instead of your app, nothing is logged, and only the users who installed during that window are affected.
What are the actual hosting requirements?
HTTPS with a certificate from a recognised authority; a JSON content type; no redirects of any kind, including www to non-www; a 200 response; and public reachability with no authentication, IP allowlist, or WAF rule in the way. Apple fetches this from its own infrastructure, so anything that blocks unknown clients will break it.
How do I test it on a real device?
Enable Associated Domains Development mode on the device (Settings, Developer, Associated Domains Development) and add ?mode=developer to your associated-domains entitlement while testing. That makes the device fetch your file directly instead of going through Apple’s CDN, so changes take effect immediately rather than waiting for a reinstall. Remember to remove it before shipping. Universal Links do not behave reliably in the Simulator, and tapping a link in Safari’s address bar never opens the app by design.
Do I need a separate file for each subdomain?
Yes. iOS treats example.com and links.example.com as different domains. Each one that appears in your links needs its own file at its own .well-known path, and each needs its own entry in the Associated Domains entitlement. This is the most common way a working setup breaks: marketing launches a campaign on a new subdomain that nobody deployed the file to.
Can I host it on a CDN?
Yes, provided the CDN serves it over HTTPS with a JSON content type, does not redirect, and does not serve a stale copy after you update it. Misconfigured caching and a content type inferred from the extensionless filename are the two things that most often go wrong.
How does DeepTap handle this?
You pick a subdomain such as myapp.deeptap.io and enter your Bundle ID and Team ID. The file is generated, served at the correct path with the correct headers and certificate, and kept that way. There is no DNS to configure on the default plan; custom branded domains are available on the Pro plan. Plans start at $5.99 per month with a 7-day free trial.
Related reading
Free AASA checker
Validate any domain's file, headers included. No sign-up.
iOS Universal Links guide
Entitlements, routing code, and deferred links in Swift.
Android App Links guide
The assetlinks.json equivalent, and how verification differs.
SDK-free deep linking
What a hosted deep-link platform adds on top of these files.