Blog

Universal Links and App Links Setup Guide

Lakshith Dinesh

Lakshith Dinesh

Head of Growth, Linkrunner

Last updated on 5 min read

Universal Links and App Links Setup Guide

Setting up deep links that open your app on both platforms sounds like a quarter of engineering work. It is not. There are two small JSON files, one DNS record, two app config changes and a test plan. Most of the delay comes from hosting the files wrong and waiting on Apple's cache.

This guide covers the full setup on a branded link domain, from choosing the subdomain to testing on real devices. If you use Linkrunner, it hosts both association files and the SSL certificate on your link domain, so the work drops to pasting two files into the dashboard and two app config changes. Integration is the same day for most teams, fully live within a week.

What are Universal Links and App Links?

Universal Links (iOS) and App Links (Android) are ordinary HTTPS links that the operating system opens directly in your app, because a file on your domain proves the app and the domain belong together. When the app is not installed, the same link opens in the browser.

The two proof files:

  • Apple App Site Association (AASA): served at /.well-known/apple-app-site-association, lists your app IDs and the URL paths they may open.
  • assetlinks.json: served at /.well-known/assetlinks.json, lists your Android package name and signing certificate fingerprints.

What you need before you start

ItemWhere to find it
Apple Team IDApple Developer Portal, Membership details
iOS bundle IDXcode project settings
Android package nameapplicationId in your Gradle file
SHA-256 fingerprintsPlay Console, Setup > App integrity (Play App Signing key), plus your upload and debug keys
DNS accessYour DNS provider for the parent domain

Use the Play Console fingerprint, not just the one from your local keystore. If Google signs your releases, the local key will not match what users install.

Step 1: choose a link domain

Use a dedicated subdomain such as go.yourapp.com or links.yourapp.com, not your root domain or www.

  • Trust: a link on your own domain reads as first-party in SMS, email and WhatsApp previews. Vendor domains look like marketing tools.
  • Same-domain rule: Safari keeps a tap on the same domain in the browser. A separate link subdomain lets buttons on your website open the app.
  • Migration independence: if you change link vendors, you repoint one DNS record and existing links keep working. Links on a vendor domain stay with the vendor.

Step 2: DNS and SSL

Add one CNAME record pointing your subdomain at your link provider. With Linkrunner, the subdomain setup is:

  • Host: go (for go.yourapp.com)
  • Value: api.linkrunner.io
  • Cloudflare: set the record to "DNS only" (grey cloud), or certificate provisioning fails.

Linkrunner then shows CNAME Verified and SSL Active, usually within minutes. If you need links today, a free yourname.app-link.co subdomain works in one click with no DNS record, and you can add the branded domain later.

Self-hosting? You also own the certificate. An expired certificate on the link domain breaks every Universal Link silently, so add an expiry alert at setup.

Step 3: the AASA file

A minimal modern file:

{
  "applinks": {
    "details": [
      {
        "appIDs": ["TEAMID.com.yourapp.ios"],
        "components": [
          { "/": "/p/*", "comment": "Product links" },
          { "/": "/internal/*", "exclude": true }
        ]
      }
    ]
  }
}

Hosting rules from Apple's TN3155:

  • HTTPS, a 200 response and no redirect on this path.
  • No .json extension; serve as application/json.
  • Open to every IP address and user agent, so exempt the path from bot protection.
  • One file per specific subdomain in your Associated Domains list.
  • Do not mix appIDs/components with the legacy appID/paths format.

Step 4: the assetlinks.json file

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.yourapp.android",
    "sha256_cert_fingerprints": ["AB:CD:..."]
  }
}]

Google's App Links requirements mirror Apple's: HTTPS, application/json, no redirects, valid JSON. List the Play signing, upload and debug fingerprints together.

With Linkrunner: paste the AASA into iOS Verification Object and assetlinks.json into Android Verification Object under Settings > Deeplinks, and Linkrunner serves both on your link domain. The deep linking setup doc has the full steps.

