Improving your deep links with Dynamic App Links
Use Android Dynamic App Links to update path, query-parameter, and exclusion rules from the server without shipping a new app version.
Users expect to tap a link and land straight in the app, not go to the browser. With the arrival of Android 15 (API level 35), Android’s App Links system gained a powerful upgrade: Dynamic App Links. You get granular link routing, exclusions, query-parameter rules, and server-side updates without shipping a new app version.
What’s changed
Previously, you would declare deep-linking rules in your app’s AndroidManifest.xml and publish a static assetlinks.json that just verified your app-to-domain relationship. With Dynamic App Links you can:
- Publish path, fragment, and query-parameter matchers in
assetlinks.json. - Specify exclusions so particular URLs will not open your app, which is useful for legacy content or web-first flows.
- Change link-routing logic on the server without pushing a new APK. Devices running Android 15 with Google services will refresh your JSON file periodically and merge dynamic rules with the manifest.
How it works in practice
- In your Android app’s manifest, declare a broad intent filter with
android:autoVerify="true"for your domain.
<activity android:name=".MyDeepLinkActivity" android:exported="true"> <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" android:host="example.com" android:pathPrefix="/" /> </intent-filter></activity>This sets the broad hostname and scheme scope.
- On your website, host
https://example.com/.well-known/assetlinks.jsoncontaining your app association and the optionaldynamic_app_link_components. For example:
[ { "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.example.app", "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" ] }, "relation_extensions": { "delegate_permission/common.handle_all_urls": { "dynamic_app_link_components": [ { "/": "/products/*" }, { "/": "/shoes", "?": { "in_app": "true" } }, { "/": "*", "exclude": true } ] } } }]In this setup:
- URLs under
/products/*open your app. - The specific path
/shoes?in_app=trueopens your app only when that query parameter is present. - Everything else (
"/": "*") is excluded.
- When a user taps a matching link and your app is installed, the system checks your rules, verifies your app-to-domain association, and then routes into the app, assuming Android 15 or later and Google services are present. On older devices it falls back to your static manifest rules.
Why this matters
- Campaign flexibility: Launch a seasonal promotion (
/promo/summer-sale) and later remove the rule without republishing your app. - Partner and vanity URLs: Add or remove partner links dynamically (
/partner/influencer-name). - A/B testing: Enable only a subset of users via query-parameter gating (
?in_app=true). - Safety and routing control: Exclude unsupported content from launching your app inadvertently.
Best practices for Android engineers
- For the intent filter in the manifest, choose a broad scope (scheme and host), but avoid overly specific paths there. Let the server rules refine it.
- Ensure your
assetlinks.jsonis served at/.well-known/assetlinks.jsonover HTTPS, with no redirects, and withContent-Type: application/json. - Rule order matters: Android evaluates the dynamic rules in declared order and stops at the first match, including exclusions.
- Test on actual Android 15 devices, or an emulator with Google services, to ensure the dynamic rules are applied. On older devices you will still use your manifest rules.
- Whenever you remove or change rules, expect a propagation delay while devices poll for updates.
- Treat changes to
assetlinks.jsonlike feature releases. A syntax error can deactivate all of your dynamic rules and fall back to the manifest only.
Read more in the Android Dynamic App Links documentation.