iOS developer & learning

Apple App Site Association (AASA) validator

Paste your apple-app-site-association file to check its structure, app IDs and components, then test URLs to see which rule matches first and which app opens.

Paste the file: a web page can't download another site's /.well-known/apple-app-site-association because browsers block cross-origin reads (CORS), so this tool doesn't fetch your domain. Copy the commands below to fetch it yourself.

    Test URLs against your rules

      A model of Apple's documented matching rules, not a device test. Confirm on a device with Settings > Developer > Universal Links > Diagnostics.

      Check your app's entitlement

        Fetch it yourself

        Free to use, no account. More developer tools

        What the validator checks

        • The file is valid JSON (no comments, no trailing commas) and no larger than 128 KB, Apple's limit for the uncompressed file.
        • Every app ID is <App ID prefix>.<bundle ID>, where the prefix is the 10-character, uppercase Team ID in almost every case. A bundle ID on its own never matches.
        • components entries use only the keys Apple defines: /, ?, #, exclude, comment, caseSensitive and percentEncoded. exclude has to be a JSON boolean; "true" in quotes is a string and is flagged.
        • Substitution variables like $(lang) or your own $(food) are defined, and their values don't nest other variables.
        • An entry doesn't mix components with the legacy paths array. Apple's TN3155 warns that mixing formats leads to unexpected behaviour.
        • An exclude that can never run, because an earlier rule such as {"/": "/*"} already matched the same URLs, is reported with the rule that shadows it.

        How URL matching works

        For each app in details, the system walks components from top to bottom and stops at the first one whose path, query and fragment patterns all match. If that component has "exclude": true the URL opens in the browser; otherwise the app opens. No match means the browser. In patterns, * matches any run of characters, ? matches exactly one, and ?* means at least one. A ? key with an object matches named query items, so {"articleNumber": "????"} requires that item with a four-character value. Matching is case sensitive unless you set "caseSensitive": false, in a component or in defaults. The tester applies those rules to each URL you list and shows which component decided, per app.

        Hosting checklist

        • Serve it at https://<domain>/.well-known/apple-app-site-association, with no file extension, over HTTPS with a valid certificate.
        • Return 200 with no redirect. Apple's CDN doesn't follow redirects, so example.com redirecting to www.example.com breaks it. Host the file on every domain and subdomain you list.
        • Send it as JSON (application/json), unsigned, and reachable from any IP address: no login, firewall rule or bot protection in front of it.
        • Add applinks:<domain> to the Associated Domains capability, with no https://, path, port or trailing slash. *.example.com covers subdomains. The entitlement box above checks these entries.

        Apple's CDN

        Since iOS 14 and macOS 11, devices don't fetch the file from your server. Apple's CDN requests it within about 24 hours, devices download it from the CDN when the app is installed, and they check for updates roughly once a week. There is no way to purge the CDN. The second command above shows what the CDN currently serves; if it differs from your server, wait or test with ?mode=developer on a development device, which bypasses the CDN.

        Questions

        Why do my universal links open Safari?

        Common causes: the app ID prefix is missing or wrong, the file redirects or sits behind bot protection, the CDN still has an old copy, an exclude or earlier rule matches first, or you typed the URL in Safari's address bar, which never opens an app. Links tapped from the same domain also stay in the browser.

        Should I use components or paths?

        Use components for iOS 13 and later: they match path, query and fragment separately and make exclusions explicit with exclude. paths is the older string format with NOT prefixes. Keep one format per details entry.

        How long does Apple's CDN cache the file?

        Apple says the CDN requests your file within 24 hours and devices check for updates about once a week after installing the app. There is no manual purge; reinstalling the app makes a device fetch the CDN's current copy.

        Does the file need a .json extension?

        No. The file is named apple-app-site-association with no extension and lives in /.well-known/. Serve it with a JSON content type.

        How do I debug universal links on a device?

        Turn on Developer Mode, then in Settings > Developer turn on Associated Domains Development and open Diagnostics under Universal Links. Enter the full URL to see whether it is valid for an installed app. On a Mac, sudo swcutil verify checks a local copy of the file against a URL.

        From the same developer