Blog›Engineering
Engineering

How to set up deferred deep linking on iOS

iOS has no install referrer, so deferred deep links need another way through the App Store. Associated Domains, the SDK, the click token, and testing.

AAAhsan AliWrites about deep linking & attributionSep 27, 2026·4 min read
Diagram: configure the iOS SDK and handle the deep link, so the first open after install lands on the right screen with its path and custom data.

A user taps your link, doesn't have your app, installs it from the App Store — and the first open lands on the product, invite or offer the link was about. That's deferred deep linking, and on iOS it takes more setup than on Android, because the App Store passes nothing from the tap to the first launch.

This guide covers the whole path on iOS with LinkTrail's SDK: the domain setup, the code, how the click survives the install, and how to test it without fooling yourself.

Why is deferred deep linking harder on iOS?

On Android, Google Play hands the app a referrer string through the Install Referrer API, so the first launch can be matched to the click exactly. iOS has no equivalent: the App Store doesn't forward anything from the link to the app.

That leaves a few options. The advertising identifier needs the user's permission under App Tracking Transparency and LinkTrail doesn't use it. Comparing device characteristics is fingerprinting, which needs consent and which Apple restricts. What LinkTrail uses first is a click token: the tapped link leaves a short token on the clipboard, and the app reads it back on first launch. Probabilistic matching exists as an optional, consent-gated fallback — the methodology page documents exactly what it compares.

What do you need before you start?

  • Your app registered in the LinkTrail dashboard (Apps → Register app), with its Apple Team ID and bundle ID.
  • A link domain — your free *.linktrail.io subdomain or a custom domain. LinkTrail generates and hosts the apple-app-site-association file for it.
  • An API key (Settings → API Keys).
  • A device running iOS 16 or later for the paste control, which is the default way the click token is read.

Step 1: Add Associated Domains

In Xcode, add the Associated Domains capability to your app target and list your link domain. This is what lets iOS open your app, instead of Safari, when someone taps a link on that domain:

applinks:yourapp.linktrail.io

While developing, adding ?mode=developer to that entry makes a device with Associated Domains Development switched on fetch the file from the server directly instead of through Apple's CDN. Remove it before release.

Add the SDK with Swift Package Manager or CocoaPods — the iOS SDK page has both. Then configure it at launch and register one handler. The same onLink callback fires for deferred links on first launch and for links opened while the app is installed:

import LinkTrailSDK

// At launch — SwiftUI App.init or AppDelegate. configure throws on a missing key.
try LinkTrail.configure(apiKey: "lt_live_...")

LinkTrail.shared?.onLink { link, source in
    // source says whether this is a deferred (first-launch) or re-engagement link
    router.route(to: link.path, customData: link.customData)
}

LinkTrail.shared?.onError { error in
    // An invalid key arrives here, not from configure — log it while testing
}

When the app is already installed, iOS delivers the tapped URL to your app, and you pass it to the SDK. In SwiftUI:

.onOpenURL { LinkTrail.shared?.handleDeepLink($0) }
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in
    if let url = activity.webpageURL { LinkTrail.shared?.handleDeepLink(url) }
}

With UIKit, do the same from your SceneDelegate's scene(_:continue:) and scene(_:openURLContexts:). handleDeepLink returns false for URLs that aren't LinkTrail links, so your own routing can take over.

Step 4: Recover the click on first launch

This is the step that makes the deferred path work on iOS, and the one most often missed. By default, the SDK reads the click token only when the user taps a paste control — Apple's UIPasteControl, which the SDK wraps as LinkTrailPasteButton. The tap is the user's permission, so iOS shows no 'Allow Paste' alert.

import LinkTrailSDK
import SwiftUI

// The install waits for the tap, so don't track it automatically.
try LinkTrail.configure(
    apiKey: "lt_live_...",
    options: LinkTrailOptions(autoTrackInstall: false,
                              clickTokenSource: .pasteButton)
)

// On your first-launch screen:
if #available(iOS 16.0, *) {
    LinkTrailPasteButton()
}

Once the user taps it, the SDK reads the token, tracks the install, and onLink delivers the destination. You can choose how the token is read:

clickTokenSourceWhat happensTrade-off
.pasteButton (default)The token is read when the user taps the paste controlNo system alert, but it needs the control on screen and autoTrackInstall: false
.automaticThe SDK reads the clipboard itself at first launchNo UI to build, but iOS shows the 'Allow Paste' alert
.noneThe clipboard is never readNo alert and no UI; deferred matching falls back to probabilistic only

Put the paste control where it makes sense to the user — a 'Continue where you left off' step on the first screen works well. UIPasteControl needs iOS 16; on iOS 15, use .automatic or .none.

Consent gating is on by default. On iOS, links route immediately and attribution waits: call setConsent(true) once your consent prompt is answered, and the install is attributed without re-routing a user who's already on their screen. Routing a user to the right screen doesn't need the advertising identifier, so none of this depends on App Tracking Transparency.

LinkTrail.shared?.setConsent(true)   // attributes the install, flushes queued events
LinkTrail.shared?.setConsent(false)  // revoke at any time

How do you test it?

  1. 1Delete the app from the test device.
  2. 2Put your link in Notes and tap it — don't paste it into Safari's address bar, which never opens an app.
  3. 3Install the build you're testing and open it.
  4. 4Tap the paste control on the first screen. The app should land on the linked screen.

To repeat the test without reinstalling, call LinkTrail.resetForTesting() in debug builds: it clears the install flag, cached attribution and device ID, so the next launch behaves like a first launch. Guard it with #if DEBUG — it must not ship.

Why isn't it working?

  • Links open Safari instead of the app. The AASA file or the Associated Domains entry is wrong — run your domain through the Universal Links validator, and check the entry matches the link domain exactly.
  • New installs open on the home screen. The paste control isn't rendered, or autoTrackInstall is still on with .pasteButton. Deferred installs then arrive unmatched.
  • It works from Notes but not from Instagram. That's an in-app browser that never hands the URL to iOS; the fallback page has to route onward. One link for every channel covers in-app browsers.
  • Nothing happens at all. An invalid API key fails silently in configure and arrives through onError — keep that handler logging while you test.

Setting up Android as well? The deferred path there runs through the Play Install Referrer instead — see the Android SDK guide.

AA

Ahsan Ali

Writes about deep linking & attribution

Ahsan Ali works with the teams integrating LinkTrail's iOS, Android, React Native, and Flutter SDKs, which is where most of what he writes here starts: deferred deep linking, install attribution after ATT, and the parts of the mobile growth stack the category tends to leave vague.

Tagged#Deferred deep linking#iOS#Universal Links#Swift

Questions about this post

How does deferred deep linking work on iOS?

The tapped link records the click and its destination, then sends the user to the App Store. iOS passes nothing through the install, so LinkTrail leaves a click token on the clipboard and the SDK recovers it on first launch — by default when the user taps a paste control — then delivers the destination to your onLink handler.

Why does iOS show an 'Allow Paste' alert?

Because the app read the clipboard without the user asking. LinkTrail's default avoids the alert by reading the click token only when the user taps a paste control, which counts as consent. Choosing the automatic mode reads the clipboard directly and shows the alert.

Do I need App Tracking Transparency for deferred deep linking?

No. Routing a user to the right screen doesn't use the advertising identifier, and LinkTrail never reads it. ATT only matters if you want the IDFA for something else.