adjust-icon

Set up deferred deep linking

Deferred deep linking allows users who don’t have your app installed to click an Adjust link, install your app from the store, and then be directed to their intended content when they first open the app.

How it works

This is the basic flow of deferred deep linking:

  1. The user clicks on an Adjust deep link.
  2. Adjust’s servers redirect the user to the app store.
  3. The user installs your app and opens it.
  4. The SDK sends session and attribution requests to Adjust’s servers. Adjust returns the deferred deep link on the session response if ODDL is enabled and the install is eligible. Otherwise, Adjust returns the deep link on the attribution response.
  5. If applicable, your app displays its initial screens, such as onboarding screens and user login.
  6. Your app receives the deferred deep link through the callback you configure. Your app then handles this link to direct the user to the appropriate screen.

When a user clicks an Adjust branded link (brandname.go.link) and the link is deferred, Adjust’s servers convert it to app scheme format (example://), using the app scheme configured in the platform settings in the Adjust dashboard, before passing it to the Adjust SDK.

Setup

  1. Create an AdjustConfig object.
  2. Set a deferred deep link callback on the AdjustConfig object. The Adjust SDK calls this callback after receiving a deferred deep link.
  3. Set the launchDeferredDeeplink property to control whether the SDK opens the deep link automatically.
  4. Initialize the SDK.
AdjustConfig adjustConfig = new AdjustConfig('{YourAppToken}', AdjustEnvironment.sandbox);
adjustConfig.deferredDeeplinkCallback = (String? uri) {
/*
* TODO: Store deep link or handle it immediately
*
* deeplink format:
*
* example://summer-clothes?promo=beach&adj_t=abc123
*/
};
adjustConfig.launchDeferredDeeplink = false; // or true based on your use case (see below)
Adjust.start(adjustConfig);

The launchDeferredDeeplink property determines what happens after your callback code executes:

Set to false (most common)

Use this approach if you want your app to have complete control over when and how to process the deferred deep link. By setting this to false, the Adjust SDK will not attempt to open the deferred deep link. For example, this approach is appropriate if your app needs to show and move past initial screens (like onboarding or login) before handling the deferred deep link.

Set to true (default)

Use this approach if you want the Adjust SDK to attempt to open the deferred deep link immediately after the callback code runs. For example, this approach is appropriate if your app does not have any initial screens.

When the Adjust SDK receives the deferred deep link, your callback code runs, and then the Adjust SDK opens the deep link URL using native OS methods (application(_:open:options:) on iOS, startActivity(Intent) on Android). The OS then delivers the link to your app_links uriLinkStream listener.

Full code example

This example shows how an app with an onboarding process handles deferred deep links. Here is a summary of the app’s internal flow:

  1. The user opens the app for the first time.
  2. The app begins its onboarding process.
  3. The app’s callback receives the deferred deep link from the Adjust SDK and then checks if onboarding is complete:
    • If complete, it handles the deep link immediately.
    • If not complete, it stores the deep link.
  4. Once onboarding finishes, the app checks for and handles any stored deferred deep link.
  5. The app navigates the user to the deep link screen.
import 'package:adjust_sdk/adjust.dart';
import 'package:adjust_sdk/adjust_config.dart';
import 'package:flutter/foundation.dart';
String? _pendingDeeplink;
void initAdjust() {
// Configure Adjust SDK
// Replace {YourAppToken} with your Adjust app token
const appToken = '{YourAppToken}';
AdjustConfig? adjustConfig;
// Enable verbose logging for deep link testing
if (kDebugMode) {
adjustConfig = AdjustConfig(appToken, AdjustEnvironment.sandbox);
adjustConfig.logLevel = AdjustLogLevel.verbose;
} else {
adjustConfig = AdjustConfig(appToken, AdjustEnvironment.production);
adjustConfig.logLevel = AdjustLogLevel.suppress;
}
// Disable automatic opening so we can handle it manually
adjustConfig.launchDeferredDeeplink = false;
// Set up deferred deep link callback
adjustConfig.deferredDeeplinkCallback = (String? uri) {
if (uri == null) return;
if (hasCompletedOnboarding) {
// If onboarding is complete, handle deferred deep link immediately
// TODO: Handle the deferred deep link by parsing the path and
// navigating to the appropriate screen.
} else {
// Store deferred deep link to handle after onboarding
_pendingDeeplink = uri;
}
};
// Initialize Adjust SDK
Adjust.start(adjustConfig);
}
// When onboarding completes:
void onOnboardingComplete() {
if (_pendingDeeplink != null) {
// TODO: Handle the deferred deep link by parsing the path and
// navigating to the appropriate screen.
_pendingDeeplink = null;
}
}