Appy
← Back to Blog
Troubleshooting

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.

August 14, 2026•10 min read

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

adb · Android 16
$ adb shell pm get-app-links com.example.app
com.example.app:
Domain verification state:
example.com: verified
promo.example.com: none
Opens the appOpens the browser
The output nobody reads until something breaks: example.com passed verification at install time, promo.example.com never did. Each verdict was decided per device, silently.

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.

App installed or updated

Android reads every domain declared with autoVerify

Fetches assetlinks.json for each domain

/.well-known/assetlinks.json

  1. 01

    Direct 200 over HTTPS

    HTTP 200

    Fails on a 301 or 302 redirect, a 404, an auth wall or bot check

  2. 02

    Served as JSON

    content-type: application/json

    Fails on text/html or text/plain, even with a valid body

  3. 03

    Package name listed

    com.example.app

    Fails on a flavor or package missing from the array

  4. 04

    Fingerprint matches the installed app

    sha256_cert_fingerprints

    Fails on only the upload key, not the Play signing key

verified: the link opens the app

Stored per domain, on this device

none: the link opens the browser

Silently, with no crash and nothing in your dashboards

The verdict is cached. A fixed file changes nothing on phones that already failed until verification runs again, so force a re-verify.

What Android checks at install time for each autoVerify domain. One failed check is enough to send that domain to the browser.

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.

01

Read the verification state

adb shell pm get-app-links com.example.app

This 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.

02

Fetch assetlinks.json the way the verifier does

curl -sI https://example.com/.well-known/assetlinks.json

You 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.

03

Compare the fingerprint against the Play signing key

Play Console → App integrity → App signing key certificate

Open 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.

04

Force a re-verification

adb shell pm verify-app-links --re-verify com.example.app

After 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.

05

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.

Sideloaded build

Signed with your upload key

Upload key

assetlinks.json

Fingerprint listed in the file

Upload key

Match: verified

Installed from Google Play

Signed with Google’s app signing key

Play signing key

assetlinks.json

Fingerprint listed in the file

Upload key

No match: none

Play signing keyUpload key

Fix: add 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.

Why it works on your phone and fails for users: the file carries the upload key fingerprint, while every Play Store install is signed with Google’s key.
Cause

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.

Android 15

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.

Android 16

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 your website 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.

Someone taps your link

appy.to/promo

On the server

The redirect reads the device

Android, iOS and desktop go to different destinations, on every plan

iOS and desktop: their own destinations

On the phone

Android lands on your https domain

The OS now sees your domain

On the phone

Android applies its verification state

verified: appnone: browser

While you repair assetlinks.json

AndroidPlay Store pageYour website

Point Android traffic at the Play Store page or your website, then flip it back. Printed QR codes stay valid.

A smart link chooses where each device goes before the OS gets involved. It cannot bypass verification: on your domain, verified or none still decides app or browser.

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

Comparison
Oct 1, 2026
12 min read

Best Deep Linking Tools in 2026: An Honest Comparison

Branch, AppsFlyer OneLink, Adjust, Airbridge, Kochava, Singular, Bitly, Dub, onelink.to and Appy, checked against their own pricing pages and docs: deep links, deferred deep linking, attribution, QR codes, AI assistants, price and setup.

deep linking
deep linking tools
branch alternative
firebase dynamic links
Read article
Comparison
Sep 24, 2026
6 min read

Branch.io Alternative: No Card, No Overage Bills, No Expiring Links

Branch dropped its free plan. Today you hand over a card just to try it, land on $39 a month with overages that have no cap, and pay $199 a month for a custom domain. Links nobody clicks for 380 days expire. The full picture, and what small teams use instead.

branch alternative
branch.io pricing
deep linking
link expiration
Read article
Comparison
Sep 23, 2026
7 min read

Airbridge Pricing Changed in 2026: The Free Plans Became a 30-Day Trial

Airbridge used to advertise a free Core allowance and a free DeepLink plan. The pricing page now shows a 30-day trial followed by $40+ a month, while the older blog posts still say free. The timeline, and what to check if you signed up on the old terms.

airbridge alternative
airbridge pricing
deep linking
pricing
Read article

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