The Modern Standard for Secure, Reliable Deep Links
In the early days of mobile, deep linking relied on custom URI schemes (e.g., `yourapp://path`). This method was flawed: it provided no easy way to fall back to a website if the app wasn't installed, and it was insecure, allowing any app to claim any URI scheme.
To solve this, Apple and Google introduced secure, web-based deep linking standards: Universal Links for iOS and App Links for Android. Both technologies use standard `https` URLs and a cryptographic verification process to create a secure association between a website domain and a mobile app. This ensures that only the legitimate owner of a domain can direct links from that domain into their app.
This guide will walk you through the technical implementation of both systems, highlighting the precise steps and common errors that teams encounter.
How Universal Links Work (iOS)
Universal Links create a secure bridge between your domain and your iOS app. The entire system is built on a foundation of trust, verified by a special file you host on your web server.
Here's the flow:
- Your app declares in its project settings which domains it is associated with (e.g., `applinks:www.example.com`).
- When a user installs or updates your app, iOS automatically attempts to fetch a file from a well-known location on that domain: `https://www.example.com/.well-known/apple-app-site-association`.
- This file, commonly called the AASA file, is a JSON that contains a list of app identifiers and the URL paths they are allowed to handle.
- If iOS successfully fetches a valid AASA file that includes your app's identifier, it creates the association.
- From then on, when a user taps a link to an approved path on `www.example.com` (e.g., in an email or text message), iOS opens your app directly instead of Safari.
Step-by-Step: Configuring the AASA File
Correctly creating and hosting the AASA file is the most critical and error-prone part of implementing Universal Links.
Step 1: Create the `apple-app-site-association` File
The AASA file is a simple JSON. It should not have a `.json` extension. The filename must be exactly `apple-app-site-association`.
{
"applinks": {
"apps": [],
"details": [
{
"appID": "YOUR_TEAM_ID.com.yourcompany.yourapp",
"paths": [ "/products/*", "/articles/2025/*" ]
}
]
}
}
- appID: This is a combination of your Apple Developer Team ID and your app's Bundle ID.
- paths: An array of URL paths your app can handle. Use `*` as a wildcard for dynamic paths and `?` to match a single character. Use `"NOT /products/legacy/*"` to exclude specific paths. `["*"]` will match your entire site.
Step 2: Host the AASA File on Your Server
This is where most implementations fail. Your server must meet Apple's strict requirements:
- Location: The file must be accessible at either `https://your.domain/.well-known/apple-app-site-association` or `https://your.domain/apple-app-site-association`.
- HTTPS Only: It must be served over a secure connection with a valid SSL certificate.
- No Redirects: The URL must return a `200 OK` status code directly. Any redirects will cause validation to fail.
- Content-Type Header: The server must serve the file with the `application/json` content-type header.
Step 3: Configure Your App in Xcode
In your Xcode project, go to the "Signing & Capabilities" tab for your app's target. Click "+ Capability" and add "Associated Domains." In the domains list, add an entry for each domain you want to support, prefixed with `applinks:`. For example: `applinks:links.yourbrand.com`.
How App Links Work (Android)
Android App Links function very similarly to Universal Links. They use standard `https` URLs and a verification process to ensure the app is the legitimate owner of the domain.
- You add `intent-filter` tags to your app's `AndroidManifest.xml` that declare which `https` URLs your app can handle. You must include `android:autoVerify="true"`.
- You host a special JSON file called `assetlinks.json` at a well-known location on your domain.
- When a user installs your app, the Android OS checks for this file. It verifies that the file is valid and contains your app's package name and certificate fingerprint.
- If verification succeeds, the OS designates your app as the default handler for those URLs. Tapping a matching link will then open your app directly.
Step-by-Step: Configuring the `assetlinks.json` File
Step 1: Get Your App's SHA-256 Fingerprint
The `assetlinks.json` file uses a SHA-256 fingerprint of your app's signing certificate to verify its identity. You can generate this using Android Studio's Gradle tools or via the command line with `keytool`.
Step 2: Create the `assetlinks.json` File
This file contains a JSON object that specifies which apps are associated with the domain.
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.yourcompany.yourapp",
"sha256_cert_fingerprints":
["YOUR:SHA256:FINGERPRINT:HERE"]
}
}]
- package_name: Your app's package name from the `build.gradle` file.
- sha256_cert_fingerprints: An array containing the SHA-256 fingerprint of your production signing certificate.
Step 3: Host the `assetlinks.json` File
The hosting requirements are strict and similar to iOS:
- Location: The file must be accessible at `https://your.domain/.well-known/assetlinks.json`.
- HTTPS Only: It must be served over a secure connection with a valid SSL certificate.
- No Redirects: The URL must return a `200 OK` status code directly.
- Content-Type Header: The server must serve the file with the `application/json` content-type header.
Common Pitfalls & Troubleshooting
This is where teams waste the most time. A single misconfiguration can cause the entire system to fail silently. Here are the most common issues:
Invalid JSON
A single trailing comma or missing bracket in your AASA or `assetlinks.json` file will cause the entire validation to fail. Always use a JSON linter.
Server/CDN Misconfiguration
Your web server or CDN might be configured to redirect requests to the `.well-known` directory, or it might not be serving the file with the correct `Content-Type` header. This is a very common point of failure.
App ID Mismatches
A small typo in the Team ID, Bundle ID, or Package Name will break the secure association. Double and triple-check these values.
Testing with the Wrong Certificate
For Android, you must use the fingerprint of the certificate you use to sign your release build, which is often different from your debug certificate.
The Infrastructure Solution: This Shouldn't Be Your Problem
As you can see, the process is brittle and requires careful coordination between mobile developers, web developers, and DevOps. A single change to your server configuration by the web team can silently break your entire mobile deep linking strategy.
This is a problem best solved at the infrastructure level. A lightweight, API-first service like SDDL abstracts away all of this complexity. Instead of managing these files yourself, you provide your app's details to us, and we handle the rest:
- Automated File Generation: We create perfectly formatted AASA and `assetlinks.json` files for you.
- Bulletproof Hosting: We serve these files from a globally distributed, high-availability infrastructure, guaranteeing they are always available with the correct headers and without redirects.
- Simplified Management: Need to add a new path or domain? Update it via a simple API call. No need to file a ticket with your web team and wait two weeks.
This lets your team focus on building great app features, not debugging server configurations.
FAQ
Can I use a different domain for my deep links than my main website?
Yes, and it's often a best practice. Using a dedicated subdomain like `links.yourbrand.com` for all your deep links isolates the configuration from your main web infrastructure, reducing the risk of accidental breakage.
What happens if a user disables Universal Links for my app?
If a user explicitly chooses to open links in the browser (by tapping the small "yourbrand.com >" button in the top-right corner of the app), iOS will remember this choice. The link will then open in Safari. This is why having a good web-to-app journey with a smart banner on your mobile site is also important.
How do I test my setup?
Both Apple and Google provide web-based validators where you can check your domain's configuration files. You can also test by sending a link to yourself in an email or iMessage and tapping it on a physical device. Testing in a development environment often requires specific device and provisioning profile configurations.
Related guides
Continue exploring-
Deep Links — The Complete Guide
Guide -
Deferred Deep Links — How They Work
Guide -
Universal Links (iOS) — Setup & Troubleshooting
Guide -
Firebase Dynamic Links Alternative
Guide -
Branch.io Alternative
Guide -
App Links (Android)
Guide -
Troubleshooting Playbook
Guide -
QA Playbook
Guide -
E-commerce Deep Links
Guide -
Deep Links for Ads
Guide -
QR Codes to App — Deferred Deep Links
Guide -
Email & SMS Deep Links
Guide -
Creator & Affiliate Deep Links
Guide -
Gaming Deep Links — Rewards, Quests
Guide -
No-SDK Deep Links — REST-Only
Guide -
Deferred Deep Links in React Native — Setup Guide
Guide