Android App Links Not Verified: A Five-Minute Diagnosis with adb
Since Android 12, an App Link that fails domain verification opens in the browser instead of your app — silently, and not on every device. Here is the adb checklist that finds the cause fast, including the Play signing key mismatch behind most of these incidents.
The app is installed. The link opens Chrome anyway.
It usually surfaces as a support ticket, not an error. Someone taps a link to your domain, your app sits right there on their phone, and Chrome opens instead. Since Android 12, per Android documentation, an https link only opens your app if the system verified your domain at install time — and when that verification fails, it fails silently. No crash, no toast, nothing in your dashboards.
Two properties make this painful to debug. Verification is per-domain, so example.com can be verified while promo.example.com quietly is not. And it is per-device: the same build can pass on a Pixel and fail on a Samsung phone, a combination reported repeatedly in Samsung developer forum threads. If you are reading this mid-incident, jump to the diagnosis below — the background will still be here afterwards.
Two domains, two verdicts
What actually happens at install time
When your app is installed or updated, Android reads every domain declared with autoVerify and fetches https://yourdomain/.well-known/assetlinks.json for each one. Per Android documentation, the file must come back as a direct 200 over HTTPS with content type application/json — the verifier does not follow redirects. The result is cached per domain, which is why one subdomain can be verified while its sibling is not.
Inside the file, sha256_cert_fingerprints must match the certificate that signed the APK on the device. Here is the number one gotcha: with Play App Signing, that certificate is Google’s app signing key — not your upload key. The fingerprint from your local keystore verifies your sideloaded builds perfectly, and fails every install that came from the Play Store. Half of the “works on my device” reports trace back to exactly this.
One more property worth knowing before you start: the verdict is cached. Fixing the JSON on your server changes nothing on phones that already failed until verification runs again — which, fortunately, you can force.
The five-minute diagnosis
Plug in any Android 12+ device with the app installed and run these in order. Most incidents are solved by step three.
Read the verification state
adb shell pm get-app-links com.example.appThis prints every domain your app declares along with its state. verified means the handshake passed; none means the verifier never approved the domain — that is the one sending users to Chrome. On devices with multiple users, check the per-user section at the bottom of the output too.
Fetch assetlinks.json the way the verifier does
curl -sI https://example.com/.well-known/assetlinks.jsonYou want a direct 200. Any 301 or 302 fails verification, because per Android documentation the verifier does not follow redirects. Confirm the content-type header says application/json, then fetch the body and read the package name and fingerprints with your own eyes. Bot protection or an auth wall in front of /.well-known/ also counts as a failure.
Compare the fingerprint against the Play signing key
Play Console → App integrity → App signing key certificateOpen that Play Console page and put the SHA-256 shown there next to your JSON. They must match byte for byte. If your file carries the upload key fingerprint instead, you have found the bug — add the Play signing key fingerprint, and keep both if you also distribute builds outside the Play Store.
Force a re-verification
adb shell pm verify-app-links --re-verify com.example.appAfter fixing the server side, tell the device to try again. The verifier runs asynchronously, so give it a few seconds, then repeat step one and watch for none to flip to verified. On some Samsung devices the state refuses to move until after a reboot — a pattern reported on Samsung developer forums.
Fire the intent like a real tap
adb shell am start -a android.intent.action.VIEW -d "https://example.com/promo"This is the end-to-end test. On a verified domain the app opens directly, no chooser. If the browser or a disambiguation sheet appears, the state has not flipped yet — re-check step one before assuming your fix failed.
If you would rather not eyeball JSON during an incident, our link validator tool fetches your assetlinks.json and checks the status code, content type, and fingerprint format in one pass.
The usual suspects
Five causes cover nearly every report we have seen. Cause on the left, fix on the right.
The JSON carries the upload key fingerprint, not the Play signing key
Copy the SHA-256 from Play Console → App integrity → App signing key certificate. Keep both fingerprints if you also ship builds signed with the upload key.
assetlinks.json answers with a redirect or a 404
Serve the file directly at /.well-known/assetlinks.json on every declared host. To the verifier, www and the bare domain are two different domains.
Wrong content type, such as text/html or text/plain
Configure the server or CDN to send application/json for this path. A perfectly valid JSON body with the wrong header still fails.
Multiple flavors or package names, one missing from the file
The file is an array: one statement per package name, each with its own fingerprints. A missing flavor fails only that flavor, which looks maddeningly random in QA.
A Samsung device stays on none after the JSON was fixed
Delayed verification on some Samsung models is a recurring theme on Samsung developer forums. Force a re-verify, then reboot the device before concluding anything else.
What Android 15 and 16 changed
Two recent releases moved the goalposts, both in the same direction: verified https App Links are the supported path, and everything else keeps getting narrower.
Added Dynamic App Links, per the platform release notes: domain associations can be updated without shipping a new APK, which shortens the loop between fixing your JSON and devices picking the fix up.
Tightened how custom URI schemes are verified and surfaced to users, per the platform release notes. If parts of your flow still rely on myapp:// schemes, treat them as legacy and move those entry points to verified https links.
Where a smart link honestly fits
A smart link routes on the server, before any of this machinery runs: when someone opens an Appy link, the redirect reads the device and sends Android, iOS, and desktop visitors to different destinations. That routing works on every plan and does not depend on on-device verification, because it happens before the OS ever sees your domain.
Be clear about what it does not do: a smart link cannot bypass App Links verification. The redirect ends on your https domain, and the same verified-or-none state decides whether the app or the browser opens. What it gives you mid-incident is a controllable front door — point Android traffic at the Play Store page or a web fallback while you repair assetlinks.json, then flip the destination back without touching anything already printed, since dynamic QR codes stay editable after printing. The analytics show how much Android traffic hit the broken path in the meantime.
Fix verification either way. Deep link destinations on Pro, and deferred deep linking on Enterprise for the install-then-open journey, are worth having — but they sit on top of a working assetlinks.json, not instead of one.
Frequently asked questions
Why does the same link work on one device and not another?
Verification runs on each device at install time, so every phone carries its own cached verdict. A network hiccup during install, an OEM verifier behaving differently — Samsung being the most-reported case on Samsung developer forums — or an install that predates your JSON fix all produce different states for the same build.
Do I need to ship an app update to fix it?
Usually no. If the manifest already declares the domain with autoVerify, the failure lives in the JSON file or the fingerprint, both server-side. Fix the file, force a re-verify, and the installed build starts opening links. An update is only needed when the domain was never declared in the manifest at all.
Does a smart link bypass App Links verification?
No, and be wary of anything claiming otherwise. The redirect chooses the destination server-side, but once the visitor lands on your https domain, the operating system applies the same verification state as always. A smart link changes what you can do while verification is broken — route to the store or the web — not whether it is broken.
How long until verification retries on its own?
Per Android documentation the verifier retries failed domains and re-runs when the app updates, but the schedule is not guaranteed and OEMs differ. In practice that means hours to days. Forcing a re-verify over adb, or reinstalling the app, is faster than waiting for the system to come back around.
Continue exploring
AppsFlyer’s Free Plan Just Shrank: What Moved to Paid, and What Your Options Are
As of August 13, 2026, deferred deep linking, branded domains, Smart Banners, bulk links, and API access sit outside AppsFlyer's free Zero plan. What changed, what it costs to replace, and a migration path that takes an afternoon.
Parameter Forwarding for Deep Links, Universal Links, App Stores, and Web
Learn how to preserve campaign and context parameters across app opens, app-store redirects, Universal Links, and web fallbacks without overwriting destination values.
Deferred Deep Linking: How It Works and When to Use It
Understand how deferred deep linking carries the original link intent across install so new users land on the right in-app screen, not a generic home tab.
Looking for something else? Browse all topics on the blog.
Give Android traffic somewhere to land
Create a smart link that detects the device server-side and routes Android visitors to the app, the store, or the web — and change the destination later without reprinting a single QR code.
Create a free smart link