Step 5: configure the app

iOS: in Xcode, Signing and Capabilities, add Associated Domains with applinks:go.yourapp.com. While testing, applinks:go.yourapp.com?mode=developer makes development builds read your server directly instead of Apple's CDN.

Android: add a verified intent filter for each host:

<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="go.yourapp.com" />
</intent-filter>

Then route the incoming URL to a screen in your navigation layer (React Navigation, go_router or native). Ship one release with both changes.

Step 6: test before any campaign

CheckiOSAndroid
File is servedcurl -v https://go.yourapp.com/.well-known/apple-app-site-associationcurl -I https://go.yourapp.com/.well-known/assetlinks.json
Platform sees ithttps://app-site-association.cdn-apple.com/a/v1/go.yourapp.comDigital Asset Links API statements:list
Pattern or host matchessudo swcutil verify on a Macadb shell pm get-app-links com.yourapp.android
Device testSettings > Developer > Universal Links > Diagnosticsadb shell am start -a android.intent.action.VIEW -d "https://go.yourapp.com/p/42"

Then run the functional tests on physical devices:

  • App installed: the link opens the right screen.
  • App not installed: the link goes to the store.
  • After installing from that link: the app opens on the right screen. That is deferred deep linking, and it needs an SDK, not just the two files.
  • From inside Instagram, WhatsApp and your email client, not just Safari and Chrome.

Linkrunner's free AASA and assetlinks.json validator runs the file checks in a browser. Our deep link QA checklist extends this to attribution.

Self-hosted vs hosted: what you maintain

TaskSelf-hostedHosted by a link provider
DNS recordOne CNAME or A recordOne CNAME
SSL certificate and renewalYouProvider
AASA and assetlinks.json hostingYou, on every hostProvider
Bot protection and redirect exemptionsYouProvider
File updates when signing keys changeEdit and redeployPaste into the dashboard
App config (entitlement, intent filter)YouYou
Deferred deep linking and attributionBuild or buyIncluded with an MMP like Linkrunner

The app config is the only part you cannot hand off, which is why setup is fast with a hosted provider.

When it does not work

  • iOS link opens Safari or the App Store: work through our Universal Links troubleshooting guide. Apple's CDN refreshes about weekly, so reinstall the app after fixing the file.
  • Android link opens Chrome: our Android App Links guide covers fingerprints, autoVerify and stale verification.
  • CNAME not resolving after a day: look for a conflicting A record on the same subdomain, and check you entered only the label (go) if your provider expects it.
  • Works in Safari, not in social apps: in-app browsers need an "Open in app" intermediary page.

FAQ

How long does it take to set up Universal Links and App Links? With a provider that hosts the files and SSL, integration is the same day for most teams, fully live within a week. Most of the remaining time is an app release and Apple's CDN picking up the AASA.

Do I need a custom domain for deep links? No. A vendor subdomain such as yourname.app-link.co works. A branded subdomain earns more trust in SMS and email and keeps your links working if you switch vendors.

Can I use my root domain for Universal Links? You can, but a dedicated subdomain is safer. It keeps the association files separate from your website, and it lets links on your own site open the app, since Safari keeps same-domain taps in the browser.

Do I need to update the files when my app changes? Yes, when your Team ID, bundle ID, package name or signing certificate changes. Adding new paths also means editing the AASA, then waiting for Apple's CDN to refresh.

Next step

Universal Links and App Links need two files, one DNS record, two app settings and a test plan. Get the hosting right and the rest is routine.

If you would rather not host the files yourself, Linkrunner serves both on your branded domain, provisions SSL, and makes every link deferred by default with attribution in the same SDK. Request a demo and set up your first link domain with us.

Start measuring the installs your team cares about

Bring attribution, deep links, SKAN, cohorts, and campaign intelligence into one workflow your growth team can trust.