App Links vs Universal Links: Technical Comparison 2026

Deep technical comparison of Android App Links vs iOS Universal Links. Implementation guides, common mistakes, and production best practices for mobile engineers.


App Links vs Universal Links: Technical Comparison 2026

App Links (Android App Links) and Universal Links (iOS Universal Links) are platform-specific deep linking standards that open native apps directly from web URLs without user prompts. App Links use Android's Intent Filter verification with Digital Asset Links, while Universal Links rely on iOS's apple-app-site-association file hosted on your domain. Both require HTTPS domains and proper server configuration. The key difference: App Links work on Android 6.0+, Universal Links on iOS 9+, and they're not interchangeable—you need both for cross-platform coverage.

App Links and Universal Links solve the same problem using different technical implementations. When a user taps a link in an email, SMS, or web page, these standards allow the URL to open directly in your native app instead of a mobile browser—assuming the app is installed.

Here's the mental model that matters:

  • Android App Links: Google's standard requiring verified domain ownership through a JSON file at /.well-known/assetlinks.json
  • Universal Links: Apple's standard requiring verified domain ownership through a JSON file at /.well-known/apple-app-site-association

Both are verified deep links—the operating system validates that you own both the domain and the app before allowing seamless handoff. This prevents malicious apps from hijacking your web traffic.

Without verification, you're stuck with URI schemes (myapp://), which trigger confirmation dialogs, fail silently if the app isn't installed, and don't work in many contexts like Chrome Custom Tabs or in-app browsers.

Key Technical Differences

Feature Android App Links iOS Universal Links
OS Support Android 6.0+ (API 23+) iOS 9.0+
Verification File assetlinks.json apple-app-site-association
File Location /.well-known/assetlinks.json /.well-known/apple-app-site-association or root
Content-Type application/json application/json or application/pkcs7-mime
Requires HTTPS Yes Yes
Fallback Handling Opens in browser automatically Opens in Safari automatically
Verification Timing App install + periodic checks App install + updates

The verification files serve the same purpose but have different syntax. Google wants proof your app should handle your domain. Apple wants the same proof, formatted differently.

Both systems follow a similar flow, but implementation details diverge significantly.

Android App Links Implementation

Step 1: Configure Intent Filters

In your AndroidManifest.xml, declare which URLs your app handles:

<activity android:name=".ProductActivity">
    <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="/products" />
    </intent-filter>
</activity>

The android:autoVerify="true" attribute triggers domain verification at install time.

Step 2: Host Digital Asset Links File

Place this at https://example.com/.well-known/assetlinks.json:

[{
  "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"
    ]
  }
}]

The sha256_cert_fingerprints must match your app's signing certificate. Android validates this when the app is installed.

Step 3: Handle Incoming Links

In your Activity:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    handleIntent(intent)
}

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    handleIntent(intent)
}

private fun handleIntent(intent: Intent) {
    val appLinkData: Uri? = intent.data
    if (appLinkData != null) {
        val productId = appLinkData.lastPathSegment
        // Navigate to product screen
    }
}

iOS Universal Links Implementation

Step 1: Configure Associated Domains

In Xcode, add your domain to the Associated Domains capability:

applinks:example.com

This goes in your entitlements file (YourApp.entitlements):

<key>com.apple.developer.associated-domains</key>
<array>
    <string>applinks:example.com</string>
</array>

Step 2: Host AASA File

Create https://example.com/.well-known/apple-app-site-association (no file extension):

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAMID.com.example.app",
        "paths": ["/products/*"]
      }
    ]
  }
}

The appID combines your Team ID (from Apple Developer account) with your bundle identifier. iOS downloads this file when your app is installed.

Step 3: Handle Universal Links

In your AppDelegate or SceneDelegate:

func application(_ application: UIApplication,
                 continue userActivity: NSUserActivity,
                 restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
          let url = userActivity.webpageURL else {
        return false
    }
    
    // Parse URL and navigate
    if url.pathComponents.contains("products") {
        let productId = url.lastPathComponent
        // Navigate to product screen
    }
    
    return true
}

For SwiftUI apps using scenes:

WindowGroup {
    ContentView()
        .onOpenURL { url in
            // Handle universal link
        }
}

Common Mistakes and Edge Cases

After implementing both systems in production, here are the issues that consistently trip up developers:

1. HTTPS Misconfiguration

Both platforms require valid HTTPS certificates. Self-signed certificates, expired certificates, or certificate chain issues will silently break verification. Use tools like SSL Labs to validate your setup before debugging app code.

Edge case: If you're using a CDN or reverse proxy (CloudFlare, Fastly), ensure the verification files bypass caching and transformations. CDNs sometimes modify JSON responses, breaking signature verification.

