Android App Links Tutorial: Set Up and Test Deep Links
Learn how to configure Android App Links with manifest intent filters, a Digital Asset Links file, signing-certificate fingerprints, Kotlin URL handling, and ADB verification. Troubleshoot common failures before releasing your app.
On this page
A product link shared in WhatsApp should open the relevant screen in your Android app, not send the user to a browser and make them search for the same product again. Android App Links can make that handoff work automatically, but adding a URL pattern to your app is only half the job. This tutorial walks through the complete setup, including website verification, signing certificates, incoming URL handling, and testing the finished implementation.
Understand what Android App Links verify before you start
Android App Links are verified web links that connect a website to an Android application. They use HTTP or HTTPS addresses, allowing a link to represent the same content on a website and inside an app. For example, a shopping app might use a product address ending in /products/42 to open the corresponding product screen when the app is installed. Without the app, the same address can still display the product on the website.
The verification process is what separates App Links from ordinary deep links. A deep link is a URL that opens a particular location inside an app, while a verified App Link additionally establishes that the website authorizes the application to handle its links. Android checks a file published by the website and compares its signing-certificate fingerprint with the installed application. This reduces the risk of an unrelated application claiming to handle links belonging to your domain.
You need an Android application with a configured application ID, a website you control, and access to the application's signing information. Android App Links are supported on Android 6.0 and later when Google services are available; some testing and dynamic-link features have additional platform requirements. You can use Android Studio for the application configuration and a browser or command-line tool to inspect the website's verification file.
Step 1: Choose the URLs your app should handle
Start by deciding which website addresses should open the application. Suppose you are developing a store app and want product pages to open inside the app. A useful URL structure might include https://shop.example.com/products/42 and https://shop.example.com/products/85. Both addresses share the same domain and path structure, so one suitable intent filter can match them.
An intent filter is a declaration in the Android manifest that tells the operating system which incoming actions and URLs an activity can handle. An activity is an application component that displays a screen or manages a user interaction. Keeping the URL structure consistent makes it easier to route incoming links to the correct screen without creating a separate filter for every product.
Before continuing, identify the exact hostname your application will use. The root domain and its subdomains are separate hosts for verification purposes. If your application needs to handle both example.com and www.example.com, plan to publish and verify the website association for each host rather than assuming that verifying one automatically covers the other.
Step 2: Add an App Links intent filter to AndroidManifest.xml
Open your project's AndroidManifest.xml file and locate the activity responsible for receiving incoming links. Add an intent filter with the view action, the default and browsable categories, the supported web schemes, and your domain. The android:autoVerify="true" attribute asks Android to verify the website association rather than treating the declaration as an ordinary unverified deep link.
Replace the example hostname with your actual domain and make sure the activity name matches your project. The example accepts matching HTTP and HTTPS product paths, including individual product pages. The HTTP declaration allows the app to recognize HTTP links, but production websites should use HTTPS and redirect visitors securely to it.
Be careful when adding multiple elements to one filter. Android combines their attributes when determining the URLs that match, which can create combinations you did not intend. If different groups of URLs require different hosts, schemes, or paths, separate intent filters are often easier to reason about and test.
Step 3: Get the SHA-256 fingerprint for your application
Your website must identify the application it trusts, including the cryptographic fingerprint of the certificate used to sign it. SHA-256 is a cryptographic hash algorithm that produces a fingerprint for the signing certificate. Android uses that fingerprint to check whether the installed app matches the application named in the website association file.
If you already distribute the application through Google Play, open Play Console and find the app-signing information in the app's release or setup area. Copy the SHA-256 certificate fingerprint associated with the app-signing key. Google Play App Signing can use a different certificate from the upload key on your development computer, so copying the upload certificate without checking the actual signing configuration can cause verification to fail.
For a local build signed with a keystore you control, you can inspect its certificate using the Java Development Kit's keytool utility. Run the following command in a terminal, replacing the example filename with your keystore file:
keytool -list -v -keystore release-key.jks
Enter the keystore password when prompted, then locate the SHA-256 fingerprint in the output. Keep the fingerprint associated with the certificate that actually signs the build you intend to test. Debug builds, locally signed release builds, and Google Play-distributed builds may have different fingerprints, so you may need separate entries for the certificates you legitimately use.
Step 4: Publish the website association file
The website needs to publish a Digital Asset Links file, named assetlinks.json, at the fixed location /.well-known/assetlinks.json. This file contains a JSON array describing which application is authorized to handle the website's links. Android retrieves it during verification and checks the application ID and certificate fingerprint against the installed app.
Create the file with the following structure, replacing the sample application ID and fingerprint with your own verified values:
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "com.example.shop",
"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"
]
}
}
]
The package name must match your application's actual application ID, not merely a display name shown to users. The fingerprint above is a placeholder and will not verify a real application. Use the complete fingerprint copied from the correct signing certificate, preserving its colon-separated hexadecimal format.
Upload the file to your website so that the required path returns the JSON document directly. It must be publicly accessible over HTTPS, and the server should return a successful response without an authentication page, an HTML error document, or a redirect to a different hostname. If you use multiple verified hosts, each host needs its own correctly configured association file.
Step 5: Read the incoming link and open the correct screen
Once the manifest and website association are configured, your application must still interpret the incoming URL. Android delivers the link through an intent, which is a message describing an action the application should perform. Your activity can retrieve the URL from that intent and use its path to decide which screen to display.
For example, a link ending in /products/42 should open product 42 rather than simply launching the application's home screen. A basic Kotlin implementation can inspect the URI in the activity that receives the link:
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIncomingLink(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleIncomingLink(intent)
}
private fun handleIncomingLink(intent: Intent?) {
if (intent?.action!= Intent.ACTION_VIEW) {
return
}
val uri: Uri = intent.data?: return
if (uri.scheme!in setOf("http", "https")) {
return
}
if (uri.host!= "shop.example.com") {
return
}
val segments = uri.pathSegments
if (
segments.size == 2 &&
segments[0] == "products"
) {
val productId = segments[1]
if (productId.matches(Regex("[A-Za-z0-9_-]+"))) {
openProductScreen(productId)
}
}
}
private fun openProductScreen(productId: String) {
// Replace with your navigation implementation.
Toast.makeText(
this,
"Open product: $productId",
Toast.LENGTH_SHORT
).show()
}
}
This example demonstrates URL parsing and validation, not a complete shopping application. Replace openProductScreen() with your app's navigation logic and load the requested product from your own data source. The handler checks the scheme, hostname, expected path structure, and product identifier before routing, rather than trusting every value received from an external intent.
If your activity uses a launch mode that reuses an existing instance, Android may deliver a subsequent link through onNewIntent() instead of creating a new activity. Handling both entry points prevents a second product link from being ignored while the app is already open. Applications using Jetpack Navigation or another navigation framework should connect the parsed URL to that framework's routing mechanism.
Step 6: Verify the association on a real Android device
Install a build signed with a certificate represented in your website's association file. On Android 12 and later, you can manually request link verification using Android Debug Bridge (ADB), a command-line tool for communicating with a connected Android device. Enable USB debugging, connect the device, and confirm that ADB can see it before running the following commands.
adb devices
adb shell pm verify-app-links --re-verify com.example.shop
adb shell pm get-app-links com.example.shop
Replace com.example.shop with your real application ID. The first command lists connected devices, the second requests fresh verification, and the third displays the operating system's App Links state for the package. Verification may take time, so inspect the result after the request has completed rather than assuming that the command immediately makes every domain verified.
Next, test a specific product address by asking Android to open it:
adb shell am start -a android.intent.action.VIEW -d "https://shop.example.com/products/42"
With the correct application installed and its domain verified, Android should route the matching address to the app. Confirm that the expected product screen appears, that an unknown product identifier is handled safely, and that links outside the declared path do not accidentally open the product screen. Also test the same address without the app installed to make sure the website still provides a usable fallback.
For devices running Android 17, the debug-link option can help inspect which candidate applications and matching rules are involved in resolving a URL. Use platform-specific diagnostic options when ordinary verification output does not explain why a link is being routed incorrectly.
Step 7: Fix the failures that most often break App Links
App Links can appear correctly configured and still open in a browser if one part of the association is wrong. The manifest, public website file, and signing certificate must agree. Troubleshooting is much faster when you check those three components separately instead of repeatedly changing the activity code.
| Symptom | What to check |
|---|---|
| The browser opens instead of the app | Check the verification state, manifest host, autoVerify attribute, and website association file. |
| The association file cannot be retrieved | Confirm the exact file path, HTTPS access, HTTP response, and server redirects. |
| Verification fails despite valid JSON | Compare the package name and SHA-256 fingerprint with the installed build's actual signing information. |
| One domain works but another does not | Verify that each declared hostname publishes its own correct association file. |
| The app opens but shows the wrong screen | Inspect the incoming URI, path parsing, navigation state, and activity lifecycle handling. |
| Only some links open the app | Check the path patterns in the manifest and any applicable dynamic rules. |
One subtle issue is the difference between the certificate used to upload an application and the certificate Google Play uses to sign distributed builds. If local testing succeeds but an installed Play version fails, compare the fingerprint against the Play app-signing certificate rather than assuming both builds use the same key.
Another issue is overly restrictive path matching. Android 15 and later support Dynamic App Links, which let developers refine link-handling rules through the website's Digital Asset Links configuration. These rules can be useful for adding campaign or content-specific routing without releasing a new app version, but they cannot expand the URL scope beyond the applicable manifest declarations. Keep the manifest broad enough for the routes you may need, then apply server-side restrictions deliberately.
What to do before releasing the app
Before shipping, test the links with a debug build and the actual release-signing configuration, including the certificate used for Google Play distribution. Verify every hostname, exercise valid and invalid paths, and confirm that links still work when the app is already running. Finally, test the website fallback on a device without the application installed.
Once the association is verified, App Links can make links from messages, search results, emails, and other applications feel like a direct continuation of your product. The next practical step is to add a small set of real URLs to your application's test plan and verify their destination on each supported Android version before expanding the routing rules.
Share this post
Written by


