To open a specific page of a web-powered app from an HTTPS link, configure Universal Links on iOS and Android App Links on Android. Both need proof that the website and installed app belong together. Then the app must read the incoming URL and show the matching screen or web route. A WebView wrapper does not automatically do all three steps.
For example, https://example.com/products/42 should open product 42 in the installed app and remain a useful product page in the browser when the app is absent. That one-link approach is more robust than sending every visitor to the app's home screen or relying on a custom URL scheme with no web fallback. This guide covers setup, routing, and debugging for an app built around an existing website. Platform documentation checked September 22, 2026.
Universal Links vs Android App Links: what changes?
| Concern | iOS Universal Links | Android App Links |
|---|---|---|
| Link people share | Normal HTTPS URL, such as https://example.com/products/42 |
The same HTTPS URL |
| Website proof | apple-app-site-association (AASA) file |
.well-known/assetlinks.json file |
| App-side declaration | Associated Domains entitlement, such as applinks:example.com |
VIEW intent filter with android:autoVerify="true" |
| App identity in proof | Application identifier prefix + Bundle ID | Android package name + SHA-256 signing certificate fingerprint |
| Final destination | Your app handles the incoming URL | Your app handles the incoming intent URL |
The association proves which app may claim a domain. It does not decide what your app renders after launch. For a WebView app, the last step is usually to pass the validated link's path and query string into the web router or load an approved URL in the WebView. Apple's associated domains guide, Android's App Links guide, and Capacitor's deep-link guide describe the platform parts.
Start with one canonical HTTPS URL per destination
Before editing native configuration, list the destinations users actually share: a product page, booking, invitation, article, support ticket, or notification target. Give each destination a stable URL on a domain you control.
| Shared URL | Installed-app destination | Website fallback |
|---|---|---|
https://example.com/products/42 |
Product 42 | Product 42 on the website |
https://example.com/orders/123 |
Order 123, after authentication | Sign-in, then order 123 |
https://example.com/invite/abc |
Invitation acceptance flow | Invitation landing page |
The website fallback must work on its own. If the link is opened on a desktop, in an unsupported browser, or before the app is installed, the user should still reach meaningful content or a clear sign-in state. Decide whether example.com or www.example.com is the canonical host: those are distinct hosts for verification. Avoid redirect-only tracking domains unless they are also correctly configured and tested; a redirect is not a substitute for a verified link on the URL the user taps.
For private destinations, preserve the intended route through login and enforce authorization on the server. A deep link is navigation input, not proof that the person may view the record. Never place access tokens or sensitive personal data in a URL that may be shared, logged, or copied.
Set up iOS Universal Links
1. Publish the Apple association file
Host an extensionless JSON file at:
https://example.com/.well-known/apple-app-site-association
Use the real application identifier prefix and Bundle ID registered for the iOS app. This example matches product URLs; replace the fictional ID and route with your own:
{
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.example.app"],
"components": [{ "/": "/products/*" }]
}
]
}
}
Apple documents the appIDs and components format in its AASA applinks reference. ABCDE12345 is an illustrative application identifier prefix, not an App Store Connect API Key ID. If the difference between Team ID, Bundle ID, and App ID is unclear, use our Apple identifiers guide before filling in the file.
Serve the AASA over HTTPS without a redirect, at the exact host named in the link. Do not append .json to the filename. If you use both example.com and www.example.com, each host needs its own file and app entitlement entry. See Apple's associated domains setup.
2. Add Associated Domains to the iOS target
In Xcode, select the app target, open Signing & Capabilities, add Associated Domains, and enter applinks:example.com. Add a separate applinks:www.example.com entry only if you intend that host to open the app too. Build with the correct signing team and registered app identifier; merely placing an AASA file on the site will not add the entitlement to an already shipped binary.
3. Handle the URL inside the app
iOS delivers the Universal Link as a browsing user activity. The app must extract its URL and navigate to the destination. In a Capacitor-based web app, the App plugin's appUrlOpen event is a common bridge into the web router. Validate that the URL's protocol and host are expected, retain the path and relevant query string, then navigate to the matching route. Handle both a cold start and a link tapped while the app is already open.
Do not simply load any inbound URL into a WebView. Limit navigation to approved hosts and routes, keep unrelated external links in the browser, and let the server enforce access control. If your app has multiple web domains, define an explicit mapping rather than guessing from a string split.
Set up Android App Links
1. Declare the HTTPS host in the manifest
Inside the activity that receives links in AndroidManifest.xml, add a verified web intent filter:
<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" />
</intent-filter>
This declares which HTTPS host the app wants to handle. Use path constraints if the app should claim only selected paths, and check how they interact with your association rules. Android's deep-link setup guide explains intent filters and URL matching. A new manifest or signing change requires a new Android build; publishing a website file alone does not update an installed app's manifest.
2. Publish Digital Asset Links
Host a public JSON file at:
https://example.com/.well-known/assetlinks.json
Its package_name must match the installed app's application ID. Its fingerprint must match the certificate that signed the installed app:
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": ["YOUR_SHA256_CERTIFICATE_FINGERPRINT"]
}
}
]
Replace the placeholder with the full colon-separated SHA-256 certificate fingerprint. For an app distributed through Play App Signing, use the app signing certificate shown in Play Console, not just a local upload-key fingerprint. A locally installed debug build may need a separate fingerprint for testing. Android permits multiple fingerprints in one statement. Serve assetlinks.json as application/json over HTTPS, with no redirect, on every declared host. Android's website association guide covers the exact format and Play App Signing caveat.
3. Route the incoming intent
The activity receives an ACTION_VIEW intent containing the URL. Your native or Capacitor layer must pass that URL into the app router so products/42 opens product 42 rather than the home screen. Capacitor's appUrlOpen guide shows this handoff for web-framework routers. Validate the domain, preserve the intended route during login, and test both cold and warm app starts.
On modern Android, an unverified web link will generally open in the browser instead of directly in your app. Do not mistake an intent filter for completed verification. Android's App Links verification guide explains the verification state and test commands.
Test the complete journey, not just the JSON files
Use a device or realistic release build with the app installed. A successful HTTP request for an association file proves only that the file is reachable; it does not prove that the signed app, operating system, and route handler agree.
- Open each
/.well-known/URL directly and confirm valid JSON, the correct host, no redirect, and the expected content type. - Install the signed app you intend to ship. On Android, confirm the installed certificate matches
assetlinks.json; on iOS, confirm the Associated Domains entitlement is in the built app. - Tap a matching HTTPS link from a message or Notes on iOS, and from a normal tappable source on Android. Check that it opens the specific destination, not only the app.
- Repeat while the app is already running, then after force-closing it. Test a protected route with the user signed out and signed in.
- Test a non-matching path, an uninstalled-app device, and desktop browser fallback. The website should remain usable.
For Android 12+, adb shell pm get-app-links com.example.app reports per-host verification state. If you have just changed the website file, Android's verification guide shows how to reset and request re-verification. On iOS, Apple's Universal Links debugging technote explains device tests and Apple's association-file cache. Allow time for iOS association updates; a browser-visible AASA change may not immediately reach a device.
Why does the link stay in the browser?
Check the problem in this order:
| Symptom | Likely cause | First check |
|---|---|---|
| Neither platform opens the app | Wrong host, inaccessible file, redirect, or invalid JSON | Request the exact /.well-known/ URLs for the tapped host |
| iOS stays in Safari | Missing entitlement, AASA mismatch/cache, or same-domain Safari navigation | Inspect the signed entitlement and test a link from Notes |
| Android opens the browser | Domain is not verified, package/fingerprint mismatch, or user link preference | Run adb shell pm get-app-links and compare the Play signing fingerprint |
| App opens but shows home | URL was received but never handed to the router | Log the incoming URL and test cold and warm starts |
| Link reaches a login screen, then loses destination | Redirect state is discarded during authentication | Store the intended route safely and resume it after login |
One iOS behavior is easy to misdiagnose: when someone is already browsing a site in Safari and taps another Universal Link on that same domain, Safari may continue browsing there. Apple describes this as respecting the user's intent, not a failed association. Test from Notes or another app before changing your AASA; if your product genuinely needs an “open in app” link from its own site, Apple's debugging guidance discusses using a separately associated subdomain.
Avoid treating every failure as a store-review problem. Link verification and route handling can be tested with installed development or test builds before an App Store or Play Store release. Store approval is a separate question.
Universal Links and App Links FAQ
Do Universal Links and Android App Links use the same URL?
Yes. Both can use a normal HTTPS URL such as https://example.com/products/42. Each platform needs its own app declaration and website association file, while the website supplies the fallback for people without the app.
Can a WebView app support deep links?
Yes. The native shell receives a verified link and passes its destination into the WebView or web router. Opening the shell alone is not enough; the route must resolve to the intended content.
Do I need both apple-app-site-association and assetlinks.json?
Yes, if the same domain should open both iOS and Android apps. Apple reads the extensionless AASA file; Android reads assetlinks.json. Each has a different format and app identity.
Can I use a custom URL scheme instead?
You can, but a custom scheme does not provide the same normal-website fallback or verified ownership of an HTTPS domain. Use Universal Links and App Links for shareable content URLs, and reserve custom schemes for cases where their tradeoffs are acceptable.
Do example.com and www.example.com need separate setup?
Yes. Treat them as separate hosts. Declare each host in the app and serve the appropriate association file on each one if both should open the app. A redirect between them is not a replacement for host verification.
Which Android SHA-256 fingerprint should I use with Play App Signing?
Use the app signing certificate fingerprint from Play Console for the build delivered to users. The upload key used to send your bundle to Google Play is usually different. Add a test certificate only if you also need to verify a separately signed test build.
Why does the app open but ignore the deep-link path?
Domain verification only starts the app. Your app must read the incoming URL and route it to the matching page. In a Capacitor app, handle appUrlOpen and connect it to your web router; test cold starts and links received while the app is running.
Will adding the association files update an already installed app?
Website association changes can be fetched by the platforms, subject to their verification and caching behavior. But if the installed app lacks the iOS entitlement, Android intent filter, or route handler, you need a new signed app build with those changes.
Official setup and debugging references
- Apple: Supporting associated domains
- Apple: AASA
applinksformat - Apple: Debugging Universal Links
- Android: About App Links
- Android: Configure website associations
- Android: Verify App Links
- Capacitor: Deep Linking with Universal and App Links
Continue building your web-powered app
Give each shared link a useful mobile destination
WebNativeApp helps package an existing website into iOS and Android app projects while you retain the web product and native source code. If your app needs verified links, plan the owned domains, association files, native configuration, and route handoff as part of the mobile release, then test the signed builds on real devices.