2. Android Certificate Fingerprint Mismatches

The most common Android App Links failure: using debug keystore fingerprints in production or forgetting to add release certificate fingerprints.

Get your release fingerprint:

keytool -list -v -keystore release.keystore

If you use Google Play App Signing, you need both your upload key fingerprint and the app signing key fingerprint from Play Console. Add both to assetlinks.json.

3. iOS Path Matching Gotchas

Universal Links path patterns are finicky:

  • "/products/*" matches /products/123 but NOT /products
  • "/products*" matches both /products and /products/123
  • Query parameters are ignored in path matching

Exclusion patterns work with NOT:

"paths": ["/buy/*", "NOT /buy/exclude/*"]

Test thoroughly because iOS caches AASA files aggressively.

4. Testing in Wrong Contexts

Universal Links don't work when tapping links on the same domain in Safari. If you're on example.com and tap a link to example.com/products/123, Safari opens it in the browser, not your app. This is intentional—Apple assumes users want to stay in Safari.

Test from different contexts:

  • Notes app
  • Messages
  • Third-party apps (Slack, Email)
  • Safari Reader Mode

On Android, test from Gmail, Chrome (not same-domain), and SMS. App Links behave differently in WebView contexts.

5. Subdomain and Multi-Domain Complications

Each subdomain needs its own verification file. If you support shop.example.com and example.com, you need:

  • https://example.com/.well-known/assetlinks.json
  • https://shop.example.com/.well-known/assetlinks.json

On iOS, add each subdomain to Associated Domains:

applinks:example.com
applinks:shop.example.com

Wildcard subdomains are supported on iOS (applinks:*.example.com) but require careful AASA configuration.

6. Link Shorteners Breaking Verification

If you use URL shorteners like bit.ly or generic shorteners, App Links and Universal Links won't work unless the shortener domain is also configured. The OS validates the shortened URL's domain, not the final destination.

Solution: Use a URL shortener that supports custom domains for deep linking, allowing you to host verification files on your branded short domain.

Best Practices for Production Systems

Verify Early, Test Often

Use Google's Statement List Generator and Tester:

https://developers.google.com/digital-asset-links/tools/generator

For iOS, use Apple's AASA validator or test directly:

https://app-site-association.cdn-apple.com/a/v1/example.com

This shows you exactly what iOS cached for your domain.

Monitor Verification File Availability

Set up uptime monitoring for your assetlinks.json and AASA files. If these go down or return 404s, new app installs won't establish verified links.

