Why your links open in the browserYou’ve configured Android App Links, but instead of a seamless transition into your app, the system ignores it. Users click a link, and the mobile browser opens—exactly what you wanted to avoid. If you check Logcat, you'll likely see a specific error: Intent filter verification failed for domain: example.com.
Android 12 changed the rules. Previously, a failed verification meant the user saw a selection dialog. Now, if verification fails, the system defaults to the browser every single time. The verification process is a strict handshake where Android fetches a file from your server to prove you own the domain.
Common causes for verification failureThe Android System Intent Filter Verification Service is sensitive. The handshake fails if any of these conditions aren't met:
- No HTTPS: Your
assetlinks.jsonfile must be reachable via a secure connection.- Invalid Status Codes: The server must return a200 OK. Redirects (301 or 302) are treated as failures.- Wrong MIME Type: TheContent-Typeheader must beapplication/json.- Fingerprint Mismatch: The SHA-256 fingerprint in your JSON doesn't match the key used to sign the APK.- Subdomain Issues:example.comandwww.example.comare treated as different domains and both need verification.## Quick Fix: Manual Verification via ADBDon't wait for the system to retry. You can check the current status and force a re-verification using the Android Debug Bridge (ADB) to see exactly what the OS thinks. Check your domain status:
adb shell pm get-app-links com.your.package.name
If the output shows legacy_failure, undefined, or ask, the verification failed. To force the system to attempt the handshake again on Android 12+ devices, run:
adb shell pm verify-app-links --re-verify com.your.package.name
Permanent Fix Steps### 1. Audit the AndroidManifest.xmlVerify that your intent filter includes android:autoVerify="true". This attribute is the trigger that tells Android to go look for your verification file. Without it, the system won't even attempt to fetch your JSON.
<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="example.com" />
</intent-filter>
2. Validate the assetlinks.json FileYour assetlinks.json must live at https://yourdomain.com/.well-known/assetlinks.json. A common trap is using the wrong SHA-256 fingerprint. If you use Google Play App Signing, the fingerprint for your local debug build is different from the production build managed by Google.
Extract your local SHA-256 fingerprint using keytool:
keytool -list -v -keystore my-release-key.keystore
Your file should look like this (ensure there are no trailing commas):
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.your.package.name",
"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"
]
}
}
]
3. Server-Side RequirementsCheck your server configuration. Many static file hosts like S3 or GitHub Pages default to text/plain for files without extensions. You must explicitly set the Content-Type to application/json. Also, ensure your robots.txt isn't accidentally blocking the /.well-known/ path from crawlers.
How to confirm it's finally fixedAfter deploying changes and re-installing the app, run this command to see the final state:
adb shell dumpsys package domain-preferred-apps
Look for your package name. You want to see status: always. This means the system successfully verified the domain and your app is now the default handler.
For an external check, use the Google Digital Asset Links API:
https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://example.com&relation=delegate_permission/common.handle_all_urls
If the API returns your package name correctly but the app still fails, double-check that your AndroidManifest.xml isn't missing a secondary domain or subdomain used in your links.

