Why don’t my links open the app?
Link Doctor reads your domain from the outside, exactly as Apple and Google read it, and reports what is wrong with the fix for each thing. It needs no account and no SDK, and it works on any domain, whoever hosts it.
The six things that break links
- The file is reachable, over HTTPS, with no redirect
- Both platforms fetch the association file directly and refuse to follow a redirect. A host that redirects the apex to www, or http to https, serves nothing as far as they are concerned.
- The content type and the bytes
- application/json, valid JSON, and no byte-order mark. A BOM in front of the opening brace is invisible in an editor and fatal to the parser.
- The app IDs match, prefix included
- An iOS app ID is the Team ID and the bundle identifier together. A file that lists the bundle identifier alone verifies for nobody.
- The fingerprint is the one Google signs with
- If Play App Signing is on, Google re-signs your release with its own key. A file listing only the upload key's fingerprint works in testing and fails for every real user.
- The paths you actually link to are covered
- Path patterns are declared separately per platform, and they drift. This is why a link opens the app on Android and the browser on iOS.
- Apple's mirror, which is the copy devices read
- iOS does not fetch from your server; it fetches from Apple's CDN. A fixed file that Apple has not re-fetched is still broken on the phone.
The same check runs in your build
vouch-doctor is a single Go binary that performs these checks locally. Point it at a build and it reads the team ID, bundle identifier, package name and signing fingerprint out of the binary rather than trusting flags, which is how it catches an upload key published as the release fingerprint.
go install github.com/vouch-dev/vouch/services/vouchd/cmd/vouch-doctor@latest vouch-doctor check --host links.example.com \ --bundle-id app.roam.ios --team-id ABCDE12345 \ --package app.roam --aab build/app-release.aabIt exits 0 when nothing is wrong, 1 when there is an error-severity finding and 2 when the tool itself could not run, so a release that would break links fails the build. --json prints the whole report, and --warnings-as-errors tightens it.