Handling App Links and Universal Links: A Comprehensive Guide

Table of Contents
Big thanks to our contributors those make our blogs possible.

Our growing community of contributors bring their unique insights from around the world to power our blog. 

Introduction

Deep linking is critical to seamless user experiences, letting you drive traffic from emails, web pages, and social channels directly into the relevant screen of your mobile app. On Android, these are called App Links; on iOS, Universal Links. Both allow HTTP URLs to open your app if installed, or fall back to the website if not—eliminating broken links and reinforcing brand consistency. In this guide, you’ll learn:

  1. The difference between URI schemes, App Links, and Universal Links
  2. Why you should adopt HTTP-based deep links over custom schemes
  3. How to configure Universal Links on iOS
  4. How to configure App Links on Android
  5. Handling link routing in your app’s code
  6. Testing, debugging, and best practices
AspectCustom URI Schemes (myapp://…)HTTP-Based Links (App/Universal)
Fallback behaviorFails if the app isn’t installedOpens web fallback automatically
Link hijacking riskAny app can register the same schemeDomain ownership verification required
SEO and sharingNot indexable by search enginesStandard URLs improve SEO and shareability
User trustUsers see unfamiliar protocolsFamiliar HTTPS URLs inspire trust

Bottom line: HTTP-based deep links provide a more robust, secure, and user-friendly experience.

2.1 Enable Associated Domains

  1. In Xcode, select your app target → Signing & Capabilities.
  2. Click + CapabilityAssociated Domains.
  3. Add an entry: makefileCopyEditapplinks:example.com

2.2 Host the apple-app-site-association File

  1. At https://example.com/apple-app-site-association (no .json extension), serve this JSON with application/json or application/pkcs7-mime content-type: jsonCopyEdit{ "applinks": { "apps": [], "details": [ { "appID": "TEAMID.com.example.myapp", "paths": [ "/product/*", "/profile/*" ] } ] } }
  2. Ensure HTTPS with valid certificate and no redirects.

In your SceneDelegate (iOS 13+) or AppDelegate:

swiftCopyEditfunc scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
  guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
        let url = userActivity.webpageURL else { return }

  DeepLinkManager.shared.route(to: url)
}
  • Parse the path (/product/123)
  • Navigate to the corresponding view controller

3.1 Declare an Intent Filter

In AndroidManifest.xml, for your main Activity:

xmlCopyEdit<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="/product/" />
</intent-filter>
  • android:autoVerify="true" prompts the OS to verify your association.

At https://example.com/.well-known/assetlinks.json, serve:

jsonCopyEdit[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.myapp",
    "sha256_cert_fingerprints": [
      "AB:CD:EF:12:34:56:78:90:..."
    ]
  }
}]
  • Use your app’s signing certificate fingerprint.

3.3 Handle the Intent in Your Activity

javaCopyEdit@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  Intent intent = getIntent();
  Uri data = intent.getData();
  if (data != null) {
    DeepLinkRouter.getInstance().route(this, data);
  }
}
  • Extract segments (data.getPathSegments()) to determine which screen to show.

4.1 React Native (React Navigation)

jsCopyEditimport { NavigationContainer } from '@react-navigation/native';

const linking = {
  prefixes: ['https://example.com'],
  config: {
    screens: {
      Product: 'product/:id',
      Profile: 'profile/:userId',
    },
  },
};

export default function App() {
  return (
    <NavigationContainer linking={linking}>
      <RootNavigator />
    </NavigationContainer>
  );
}

4.2 Flutter (GoRouter)

dartCopyEditfinal GoRouter router = GoRouter(
  urlPathStrategy: UrlPathStrategy.path,
  routes: [
    GoRoute(path: '/product/:id', builder: (_, state) => ProductPage(id: state.params['id'])),
    GoRoute(path: '/profile/:userId', builder: (_, state) => ProfilePage(userId: state.params['userId'])),
  ],
);

5. Deferred Deep Linking (Cold-Start Scenarios)

5.1 Android — Install Referrer

  • Integrate the Play Referrer API to retrieve the original link used to install the app.
  • Use the new “fallback” parameter in App Store URLs, or store the link in your backend for retrieval after first launch.

5.3 Third-Party SDKs

  • Services like Branch.io, Firebase Dynamic Links, and Adjust handle deferred deep linking, attribution, and analytics out of the box.

6. Testing and Debugging

  1. Localhost with Ngrok:
    • Tunnel example.com to your dev machine.
  2. iOS Simulator & Android Emulator:
    • Universal Links on simulator require real device for validation; test web fallback in simulator.
  3. Verify Association:
    • iOS: Check Associated Domains logs in device Console.
    • Android: Run adb shell pm get-app-links com.example.myapp.
  4. Edge Cases:
    • App not installed → opens web page
    • Invalid path → show 404 or home
    • Conflicting intent filters → ensure only one handles your URL

7. Analytics and Attribution

  • UTM Parameters: Append ?utm_source=campaign&utm_medium=email to your deep links.
  • In-App Logging: Record link_opened, link_source, and link_target events in your analytics platform (Firebase, Amplitude).
  • Campaign Tracking: Measure conversion lift by comparing direct installs vs. deep-linked installs.

Conclusion

App Links and Universal Links empower you to bridge the web and mobile worlds, delivering users directly to the content they care about—regardless of whether your app is already installed. By configuring domain associations, intent filters, and proper code routing, you can ensure reliable, secure, and analytics-enabled deep linking. Embrace HTTP-based links to improve SEO, simplify sharing, and provide cohesive fallbacks. With thorough testing, deferred deep linking support, and clear attribution, your deep link strategy will become a cornerstone of user acquisition, engagement, and retention.

Let's connect on TikTok

Join our newsletter to stay updated

Sydney Based Software Solutions Professional who is crafting exceptional systems and applications to solve a diverse range of problems for the past 10 years.

Share the Post

Related Posts