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:
- App is installed → Universal Link / App Link opens the app directly with the full payload
- 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-clipboardto 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"):
- The redirect page writes a URL containing the
cidto the system pasteboard - After installation, the SDK checks the pasteboard for a li-nk.me URL
- If found, it claims the payload directly via the
cid - If not found, falls back to fingerprint matching

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:
- Check
getInitialLink()first (handles direct opens) - 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):
- Enable in Portal: App Settings → iOS → "Enable Pasteboard for Deferred Links"
- When enabled, the redirect page writes a URL containing the
cidto the system pasteboard - After installation, the SDK automatically checks the pasteboard for a li-nk.me URL
- If found, it extracts the
cidand claims the payload directly (more reliable than fingerprint) - 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
- Ensure
com.android.installreferrer:installreferrerdependency is added - Test with an actual Play Store install (sideloading won't work)
- Check if the referrer parameter is being passed in the Play Store URL
iOS: Fingerprint Not Matching
- Verify the app launch happens on the same network as the click
- Check if the click is within the 72-hour window
- User-Agent must match (same browser/device)
General: No Payload Returned
- Verify the link was created in li-nk.me (not just a random URL)
- Check that the link's app has valid configuration
- Ensure API credentials (appId, appKey) are correct