Android App Links not verified? Fix assetlinks.json
If your https links open Chrome instead of your app, Android couldn't verify your domain. Here's how to read pm get-app-links, fix assetlinks.json and the SHA-256 fingerprint, and re-verify.
On Android, a verified App Link opens your app straight away when someone taps an https:// link. If verification fails, Android 12 and later open the link in the browser, and older versions may show a "which app?" chooser.
The good news: unlike iOS, Android tells you exactly which domains failed. This guide shows how to read that status, the five causes behind most failures, and how to make Android check again without reinstalling.
How App Link verification works
- Your app declares an intent filter with
android:autoVerify="true"for one or more hosts. - When the app is installed (or updated), Android fetches
https://<host>/.well-known/assetlinks.jsonfor every host in those filters. - The file must list your package name and the SHA-256 fingerprint of the certificate that signed the installed APK.
- If it matches, the domain is marked
verifiedand links to it open your app.
Since Android 12, each host is verified separately. On Android 11 and earlier, a single host that fails can stop all of the app's App Links from verifying, so one stray domain in your manifest can break everything.
Step 1: Read the verification state
Install the build you're testing, wait about 20 seconds, then run:
adb shell pm get-app-links com.example.shop
The output looks like this:
com.example.shop:
ID: 01234567-89ab-cdef-0123-456789abcdef
Signatures: [***]
Domain verification state:
links.example.com: verified
www.example.com: legacy_failure
example.org: 1026
What each state means (from Android's docs):
| State | Meaning |
|---|---|
verified |
Works. Links to this host open the app. |
none |
Nothing recorded yet. Wait a few minutes and re-verify. |
legacy_failure |
The verifier rejected it; the reason isn't given. Usually the file or fingerprint. |
approved / denied |
Forced by a shell command, not real verification. |
1024 or higher |
A device-specific verifier error. Check the network and re-verify. |
Any host that isn't verified won't open your app automatically.
Step 2: Check the assetlinks.json file
Fetch it the way the verifier does:
curl -v https://links.example.com/.well-known/assetlinks.json
It must:
- Return HTTP 200 over HTTPS with a valid certificate.
- Not redirect. Android's docs are explicit: a redirect such as
http://→https://orexample.com→www.example.commeans verification fails. - Be served as
application/jsonand be valid JSON. - Exist on every host in your intent filters.
www.example.comandexample.comare different hosts and each needs its own file.
A correct file:
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.shop",
"sha256_cert_fingerprints": [
"14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5",
"FA:C6:17:45:DC:09:03:78:6F:B9:ED:E6:2A:96:2B:39:9F:73:48:F0:BB:6F:89:9B:83:32:66:75:91:03:3B:9C"
]
}
}
]
(The fingerprints above are examples. Use your own.)
Then ask Google directly whether it can read your statements:
https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://links.example.com&relation=delegate_permission/common.handle_all_urls
If your package and fingerprint don't appear in the response, Google can't read your file. Fix the hosting before going further.
Step 3: Get the right SHA-256 fingerprint
Most real-world failures are here. The fingerprint must belong to the key that signed the APK on the device, and that differs depending on how the app was installed:
| How the app was installed | Signing key to list |
|---|---|
| From Google Play (production, internal testing, etc.) | The Play App Signing key: Play Console → Test and release → App integrity → App signing |
| An APK or AAB you built and shared yourself | Your upload / release key |
./gradlew installDebug, Android Studio, react-native run-android, flutter run |
The debug key on your machine |
With Play App Signing, Google re-signs your app, so the fingerprint of the keystore on your laptop won't match the build users install from Play. List every key you need. sha256_cert_fingerprints is an array, so the debug, upload and Play keys can all be listed together.
Get fingerprints locally:
# Debug key
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
# Your release / upload keystore
keytool -list -v -keystore path/to/release.jks -alias your-key-alias
# Every variant at once
./gradlew signingReport
Format matters: uppercase hex pairs separated by colons. Android's troubleshooting page specifically lists a lowercase fingerprint as a cause of failure.
Play Console also shows a ready-made Digital Asset Links JSON snippet on the App signing page. Copying it avoids typos.
Step 4: Check the intent filter
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="links.example.com" />
</intent-filter>
</activity>
Things to check:
android:autoVerify="true"is on the intent filter. Without it, nothing is verified.- All three of
VIEW,DEFAULTandBROWSABLEare present. - Every host listed is one you control and that serves the file. A leftover host (an old Firebase
page.linkdomain, a staging domain without a file) can stop all App Links verifying on Android 11 and earlier, and is simply unverified on Android 12+. - Keep custom schemes in a separate intent filter. Put
myapp://in its own filter withoutautoVerify, so the verified filter only contains thehttpshosts you mean to verify. - Manifest merging. In React Native, Flutter and multi-module apps, inspect the merged manifest (Android Studio → AndroidManifest.xml → Merged Manifest) to see what actually ships.
Step 5: Force Android to verify again
You don't need to reinstall after each fix. Reset and re-run verification:
adb shell pm set-app-links --package com.example.shop 0 all
adb shell pm verify-app-links --re-verify com.example.shop
# wait a minute or two, then:
adb shell pm get-app-links com.example.shop
Then test a link the way a user would open it:
adb shell am start -a android.intent.action.VIEW \
-c android.intent.category.BROWSABLE \
-d "https://links.example.com/product/42"
If the app opens directly with no chooser, verification works.
Two timing notes from Android's docs (checked 2026-10-22): on Android 15 and later, changes to assetlinks.json can take up to seven days to reach devices on their own, and on Android 14 and earlier they're only picked up when the app is installed or updated. During development, --re-verify is how you skip the wait.
Users can turn links off (and on)
Each app has a per-user setting: Settings → Apps → your app → Open by default. A user (or tester) may have turned off "Open supported links", or links may need adding by hand during development on some Android 13+ devices. Check here before assuming verification is broken.
The usual causes
- Play App Signing fingerprint missing. Works from Android Studio, fails from Play.
- Redirect on the file. Often a
wwwredirect or a CDN rule. - A host in the manifest without a file. Especially subdomains.
- The file isn't really JSON. A web framework returns its HTML 404 page with a 200 status, or the wrong content type.
- Lowercase or truncated fingerprint.
A quick checklist
| Check | Command or place |
|---|---|
| Which hosts fail | adb shell pm get-app-links <package> |
| File is 200, JSON, no redirect, on every host | curl -v https://host/.well-known/assetlinks.json |
| Google can read it | Digital Asset Links API statements:list |
| Fingerprint of the key that signed this install | Play Console App signing / ./gradlew signingReport |
autoVerify="true", VIEW + DEFAULT + BROWSABLE |
Merged manifest |
| Re-verify after changes | pm set-app-links … 0 all then pm verify-app-links --re-verify |
Check it in one go
Our free Universal Link & App Link Validator checks assetlinks.json over HTTPS with redirects turned off, checks the content type and JSON structure, validates the package name and fingerprint format, and asks Google's Digital Asset Links API whether it can read your statements. It checks the iOS apple-app-site-association file too; for the iOS side, see Universal Links not working? An iOS debugging checklist.
With CodeOnAir AppLinks, you enter your package name and fingerprints (up to 20, so debug, upload and Play keys can all be listed) and CodeOnAir builds and serves assetlinks.json on every link domain for you. The dashboard's App setup box shows the intent filter with your domains filled in, and a Check button reads the files the way phones do. See the Android SDK setup and AppLink setup docs. Coming from Firebase? Remove your old page.link host from the manifest; the Firebase Dynamic Links alternative page covers the move. AppLinks is on the paid plans (pricing); sign-ups are currently by invitation, so request access.
FAQ
Why do my Android App Links open in the browser?
Android only opens your app automatically for hosts it has verified. If pm get-app-links shows anything other than verified for the host, the link goes to the browser (Android 12+) or shows a chooser. The usual reasons are a missing Play App Signing fingerprint, a redirect on assetlinks.json, or a host in the manifest with no file.
Where do I find the SHA-256 for Play App Signing?
Play Console → your app → Test and release → App integrity → App signing. Use the "App signing key certificate" SHA-256. Add your upload key and debug key as well if you install builds outside Play.
What does legacy_failure mean in pm get-app-links?
The verifier rejected the domain without giving a reason. Check the file over HTTPS without redirects, check the JSON and content type, and check that the fingerprint matches the key that signed the installed build. Then run pm verify-app-links --re-verify.
Does assetlinks.json need to be on the www and the root domain?
Yes, if both are in your intent filters. Every host is checked separately at its own /.well-known/assetlinks.json, and a redirect from one to the other fails verification.
How long does Android take to notice changes to assetlinks.json?
Per Android's docs (checked 2026-10-22), Android 14 and earlier only re-check on install or update; Android 15 and later can take up to seven days. During testing, adb shell pm verify-app-links --re-verify <package> checks again immediately.
Can one bad domain break all my App Links?
On Android 11 and earlier, yes: if any autoVerify host fails, none of the app's links are verified. On Android 12 and later, each host is verified separately.
Checked 2026-10-22 against Android Developers "Verify App Links" and "Troubleshoot App Links". Commands and states may change in future Android releases.