Home Guides Deferred Deep Linking Guide

Deferred Deep Linking Guide

Last updated on Apr 04, 2026

import MermaidChart from '@site/src/components/MermaidChart'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';

Deferred Deep Linking

Deferred deep linking allows you to pass link data through the app store installation process. When a user clicks a link but doesn't have your app installed, li-nk.me preserves the link data so the app can retrieve it after installation.

If you are setting this up for the first time, pair this guide with the Universal Links Validator, custom domain setup, and the Portal so you can verify the association files and app settings before testing install flows.

How It Works

The Problem

When a user clicks a link:

  1. App is installed → Universal Link / App Link opens the app directly with the full payload
  2. App is NOT installed → User is redirected to the App Store / Play Store

In case #2, the original link context is normally lost. Deferred deep linking solves this.

The Solution

li-nk.me uses platform-specific mechanisms to recover the original link data:

Platform Primary Method Fallback
Android Play Install Referrer API Fingerprint matching
iOS (Native/Flutter) Pasteboard (if enabled in Portal) Fingerprint matching
iOS (React Native) Pasteboard (with expo-clipboard) Fingerprint matching

:::note SDK Support

  • Native iOS SDK & Flutter: Full pasteboard support (automatic)
  • React Native: Install expo-clipboard to enable pasteboard support, otherwise uses fingerprint matching :::

Architecture

<MermaidChart chart={` flowchart TB click["User clicks https://link.app/promo"] edge["li-nk.me Edge Server1. Create click_token (cid)2. Hash IP + UA for fingerprint3. Redirect to App/Play Store"] click --> edge

subgraph Android
    storeA["Play Store redirect<br/>referrer=cid=xxx"]
    installA["User installs app"]
    launchA["First launch<br/>1. SDK reads Install Referrer<br/>2. If cid: GET /api/deeplink?cid=xxx<br/>3. Else: POST /api/deferred/claim"]
end

subgraph iOS
    storeI["App Store redirect<br/>Pasteboard write if enabled"]
    installI["User installs app"]
    launchI["First launch<br/>1. SDK reads pasteboard (if enabled)<br/>2. If cid missing: POST /api/deferred/claim"]
end

edge --> storeA
edge --> storeI
storeA --> installA --> launchA
storeI --> installI --> launchI

payload["Payload returned to app<br/>{ linkId, path, params, utm, custom }"]
launchA --> payload
launchI --> payload

`} />

Implementation

Android uses the Play Install Referrer API as the primary mechanism. When li-nk.me redirects to the Play Store, it embeds the click token (cid) in the referrer parameter:

https://play.google.com/store/apps/details?id=com.app&referrer=cid%3Dxxx

After installation, the SDK reads this referrer and claims the payload directly.

// In your Application or first Activity
LinkMe.shared.configure(context, config)

// Check for initial link from direct open
LinkMe.shared.getInitialLink { payload ->
    if (payload != null) {
        // App opened via direct link
        routeUser(payload)
    } else {
        // No direct link — check for deferred (first install)
        LinkMe.shared.claimDeferredIfAvailable(context) { deferred ->
            if (deferred != null) {
                // First install from a link!
                routeUser(deferred)
            }
        }
    }
}

Dependencies required:

implementation("com.android.installreferrer:installreferrer:2.2")

iOS uses pasteboard (when enabled in Portal) or fingerprint matching for deferred deep linking.

When pasteboard is enabled in the Portal (App Settings → iOS → "Enable Pasteboard for Deferred Links"):

  1. The redirect page writes a URL containing the cid to the system pasteboard
  2. After installation, the SDK checks the pasteboard for a li-nk.me URL
  3. If found, it claims the payload directly via the cid
  4. If not found, falls back to fingerprint matching

App settings screen with the deferred deep linking toggle enabled

Toggle pasteboard support inside the App Settings view before shipping so new installs can recover their click tokens without relying solely on fingerprint matching.

// In your App init
LinkMe.shared.configure(config: .init(
    baseUrl: baseUrl,
    appId: appId,
    appKey: appKey
))

// Check for initial link from direct Universal Link open
LinkMe.shared.getInitialLink { payload in
    if let p = payload {
        // App opened via direct Universal Link
        routeUser(p)
    } else {
        // No direct link — check for deferred (first install)
        // SDK automatically checks pasteboard first (if enabled), then fingerprint
        LinkMe.shared.claimDeferredIfAvailable { deferred in
            if let d = deferred {
                // First install from a link!
                routeUser(d)
            }
        }
    }
}
# Required
npm install @li-nk.me/react-native-sdk

