Apple App Site Association Validator Guide: Check Your AASA File
A universal link is a web link that opens an app instead of a browser when the app is installed, falling back to the website when it is not. For that handoff to be trusted, Apple requires the website to publish a file proving the association: the Apple App Site Association file, usually called the AASA file, served from the site's well-known location. If that file is missing, malformed, or wrong, universal links fail silently, and users land in the browser even with the app installed, wondering why the promised app experience never arrived.
The Apple App Site Association Validator tool validates pasted association file JSON structure. You paste the file's JSON text, and it checks whether the structure matches the expected shape: the right top-level sections, the right nesting, and the right kinds of values. It validates structure, not deployment: it does not fetch the live file from your site, confirm it is served from the correct path with the correct content type, or prove that any app identifier in it is real. A file that passes structural validation still needs those deployment checks, and a file that fails structural validation will not work no matter how well it is deployed.
The AASA file's structure is JSON, and its most important section is applinks, which contains details of which apps may handle which paths, and, in newer formats, components that describe URL patterns more precisely. Each app is identified by a team identifier combined with a bundle identifier, in the form TEAMID.com.example.myapp, where the team identifier is issued by Apple and the bundle identifier is the app's unique name. Paths are patterns: a simple path matches one URL, a wildcard pattern matches many, and a NOT prefix excludes a path from matching. Getting any of those pieces wrong, a mistyped team identifier, a bundle identifier that does not match the app, or a path pattern that is too broad or too narrow, breaks the association for exactly the links it was meant to enable.
A worked example you can follow
Take a sample AASA file for one app, with team identifier ABCDE12345 and bundle identifier com.example.myapp, giving an app identifier of ABCDE12345.com.example.myapp. Suppose its applinks section allows the paths /articles/ and /products/, and excludes /articles/private/. Counting the pattern set: 2 allowed patterns and 1 excluded pattern, which is 3 patterns in total. Test three sample URLs against that set. First, https://example.com/articles/how-to-start matches /articles/ and does not match the exclusion, so it is handled by the app. Second, https://example.com/articles/private/report matches /articles/ but also matches the exclusion /articles/private/, and the exclusion wins, so it opens in the browser. Third, https://example.com/about matches neither allowed pattern, so it also opens in the browser. The outcomes are 1 app-handled and 2 browser-opened, and 1 plus 2 equals 3, accounting for every tested URL.
Now take a broken sample. Its JSON is missing a closing brace, so the file is not valid JSON at all, and the validator will report a parse error before any structural check can run. The fix is to repair the JSON syntax first, because no structural judgement is possible on text that is not JSON. A second broken sample is valid JSON but nests the applinks section at the wrong level, so the validator reports a missing or misplaced section; the fix is to move the section to the expected nesting. A third broken sample has a valid structure but an app identifier of ABCDE12345.com.example.myap, missing the final p, a difference of 1 character that makes the identifier name a different, nonexistent app. Counting characters is the verification here: the bundle identifier in the file must match the app's bundle identifier exactly, and any difference, however small, breaks the match.
When you paste a file to validate, paste the exact text you intend to publish, not a tidied-up copy, because a tidy copy can pass while the published file still fails. If the file contains comments, note that plain JSON does not allow comments, so a file that works in an editor with comment support may fail as strict JSON; remove comments before publishing, or keep them only in a separate source copy.
Common mistakes to avoid
The first mistake is validating a draft and publishing a different file, which makes the validation meaningless. The second mistake is serving the file from the wrong path or with the wrong content type, so Apple's systems never read it even though its content is correct. The third mistake is using a wildcard path that is broader than intended, such as /*, which hands every link to the app, including pages the app cannot display. The fourth mistake is forgetting the fallback: a universal link on a device without the app must still lead to a useful web page, so the website itself must handle the URL gracefully, not just the app.
The JSON Studio tool helps you format and inspect JSON structure generally, and the Word Counter tool confirms the size of a pasted file. For background on how web addresses and responses work, see HTTP Status Codes Explained.
Checking the result before you publish it
A passing structural validation is step one. Step two is confirming the file is served from the correct well-known path with the correct content type and no redirect in the way. Step three is testing real links on a device with the app installed, and on a device without it, confirming the app and browser outcomes respectively. When structure, serving, and live behaviour all agree, universal links become what they promise: a single link that takes each user to the best available version of the content.
Caching is a quiet trap with association files, because both servers and Apple's systems may cache an older version after you publish a fix. If a corrected file still behaves like the old one, the likeliest explanation is a cached copy somewhere along the path, not a fresh error in the new file. Allow time for caches to expire, test from a device that has not recently fetched the old file, and confirm the served content directly before concluding that a fix failed. Patience with caching, combined with a direct check of what the server actually returns, prevents the frustrating loop of fixing a file that was already fixed.