Android App Links
Intent filters, assetlinks.json, and verified links - the Android cookbook for opening https:// URLs directly in your Expo SDK 57 app without the "Open with" disambiguation sheet.
Search across all documentation pages
Intent filters, assetlinks.json, and verified links - the Android cookbook for opening https:// URLs directly in your Expo SDK 57 app without the "Open with" disambiguation sheet.
Quick-reference recipe card - copy-paste ready.
// app.config.ts
export default {
expo: {
android: {
package: "com.example.shopapp",
intentFilters: [
{
action: "VIEW",
autoVerify: true,
data: [
{
scheme: "https",
host: "shop.example.com",
pathPrefix: "/orders",
},
],
category: ["BROWSABLE", "DEFAULT"],
},
],
},
},
};// https://shop.example.com/.well-known/assetlinks.json
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.shopapp",
"sha256_cert_fingerprints": [
"14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:10:D4:4A:8F:D8:00:6F:8F:95:34:E7:6B:58"
]
}
}
]When to reach for this:
assetlinks.json beside it.https://shop.example.com/... paths.Full verification setup for https://shop.example.com/orders/*.
Step 1 - Intent filters in app.config.ts
// app.config.ts
import type { ExpoConfig } from "expo/config";
const config: ExpoConfig = {
name: "ShopApp",
slug: "shop-app",
scheme: "shopapp",
android: {
package: "com.example.shopapp",
intentFilters: [
{
action: "VIEW",
autoVerify: true,
data: [
{
scheme: "https",
host: "shop.example.com",
pathPrefix: "/orders",
},
{
scheme: "https",
host: "shop.example.com",
pathPrefix: "/product",
},
],
category: ["BROWSABLE", "DEFAULT"],
},
],
},
ios: {
bundleIdentifier: "com.example.shopapp",
associatedDomains: ["applinks:shop.example.com"],
},
};
export default config;Step 2 - Host assetlinks.json
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.shopapp",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
]
}
}
]Serve at: https://shop.example.com/.well-known/assetlinks.json
Step 3 - Obtain SHA-256 fingerprint
# Play Console → App integrity → App signing key certificate → SHA-256
# Local debug keystore (development builds only):
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass androidStep 4 - Build and test
npx expo prebuild --platform android
npx expo run:android
adb shell am start -a android.intent.action.VIEW -d "https://shop.example.com/orders/42" com.example.shopappStep 5 - Check verification status
adb shell pm get-app-links com.example.shopappLook for shop.example.com: verified - none or legacy_failure means fix hosting or fingerprint.
What this demonstrates:
autoVerify: true triggers install-time domain verification.pathPrefix scopes which URLs the app claims.assetlinks.json for each host in intent filters with autoVerify.shopapp://) bypass verification - still useful for dev and OAuth.| Field | Purpose |
|---|---|
action: "VIEW" | Standard open-URL intent |
category: ["BROWSABLE", "DEFAULT"] | Required for link handling |
autoVerify: true | Enable Digital Asset Links |
data.scheme | https for App Links |
data.host | Domain without path |
data.pathPrefix | URL path prefix match |
data.pathPattern | Regex path (escape carefully) |
| Status | Meaning | Action |
|---|---|---|
verified | Success | Ship |
none | No attempt / missing filter | Check manifest |
legacy_failure | Fingerprint or JSON mismatch | Fix assetlinks.json |
no_response | Server unreachable | Fix CDN / TLS |
# Re-run verification after fixing assetlinks.json (Android 12+)
adb shell pm verify-app-links --re-verify com.example.shopappassetlinks.json break verification - serve 200 on exact URL.application/json.android:launchMode on main activity affects back-stack - singleTask is common for deep-link apps.autoVerify: true - filter works but shows chooser. Fix: set autoVerify and reinstall app.pathPrefix too broad - / claims entire site including blog. Fix: narrow to /orders, /product.app.config.ts but ran old APK. Fix: npx expo prebuild --clean then rebuild.shopapp:// only - App Links are HTTPS-only. Fix: test https:// URLs with adb intent command.| Alternative | Use When | Don't Use When |
|---|---|---|
| Custom scheme intent filter | OAuth, quick internal tests | Public marketing HTTPS links |
expo-linking scheme only | Prototype before CDN setup | Production Android campaigns |
| Branch / Firebase Dynamic Links | Deferred attribution | You control the domain and want zero SDK |
| User-trusted chooser (no autoVerify) | Competing apps share domain | You want one-tap open |
target objects with different package_name values (e.g. .dev suffix).pathPrefix: "/orders" matches /orders, /orders/42, /orders/42/items.pathPattern uses regex - powerful but easy to mis-escape; prefer prefix when possible.pm get-app-links.data entries.pathPrefix.https - http will not auto-verify. Use HTTPS everywhere.pm verify-app-links --re-verify after fixing JSON - no hour-long Apple-style cache, but CDN TTL applies.assetlinks.json and apple-app-site-association on the same domain - see iOS Universal Links.Stack versions: This page was written for React 19.2.3, React Native 0.86.0, and Expo SDK 57 (
expo~57.0.4).
Reviewed by Chris St. John·Last updated Jul 16, 2026