Managing link verification across multiple apps and bundle IDs
One AASA, several bundle IDs, debug plus release fingerprints — kept correct automatically as you add build targets.
A single app with one bundle ID and one signing key is the easy case for Universal Links and App Links. Real products outgrow that fast: a white-label build, a staging app, a debug variant, an acquisition that adds a second package. Every one of those needs to appear in your association files, correctly, or links silently stop opening the app.
When one appID isn't enough
The moment you ship more than one build that should open the same links, your AASA needs multiple appIDs and your assetlinks.json needs multiple targets. Miss one and that build falls back to the browser with no error — the worst kind of failure, because it looks fine in QA on the build you remembered to add.
{
"applinks": {
"details": [
{
"appIDs": [
"TEAMID.com.example.app",
"TEAMID.com.example.app.staging"
],
"components": [{ "/": "/l/*" }]
}
]
}
}Android is the same story: one object per package, and crucially one fingerprint per signing key — debug and release are different keys, so both belong in the list while you're still sideloading test builds.
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": ["AA:BB:...debug", "CC:DD:...release"]
}
}
]Which signing fingerprints do I actually need?
More than you think, and a missing one is the single most common reason App Links open the browser. You ship under a different key in almost every distribution path, and each of those keys needs its SHA-256 fingerprint listed in assetlinks.json.
| Build path | Signed by | Needed in assetlinks.json? |
|---|---|---|
| Play Store (Play App Signing) | Google's app signing key | Yes — this is the one people miss |
| Play internal testing | Google's app signing key | Covered by the above |
| Sideloaded release APK | Your upload key | Yes, while you distribute builds directly |
| Local debug build | Each machine's debug key | Yes, if you test App Links on debug builds |
| Firebase App Distribution | Whichever key built it | Yes, matching that key |
The Play App Signing row is the trap. You upload an APK signed with your key, Google re-signs it with theirs, and the fingerprint on a user's device is one you have never seen locally. Take it from the Play Console's app signing page, not from your keystore — and if links work on your sideloaded build but not from the store, this is almost certainly why.
How do you handle staging without breaking production?
Give staging its own link domain rather than sharing production's. It is tempting to add the staging bundle ID to the production AASA and be done, but that means a staging build on any device will claim production links — and on Android, whichever verified app is installed can intercept them.
A separate domain per environment keeps the blast radius contained, makes the association files easy to reason about, and means a mistake in staging config cannot take down real user links. Do add every environment's bundle ID and fingerprint to its own domain, though, or your QA builds fail in ways that look like product bugs.
Regenerate, don't hand-edit
The failure mode is always a stale, hand-maintained file. Treat the association files as generated artifacts keyed off your registered bundle IDs and signing certs, so adding a build target updates them automatically. A managed link domain does this for you and serves both files with the correct content type and no redirects.
Verify it's actually live
Trust nothing until you've checked the wire — our free Universal Links validator fetches both association files for any domain and flags the classic mistakes. The two failures that bite hardest are a wrong Content-Type on the extension-less AASA and a redirect in front of it — Apple's fetch follows neither.
curl -sI https://yourapp.linktrail.io/.well-known/apple-app-site-association | grep -i content-type
# Expect: content-type: application/json
adb shell pm verify-app-links --re-verify com.example.app“A deep link that opens the browser doesn't throw an error. That's exactly why it survives to production.”
Ahsan
LinkTrail Engineering
Ahsan is on the LinkTrail engineering team and the engineer behind its SDKs for iOS, Android, React Native, and Flutter. He started the company after the Firebase Dynamic Links shutdown left teams with links that opened the store and forgot where the user was going — and after too many vendor calls that ended without a price. He writes here about deferred deep linking, install attribution after ATT, and the parts of the mobile growth stack the category tends to leave vague.
All posts by Ahsan