# Optional but recommended: enables pasteboard support on iOS
npx expo install expo-clipboard

Package: @li-nk.me/react-native-sdk

import {
    configure,
    getInitialLink,
    claimDeferredIfAvailable,
} from '@li-nk.me/react-native-sdk';

await configure({ baseUrl, appId, appKey });

const initial = await getInitialLink();
if (initial?.path) {
    routeUser(initial);
} else {
    // No direct link — check for deferred (first install)
    // On iOS: checks pasteboard first (if expo-clipboard installed), then fingerprint
    // On Android: uses fingerprint matching (Install Referrer not available in JS)
    const deferred = await claimDeferredIfAvailable();
    if (deferred?.path) {
        routeUser(deferred);
    }
}

:::tip iOS Pasteboard When expo-clipboard is installed, the SDK automatically checks the iOS pasteboard for a li-nk.me URL before falling back to fingerprint matching. This requires pasteboard to be enabled in the Portal (App Settings → iOS). :::

final linkme = LinkMe();
await linkme.configure(config);

final initial = await linkme.getInitialLink();
if (initial != null) {
    routeUser(initial);
} else {
    // No direct link — check for deferred (first install)
    final deferred = await linkme.claimDeferredIfAvailable();
    if (deferred != null) {
        routeUser(deferred);
    }
}

Best Practices

1. Always Check Both

The recommended pattern is:

  1. Check getInitialLink() first (handles direct opens)
  2. If null, call claimDeferredIfAvailable() (handles first installs)

This ensures you catch both scenarios.

2. Call Only on First Launch

Deferred claim should only be called on the first app launch after installation. Subsequent launches should skip it:

val prefs = getSharedPreferences("linkme", MODE_PRIVATE)
if (!prefs.getBoolean("deferred_checked", false)) {
    prefs.edit().putBoolean("deferred_checked", true).apply()
    LinkMe.shared.claimDeferredIfAvailable(context) { /* ... */ }
}

3. Handle Duplicates

The API returns a duplicate flag when the same fingerprint has already claimed a link. Use this to avoid re-routing users who have already been attributed.

4. Time Window

Fingerprint matches are valid for 72 hours by default. Links clicked more than 72 hours before installation cannot be matched via fingerprinting.

Fingerprint Matching Accuracy

Fingerprint matching uses IP address + User-Agent hash. While not 100% accurate, it provides a good balance:

Scenario Accuracy
Same network, same device High
Same network, different device False positive possible
Different network (VPN, carrier change) Will not match
Shared public IP (office, school) False positive possible

Note: Android Install Referrer is deterministic and does not have these limitations.

Pasteboard Flow (iOS)

Pasteboard is controlled from the Portal (not SDK config):

  1. Enable in Portal: App Settings → iOS → "Enable Pasteboard for Deferred Links"
  2. When enabled, the redirect page writes a URL containing the cid to the system pasteboard
  3. After installation, the SDK automatically checks the pasteboard for a li-nk.me URL
  4. If found, it extracts the cid and claims the payload directly (more reliable than fingerprint)
  5. If not found, falls back to fingerprint matching

Considerations:

  • iOS 14+ prompts users when an app reads the pasteboard ("app has pasted from...")
  • This prompt appears the first time the app reads the pasteboard
  • The SDK only reads pasteboard URLs that match the li-nk.me domain format
  • Enable this if fingerprint matching accuracy is insufficient for your use case

Claim Types

The claim response includes a claim_type field indicating how the link was matched:

Type Description
direct Claimed via cid from Install Referrer or pasteboard
install_referrer Claimed via Android Play Install Referrer
probabilistic Claimed via fingerprint matching
pasteboard Claimed via iOS pasteboard read

Troubleshooting

Android: Install Referrer Not Working

  1. Ensure com.android.installreferrer:installreferrer dependency is added
  2. Test with an actual Play Store install (sideloading won't work)
  3. Check if the referrer parameter is being passed in the Play Store URL

iOS: Fingerprint Not Matching

  1. Verify the app launch happens on the same network as the click
  2. Check if the click is within the 72-hour window
  3. User-Agent must match (same browser/device)

General: No Payload Returned

  1. Verify the link was created in li-nk.me (not just a random URL)
  2. Check that the link's app has valid configuration
  3. Ensure API credentials (appId, appKey) are correct