Configure Deeplinks (SDK part)
Overview
Deferred Deeplinking lets you attribute users who install and open the app after clicking an Apphud deep link. The SDK supports two attribution flows:
- Direct deeplinking — the app is opened from a Universal Link / App Link or custom scheme, and the SDK sends the opened URL to Apphud.
- Deferred deeplinking — the app requests attribution for the current installation after the first launch, even when the app was installed before the link could be opened directly.
Use this guide after the Apphud SDK is installed and initialized. See Initialization and Identification if you have not initialized the SDK yet.
Platform setup requiredApphud receives the attribution result through the SDK, but your app must still be configured to open links on each platform:
- iOS: configure Universal Links using Apple's guide: Supporting universal links in your app
- Android: configure Android App Links using Google's guide: Android App Links
Requirements
- Use an Apphud SDK version that includes Deferred Deeplinking support.
- Configure Universal Links on iOS and/or Android App Links on Android for your domain.
- Register a deeplink handler in Apphud SDK to receive attribution results.
- Forward incoming links to Apphud SDK from your app lifecycle callbacks.
- Request deferred attribution after SDK initialization, typically once on the first launch after install.
ImportantThe deeplink handler may be called multiple times during the app lifecycle: for direct link opens and for deferred attribution requests. If Apphud does not find a match, the handler receives an empty attribution dictionary/map.
Attribution Result
The deeplink handler receives:
attribution— attribution data returned by Apphud. It is empty when no match is found.kind— attribution kind:direct/DIRECT: the user opened an actual deep link.deferred/DEFERRED: attribution was resolved for the current installation.
url/uri— the original link for direct deeplinking, ornil/nullfor deferred deeplinking.
iOS
1. Configure Universal Links
Configure Associated Domains in Xcode and host the apple-app-site-association file for your link domain. Follow Apple's official guide: Supporting universal links in your app.
2. Add a deeplink handler during initialization
import ApphudSDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Apphud.start(apiKey: "YOUR_API_KEY", deeplinkHandler: { attribution, kind, url in
switch kind {
case .direct:
print("Direct deeplink attribution", url?.absoluteString ?? "", attribution)
case .deferred:
print("Deferred deeplink attribution", attribution)
}
// Use attribution values here, for example to route the user,
// unlock onboarding content, or store campaign parameters.
})
// Handles direct links that launched the app.
Apphud.handleLaunchOptions(launchOptions: launchOptions)
return true
}
}You can also set or replace the handler after initialization:
Apphud.setDeeplinkHandler { attribution, kind, url in
print("Deeplink attribution", kind, url?.absoluteString ?? "", attribution)
}3. Forward direct deep links to Apphud
For custom scheme links or links delivered through application(_:open:options:):
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
Apphud.handleOpen(url: url)
return true
}For Universal Links:
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
Apphud.continueUserActivity(userActivity)
return true
}4. Request deferred attribution
Call this after Apphud SDK initialization, typically once on the first launch after install:
if isFirstLaunchAfterInstall {
Apphud.requestDeferredDeeplinkAttribution()
}The result is delivered to the same deeplinkHandler with kind == .deferred and url == nil.
NoteDeferred attribution uses a temporary hidden web view to resolve the visitor identifier. Direct Universal Link attribution should still be configured and forwarded separately as shown above.
Android
1. Configure Android App Links
Add an ACTION_VIEW intent filter to the Activity that should receive your links and host the Digital Asset Links file for your domain. Follow Google's official guide: Android App Links.
Example AndroidManifest.xml:
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop">
<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="/deeplink" />
</intent-filter>
</activity>Replace example.com and /deeplink with your actual link domain and path.
2. Add a deeplink handler during initialization
import android.app.Application
import android.util.Log
import com.apphud.sdk.Apphud
import com.apphud.sdk.ApphudDeeplinkAttributionKind
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Apphud.start(
context = this,
apiKey = "YOUR_API_KEY",
deeplinkHandler = { attribution, kind, uri ->
when (kind) {
ApphudDeeplinkAttributionKind.DIRECT -> {
Log.d("Apphud", "Direct deeplink: uri=$uri attribution=$attribution")
}
ApphudDeeplinkAttributionKind.DEFERRED -> {
Log.d("Apphud", "Deferred deeplink: attribution=$attribution")
}
}
// Use attribution values here, for example to route the user,
// unlock onboarding content, or store campaign parameters.
},
)
}
}You can also set or replace the handler after initialization:
Apphud.setDeeplinkHandler { attribution, kind, uri ->
Log.d("Apphud", "Deeplink attribution: kind=$kind uri=$uri attribution=$attribution")
}3. Forward direct deep links to Apphud
Forward the Activity intent from both onCreate and onNewIntent:
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.apphud.sdk.Apphud
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Apphud.handleIntent(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
Apphud.handleIntent(intent)
}
}Apphud.handleIntent(intent) processes only ACTION_VIEW intents with a link URI. You can also pass a URI directly:
Apphud.handleUri(uri)4. Request deferred attribution
Call this from a visible Activity after Apphud SDK initialization, typically once on the first launch after install:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Apphud.handleIntent(intent)
if (isFirstLaunchAfterInstall()) {
Apphud.requestDeferredDeeplinkAttribution(this)
}
}
}The result is delivered to the same deeplinkHandler with kind == ApphudDeeplinkAttributionKind.DEFERRED and uri == null.
NoteDeferred attribution on Android uses a temporary 1x1 WebView attached to the provided Activity to resolve the visitor identifier. Call it from a started, visible Activity rather than from
Application.onCreate().
Testing
- Install a build with the Apphud SDK version that supports Deferred Deeplinking.
- Verify that Universal Links / App Links open the app directly.
- Open a direct link and confirm that the handler receives
direct/DIRECTattribution with the original URL. - For deferred deeplinking, click the link before installing the app, install and open the app, then call the deferred attribution request once after initialization.
- Confirm that the handler receives
deferred/DEFERREDattribution. If there is no match, the attribution payload will be empty.
Troubleshooting
- If direct links do not open the app, verify Universal Links / App Links configuration first:
- iOS: Bundle Identifier, Associated Domains entitlement must match with
apple-app-site-associationon record. - Android: intent filter, package name, signing certificate fingerprint must match with
assetlinks.json
- iOS: Bundle Identifier, Associated Domains entitlement must match with
- Make sure Apphud SDK is initialized before requesting deferred attribution.
- Make sure incoming links are forwarded to Apphud from all relevant lifecycle callbacks.
- Do not assume the handler is called only once; handle both direct and deferred results idempotently.
- An empty attribution payload means Apphud did not find a matching attribution for that request.
