App links are links that should open your mobile app when it's installed and fall back to the website when it isn't. When they work, nobody notices. When they don't, users land on a web page asking them to log in again, or in the app's home screen instead of the order they tapped, or in a browser tab that loops back to the App Store.
The frustrating part is that these failures are hard to see from a desktop link checker. The URL returns 200. The page exists. The link is "fine", it just doesn't do what it's supposed to.
Here are seven tools for testing them properly. None are paid, and most you already have.
1. curl, for the association files
Both platforms start by fetching a file from your domain:
- iOS:
https://example.com/.well-known/apple-app-site-association - Android:
https://example.com/.well-known/assetlinks.json
Many app-link failures are simply these files being wrong: redirected, served as HTML, blocked by a WAF, or missing on one hostname.
curl -sS -D - -o /dev/null https://example.com/.well-known/apple-app-site-association
curl -sS https://example.com/.well-known/assetlinks.json | python3 -m json.tool
Check for:
- A 200 status, directly, without redirects.
- A JSON content type.
- Valid JSON (the second command will complain if not).
- The same result on every hostname you use in links, including
www.
2. Apple's CDN copy of your association file
iOS devices typically don't fetch your association file directly; Apple's CDN fetches and caches it. So what you serve and what devices see can differ for a while after a change.
You can request the cached copy from Apple's CDN endpoint (the path format is https://app-site-association.cdn-apple.com/a/v1/<your-domain>). If it differs from your live file, devices are working from the old version. This explains a lot of "I fixed it but it still doesn't work" moments.
For development, Apple supports a developer mode for associated domains that bypasses the CDN on test devices; check Apple's current documentation for how to enable it in your entitlements.
3. xcrun simctl openurl, for the iOS Simulator
To test how the app handles a specific link without tapping through Notes or Messages:
xcrun simctl openurl booted "https://example.com/orders/123"
This is quick for checking that your routing code sends each URL pattern to the right screen. Note that the Simulator isn't a perfect stand-in for association behaviour on real devices, so use it for routing tests and confirm association on hardware.
4. adb, for Android devices and emulators
Android gives you more visibility. To open a link:
adb shell am start -a android.intent.action.VIEW \
-c android.intent.category.BROWSABLE \
-d "https://example.com/orders/123"
And to see whether Android has actually verified your domains for the app:
adb shell pm get-app-links com.example.app
The output shows each domain and its verification state. If a domain isn't verified, Android will treat your links as ordinary web links (or show a chooser), regardless of how good your routing code is. On recent Android versions you can also ask the system to re-run verification after fixing your assetlinks.json; see the developer docs for the exact pm verify-app-links options for your target version.
5. Google's Digital Asset Links tools
Google provides a web-based Statement List Generator and Tester for Digital Asset Links. Give it your domain, package name and signing certificate fingerprint, and it checks whether your assetlinks.json grants the association.
The most common failure it catches: the certificate fingerprint. If you use Play App Signing, the fingerprint in the file must match the key Google uses to sign the app distributed through the Play Store, not just your local upload key. Debug builds signed with a debug key need their own entry if you want to test them.
6. Android Studio's App Links Assistant
If your team uses Android Studio, the App Links Assistant (under the Tools menu) helps you add intent filters, generate the association file and test URLs against your manifest. It's especially useful for checking that the pathPattern or pathPrefix rules in your intent filters match the URLs you actually publish, because a link outside those patterns just opens the browser.
7. A plain list of real links, tested by hand
The least glamorous tool is the most useful: a list of real URLs from real places your links appear (marketing emails, push notifications, QR codes, support macros, social posts, SMS) and a habit of tapping each one on a real iOS and Android device before a release.
Two things this catches that the tools above miss:
-
Tracking wrappers. Email platforms often rewrite links through a click-tracking domain. The user taps a link on
click.mailer.example.net, which redirects to your domain. Depending on platform behaviour, that redirect can stop the app from opening. Test links from actual sent emails, not from your source templates. - In-app browsers. Links tapped inside some social and messaging apps open in their own browser views, which may not hand off to your app the way the system browser does.
A short release checklist
- [ ] Association files return 200, JSON, no redirects, on every hostname.
- [ ] Apple's CDN copy matches the live file.
- [ ]
pm get-app-linksshows domains as verified on a test device. - [ ] Each URL pattern routes to the right screen, including logged-out states.
- [ ] Links from real emails, QR codes and notifications open the app.
- [ ] Fallback to the website works when the app isn't installed.
Regular checks that the web side of these links still resolves, including the association files, are part of what linkbruno.com handles.
Related reading
- Experiment: what share of the links in your GitHub READMEs still work? Measure every repo you own in 15 minutes
- '0 broken links found' is a myth: 7 places link checkers don't look
- Every URL in your error messages is a promise: a 10-point checklist for links baked into software
- Quick tip: your link checker probably skips mailto: and tel: links. Check them yourself in 40 lines
Which app-link failure has cost you the most debugging time: association files, signing fingerprints, or tracking redirects?
Top comments (0)