Check that:

  • Files return 200 OK
  • Content-Type is application/json
  • No redirects occur (Android may follow 301/302, iOS won't)
  • Response size is under 128 KB (iOS limit)

Version Your AASA Files Carefully

iOS caches AASA files for days or weeks. When you update path patterns, existing users may not see changes immediately. Plan for gradual rollout or use server-side routing to handle both old and new patterns during transitions.

Implement Fallback Logic

Even with perfect configuration, App Links and Universal Links can fail due to:

  • User explicitly choosing "Open in Browser"
  • Corporate network proxies stripping headers
  • OS bugs or version-specific issues

Always include a web fallback that handles the same deep link parameters. Your web page should:

  • Attempt a final deep link with custom URI schemes (fallback of fallback)
  • Show app store badges
  • Display meaningful content for web users

Track Link Performance

Instrument your deep link handlers to track:

  • App opens via verified links vs URI schemes vs direct launch
  • Failed deep link attempts (users who landed on web instead)
  • Time-to-handle metrics

Use link-level analytics to understand where users drop off in the deep link flow.

1. You Don't Control the Domain

If you're using third-party platforms (Shopify, WordPress.com, hosted solutions) where you can't upload custom files to /.well-known/, verified deep links won't work. You need full control over your domain's web server.

2. Your App Isn't Listed Yet

Both systems require your app to be installed from official app stores. During beta testing with TestFlight or internal builds, Universal Links work, but if you're using sideloaded APKs or enterprise distribution, verification may fail.

3. Cross-App Communication

If you're building deep links for other apps to call yours (like payment callbacks or OAuth redirects), URI schemes (yourapp://callback) are more reliable. App Links and Universal Links are designed for web-to-app transitions, not app-to-app.

4. Immediate Testing Needs

Setting up verified links requires domain access, certificate management, and app store builds. If you need to test deep linking logic quickly, start with URI schemes. Migrate to verified links before production launch.

5. Web-Only Flows

If your feature is intentionally web-only (like password reset flows that should never open in-app), exclude those paths from your verification files. Don't assume every link should deep link.

In 2025, verified deep links are table stakes, but they're only one piece of a complete deep linking strategy.

The Verified Link Foundation

App Links and Universal Links handle the "installed app" scenario perfectly. When a user taps a link and has your app, these standards provide instant, seamless handoff. This is critical for:

  • Email campaigns to existing users
  • Push notification fallbacks
  • Social media post attribution
  • Referral program links

Deferred Deep Links for New Users

Verified links don't solve the "app not installed" problem. When users don't have your app, the link opens in a browser. This is where deferred deep linking becomes essential.

A complete system combines:

  1. Universal Links / App Links for installed users (instant open)
  2. Smart web pages that detect app installation status
  3. Deferred deep links that preserve context through app install
  4. Attribution tracking to measure conversion across the journey

Platforms like Smler implement this full stack. When you create a deferred deep link, the system:

  • Serves verified AASA and assetlinks files for your custom domain
  • Routes installed users directly to your app via App Links/Universal Links
  • Sends uninstalled users to the app store with preserved deep link data
  • Passes original link context to your app on first launch

Analytics and Attribution Layer

Raw App Links and Universal Links don't provide click tracking, geographic data, or device information. Wrapping them in a URL shortener with link-level analytics gives you visibility into:

  • Click-through rates before app opens
  • Platform split (iOS vs Android vs desktop)
  • Geographic performance
  • Time-to-conversion metrics

Multi-Platform Routing

Production deep linking systems need device-based routing. A single shortened URL should:

  • Open Android app via App Links on Android devices
  • Open iOS app via Universal Links on iOS devices
  • Redirect desktop users to a landing page
  • Handle edge cases (Kindle, smart TVs, etc.)

Implementing this manually requires significant infrastructure. Smart URL shorteners handle platform detection, fallback logic, and routing automatically.

Compliance and Brand Control

For SMS campaigns, especially in regulated markets, you need compliance-ready short URLs with custom domains and header support. Generic shorteners (bit.ly, tinyurl) don't support the domain verification files needed for App Links and Universal Links.

Using branded short domains gives you:

  • Full control over verification files
  • Brand consistency in links
  • Trust signals for users
  • SEO benefits from your own domain

Frequently Asked Questions

Can I use both App Links and Universal Links for the same URL?

Yes, and you should. A single https://example.com/products/123 URL can work as both an Android App Link and iOS Universal Link. Host both assetlinks.json and apple-app-site-association files on the same domain. The operating systems check their respective files independently.

Why do my Universal Links stop working after tapping "Open in Safari"?

iOS remembers user preference. If a user long-presses a Universal Link and chooses "Open in Safari" (or taps the top-right breadcrumb to return to Safari), iOS disables Universal Links for that domain until the user manually re-enables them. There's no programmatic fix—this is intentional user control. To re-enable, the user must long-press a link and choose "Open in [App Name]".

Do App Links work in WebView or Chrome Custom Tabs?

Android App Links behavior varies by context. In Chrome Custom Tabs, they typically work. In WebView components, they often don't—the link opens in the WebView browser instead of triggering the app. This affects in-app browsers used by Facebook, Twitter, and Instagram. For reliable deep linking from social apps, consider implementing alternative strategies like QR codes that open in system browsers.

How long does it take for iOS to verify my AASA file after I update it?

iOS fetches AASA files during app installation and updates. For already-installed apps, iOS may cache the file for several days. Apple's CDN also caches it. In practice, expect 24-48 hours for changes to propagate to all users. Uninstalling and reinstalling your app forces immediate re-fetch during testing, but don't expect real users to do this.

Can I debug why my App Links aren't working on Android?

Yes. Use ADB to check verification status:

adb shell pm get-app-links com.example.app

This shows which domains are verified. For detailed logs:

adb shell dumpsys package domain-preferred-apps

Look for your package name and check verification state. If it shows "none" or "legacy_failure", there's a problem with your assetlinks.json file or certificate fingerprints.

Summary: Choosing the Right Approach

App Links and Universal Links are not competing standards—they're complementary platform requirements. If you're building a cross-platform mobile app, you need both. There's no either/or decision.

Key takeaways:

  • App Links are Android's verified deep linking standard; Universal Links are iOS's equivalent
  • Both require HTTPS domains, server-hosted verification files, and proper app configuration
  • Implementation differs significantly, but the end-user experience is identical: seamless web-to-app transitions
  • Common failures stem from certificate mismatches, caching issues, and testing in wrong contexts
  • Verified links are essential but insufficient alone—combine with deferred deep linking, analytics, and smart routing

For production systems, consider using a deep linking platform that handles verification file hosting, multi-platform routing, and analytics automatically. This lets you focus on app features instead of infrastructure edge cases.

When implementing from scratch, start with one platform to validate your verification file setup, then expand to the second. Test across multiple apps and contexts before launching to users. And always implement web fallbacks—no deep linking system is 100% reliable across all environments.

Published with LeafPad