Tutorial
How to Fix Android App Links and Deep Linking in TWAs on Android 12+
October 22, 2026 · 7 min read
Deep linking is essential for bringing users back into your application from external sources such as email campaigns, social media, and third-party links. However, starting with Android 12, Google radically changed how deep links are handled. If your application does not pass strict security checks, Android completely ignores your app and opens all domain links in the default web browser instead.
For developers publishing a Progressive Web App (PWA) to the Google Play Store using a Trusted Web Activity (TWA), this means clicking a link to your web app on a platform like Slack or Twitter might result in a standard browser launch instead of opening inside your installed TWA. This guide walks you through configuring, registering, and debugging Android App Links to ensure seamless app routing on modern Android devices.
The Core Problem: Why Android 12 Changed Deep Linking
Historically, Android used a concept called Deep Links based on standard intent filters. When a user clicked a web link (e.g., https://yourdomain.com/dashboard), the Android operating system displayed a system prompt—often called the disambiguation dialog—asking the user if they wanted to open the link in Chrome or your installed application. The user had to select a default handler manually.
To prevent malicious apps from hijacking URLs of trusted domains (like banking or social platforms), Android 12 introduced a strict verification model called Android App Links. Under this model, clicking a web link will only open the app directly if the app developer has explicitly verified ownership of the domain. If verification fails, Android 12+ silently falls back to opening the link in the web browser, without showing the user any choice. For a TWA to capture these intents, it must explicitly pass this strict OS-level verification.
Step 1: Configuring the Android Manifest for App Links
The first step in setting up App Links is defining an intent-filter inside your application’s AndroidManifest.xml. This filter tells the Android system that your app is capable of handling web links from your specific domain, and that it wants to automatically verify this association.
To enable auto-verification, you must include the android:autoVerify="true" attribute in your intent-filter. This attribute signals to the Android OS that it must attempt to verify your domain immediately upon app installation.
The following XML structure shows how the intent-filter must be defined inside the activity node of your TWA wrapper:
<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="http" />
<data android:scheme="https" />
<data android:host="yourdomain.com" />
</intent-filter>
If your web application uses multiple subdomains (such as app.yourdomain.com or dashboard.yourdomain.com), you must include a separate data node for each host. If even a single domain specified inside the autoVerify filter fails validation, the entire verification process fails, and all links will default back to the browser.
Step 2: Hosting the Digital Asset Links File
Once Android reads the intent-filter during installation, it attempts to fetch a JSON file from your server to confirm you own the domain. This file must be served over HTTPS at exactly this path:
https://yourdomain.com/.well-known/assetlinks.json
This configuration file must return a content-type of application/json, return an HTTP 200 OK status, and be served without redirects. The payload links your web domain to your Android app's package name and SHA-256 certificate fingerprint.
The following example represents a valid assetlinks.json payload configured for both TWA execution (hiding the browser URL bar) and Android App Link routing:
[
{
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.use_as_origin"
],
"target": {
"namespace": "android_app",
"package_name": "com.yourdomain.twa",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:EE:FF:11:22:33:44:55:66:77:88:99:00:AA:BB:CC:DD:EE:FF:11:22:33:44:55:66:77:88:99:00"
]
}
}
]
Note the use of target relation types. The handle_all_urls parameter instructs Android 12+ that this application is authorized to handle incoming deep links, while use_as_origin is required by Chrome to run your TWA in full-screen mode without displaying the browser navigation bar.
Step 3: Managing Play App Signing SHA-256 Fingerprints
The most common reason developers fail App Link verification on Android 12+ is using the wrong SHA-256 fingerprint in production. When you build and test your TWA locally, your app is signed with a local debug keystore. The SHA-256 fingerprint of your debug keystore must be in your assetlinks.json for local deep link testing to work.
However, once you upload your Android App Bundle (AAB) to the Google Play Store, Google Play App Signing strips your upload signature and signs your APK with a secure, production-level key managed on Google's servers.
You must grab the production SHA-256 fingerprint directly from your Google Play Console and append it to your assetlinks.json file. Failing to do this means deep links will work during local emulator testing but fail completely for real users downloading your app from the Play Store.
| Testing Stage | Key Source | Where to Find SHA-256 Fingerprint |
|---|---|---|
| Local Testing | Debug Keystore | Run keytool -list -v -keystore ~/.android/debug.keystore |
| Play Store Distribution | Google Play Signing Key | Google Play Console > Setup > App Signing |
Step 4: Testing and Debugging Verification Status
Because Android 12 executes App Link verification silently in the background during installation, failures can be hard to spot. If your link routing is failing, you can use the Android Debug Bridge (ADB) via terminal commands to force verification and inspect the exact registration status of your package.
To check the current domain verification status of your application, connect your test device via USB and run the following command:
adb shell pm get-app-links com.yourdomain.twa
This will output the status of your configured domains. A successful setup will show your domain followed by "verified". If the output shows "legacy", "ask", or "undefined", your verification failed.
To force the Android OS to run the verification process immediately without reinstalling the app, execute the following command:
adb shell pm verify-app-links --user 0 --verify-force com.yourdomain.twa
If the verification output still returns an error, verify that your server is not blocking requests to the .well-known folder using rate-limiting services, cloud-native firewalls, or user-agent verification scripts that might prevent the Android verification manager from reading the assetlinks.json file.
Ready to ship your Android app?
Paste your PWA URL, get a signed APK and a Google Play ready AAB in minutes.
Build my app