Adjust Migration
Migrate from Adjust to WarpLink: tracker and parameter mapping, SDK swap, and deep linking, install attribution, and analytics.
This guide is for teams moving from Adjust (Adjust Link / TrueLink) to WarpLink: mapping trackers and link parameters, swapping the SDK, and carrying deep linking, install attribution, and analytics over to WarpLink. It assumes a WarpLink account and app are already set up.
For the provider-agnostic playbook (planning, domains, cutover, decommissioning), see the general migration guide. This page covers only what is specific to leaving Adjust.
Concept Mapping
| Adjust | WarpLink |
|---|---|
| Tracker (Adjust Link / TrueLink) | Link |
| Adjust dashboard | WarpLink dashboard |
adj.st subdomain or *.go.link branded domain | aplnk.to domain |
| Enterprise Domain | Custom domain |
AdjustDelegate deferred deep link callback | onLink callback |
Tracker URL parameters (deep_link, redirect, label, ...) | Link fields |
| Datascape reporting | Built-in click analytics |
| SKAdNetwork postbacks, Fraud Prevention Suite, Audience Builder | Not replaced by WarpLink; see Attribution and Reporting |
1. Export Your Links
Tracker list via API. Adjust's Campaign API includes an endpoint that lists trackers for a given app, with cursor-based pagination, so you can pull your tracker list and their parameters programmatically.
Raw click and event data. Adjust exports raw and historical data two ways: real-time server callbacks to your own servers or BI system, or hourly CSV uploads to a customer-owned cloud storage bucket (S3, GCS, or similar), configured under Dashboard > App settings > All Settings > Raw Data Exports > CSV Upload.
Dashboard export. Adjust's Datascape reporting UI lets you filter, visualize, and export reports directly from the dashboard.
2. Recreate Your Links
Recreate each Adjust tracker as a link in WarpLink via the dashboard or the REST API.
Parameter Mapping
| Adjust Parameter | WarpLink Field |
|---|---|
deep_link (direct in-app route, supersedes every other redirect parameter) | ios_url / android_url |
redirect (override destination) | destination_url |
redirect_ios / redirect_android (platform-specific redirect override) | ios_fallback_url / android_fallback_url |
fallback (redirect for an unsupported OS) | destination_url |
label (free-form passthrough attached to raw data exports) | tags |
adj_campaign (short-link append parameter) | utm_campaign |
label does not map to a literal WarpLink field: it is Adjust's free-form export passthrough, and the closest WarpLink equivalent is tags, which organizes links internally rather than attaching to each exported click. Also note that on Adjust short links (adj.st/go.link URLs already created), the adj_redirect and adj_fallback query parameters are recognized names but cannot override that short link's destination or fallback, for security reasons. Only tracker-level redirect and fallback control where a link sends a user.
Adjust's adj_adgroup and adj_creative append parameters have no direct WarpLink field. Fold anything you still need into destination_url query parameters.
Create via API
curl -X POST https://api.warplink.app/v1/links \
-H "Authorization: Bearer wl_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"destination_url": "https://yourapp.com/product/123",
"ios_url": "myapp://product/123",
"android_url": "myapp://product/123",
"utm_campaign": "spring_sale"
}'
3. Swap the SDK
Remove Adjust:
- Remove the
AdjustCocoaPods pod (pod 'Adjust', '~> 4.38.4') or the SPM package fromhttps://github.com/adjust/ios_sdk(productAdjustSdk) - Remove
ADJConfig(appToken:environment:)and theAdjust.initSdk(_:)call - Remove the
AdjustDelegateconformance andadjustDeferredDeeplinkReceived(_:) - Remove the deep link forwarding calls that exist solely to reach Adjust:
application(_:continue:restorationHandler:),application(_:open:options:),scene(_:willConnectTo:options:),scene(_:continue:),scene(_:openURLContexts:), or SwiftUI's.onOpenURL
Add WarpLink:
// Package.swift
dependencies: [
.package(url: "https://github.com/WarpLinkApp/warplink-ios-sdk", from: "1.1.0")
]Remove Adjust:
// Remove from build.gradle.kts
// implementation("com.adjust.sdk:adjust-android:5.8.0")
// implementation("com.android.installreferrer:installreferrer:<version>")
// implementation("com.google.android.gms:play-services-ads-identifier:<version>")Also remove the AdjustConfig(context, appToken, environment) / Adjust.initSdk(config) calls and any Adjust.processDeeplink(...) or Adjust.processAndResolveDeeplink(...) calls in your Activity.
Add WarpLink:
dependencies {
implementation("app.warplink:sdk:1.1.0")
}Remove Adjust:
npm uninstall react-native-adjustAdd WarpLink:
npm install @warplink/react-nativeThe iOS SDK is distributed through Swift Package Manager and needs dynamic linkage, so add this to ios/Podfile inside your app target before installing pods:
# ios/Podfile, inside your app target
use_frameworks! :linkage => :dynamiccd ios && pod install4. Update SDK Initialization
Mobile apps authenticate with an SDK key, created in the dashboard under API Keys > SDK key. An API key looks identical but cannot record installs, so pasting one here leaves deep links working while attribution silently fails.
Before (Adjust):
import AdjustSdk
let adjustConfig = ADJConfig(appToken: "{YourAppToken}", environment: ADJEnvironmentProduction)
Adjust.initSdk(adjustConfig)After (WarpLink):
import WarpLink
WarpLink.configure(
apiKey: "wl_live_yoursdkkeyhere000000000000000000",
options: WarpLinkOptions(onLink: { result in
if case .success(let link) = result, let link {
navigate(to: link) // taps AND deferred installs (check link.isDeferred)
}
})
)Before (Adjust):
import com.adjust.sdk.Adjust
import com.adjust.sdk.AdjustConfig
val config = AdjustConfig(this, "{YourAppToken}", AdjustConfig.ENVIRONMENT_PRODUCTION)
Adjust.initSdk(config)After (WarpLink):
import app.warplink.WarpLink
import app.warplink.WarpLinkOptions
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
WarpLink.configure(
context = this,
apiKey = "wl_live_yoursdkkeyhere000000000000000000",
options = WarpLinkOptions(onLink = { result ->
result.onSuccess { link -> navigateTo(link) }
})
)
}
}Before (Adjust):
import { Adjust, AdjustConfig } from 'react-native-adjust';
const adjustConfig = new AdjustConfig('{YourAppToken}', AdjustConfig.EnvironmentProduction);
Adjust.initSdk(adjustConfig);After (WarpLink):
import { WarpLink } from '@warplink/react-native';
WarpLink.configure({
apiKey: 'wl_live_yoursdkkeyhere000000000000000000',
onLink: ({ deepLink }) => deepLink && navigateTo(deepLink.destination),
});5. Update Domain Configuration
In Signing & Capabilities > Associated Domains:
- applinks:f2k5.adj.st
+ applinks:aplnk.toIn AndroidManifest.xml, update the intent filter host:
<data
android:scheme="https"
- android:host="f2k5.adj.st" />
+ android:host="aplnk.to" />adj.st and branded *.go.link domains are Adjust-owned. The branded domain name cannot be changed once saved, and neither domain can be repointed to another provider, so migrating off either means standing up a new domain on WarpLink and updating every published link. An Enterprise Domain is different: it is your own subdomain, wired to Adjust with an A record in your own DNS. Adjust's own configuration for that domain cannot be changed without contacting Adjust support, but the DNS record itself is yours, so once your links exist on WarpLink you can replace that record (delete Adjust's A record and add WarpLink's CNAME) and keep the domain and its already-distributed links intact. See custom domains.
Keep your existing Adjust Associated Domains and App Links entries in place alongside the new WarpLink ones during the transition, the same approach Adjust itself recommends when adding a new branded domain. This keeps links already distributed (emails, ads, social bios, QR codes) resolving on-device while you cut over.
If Android App Links fail to verify after cutover, the most common causes are a signing-key fingerprint mismatch between assetlinks.json and the APK's actual signature (especially with Play App Signing re-signing), a missing android:autoVerify="true", or assetlinks.json being served via a redirect instead of a direct response.
Moving to a custom domain? Declare it to the SDK too: linkDomains at configure(), or the WarpLinkDomains plist key / app.warplink.DOMAINS manifest entry. See Use it in your app.
6. Migrate Deep Link Handling
The onLink callback set in step 4 already receives resolved links for cold start, warm start, and deferred installs.
Delete the Adjust.processAndResolveDeeplink(_:withCompletionHandler:) (or legacy Adjust.processDeeplink(_:)) call and the ADJDeeplink construction around it. Forward the incoming activity to WarpLink (or set your scene delegate class to WarpLinkSceneDelegate):
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
WarpLink.continue(userActivity)
}Resolved links arrive in your onLink callback.
Delete the Adjust.processDeeplink(AdjustDeeplink, Context) (or Adjust.processAndResolveDeeplink(...)) call from onCreate / onNewIntent. Cold start is automatic. For warm start, forward new intents and set android:launchMode="singleTask" on the Activity:
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
WarpLink.onNewIntent(intent)
}Resolved links arrive in your onLink callback.
Delete the Adjust.processDeeplink(...) calls from your Linking listeners. Cold and warm start flow into onLink automatically.
On iOS you are removing the Adjust call from a delegate method that already exists and already forwards to your linking library. Swap the Adjust line for the WarpLink call and leave the rest of the method alone. Do not let handleIncomingURL decide the return value: it returns nothing, and replacing the forwarded result breaks React Navigation, Expo Linking, and OAuth callbacks.
// ios/YourApp/AppDelegate.swift
import React
import warplink_react_native
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL {
WarpLinkModule.handleIncomingURL(url) // was Adjust.processDeeplink(...)
}
return RCTLinkingManager.application(
application, continue: userActivity, restorationHandler: restorationHandler)
}Android needs no host code, given android:launchMode="singleTask". See the React Native SDK guide for the Objective-C form and Expo prebuild, and the iOS SceneDelegate hook if your app has a SceneDelegate (Info.plist declares UIApplicationSceneManifest): iOS stops calling the AppDelegate method above once a scene exists.
7. Migrate Deferred Deep Links
WarpLink runs the deferred deep link check automatically from configure(). The match arrives in the same onLink callback, flagged with isDeferred. There is no separate deferred call to port.
Adjust's deferred delivery runs through the AdjustDelegate protocol's adjustDeferredDeeplinkReceived(_ deeplink: URL?) -> Bool method on iOS, registered via adjustConfig.delegate before Adjust.initSdk(...), and through setDeferredDeeplinkCallback on AdjustConfig in React Native. Delete those; WarpLink's onLink replaces both. On Android, remove whatever deferred handling code you added alongside the SDK itself in step 3.
Handle the deferred case inside your onLink callback:
options: WarpLinkOptions(onLink: { result in
guard case .success(let deepLink) = result, let deepLink else { return }
if deepLink.isDeferred {
print("Match confidence: \(deepLink.matchConfidence ?? 0)")
}
navigate(to: deepLink)
})Handle the deferred case inside your onLink callback:
options = WarpLinkOptions(onLink = { result ->
result.onSuccess { deepLink ->
if (deepLink.isDeferred) {
Log.d("MyApp", "Match confidence: ${deepLink.matchConfidence}")
}
navigateTo(deepLink)
}
})Handle the deferred case inside your onLink callback:
WarpLink.configure({
apiKey: 'wl_live_yoursdkkeyhere000000000000000000',
onLink: ({ deepLink }) => {
if (!deepLink) return;
if (deepLink.isDeferred) console.log('Match confidence:', deepLink.matchConfidence);
navigateTo(deepLink.destination);
},
});To run the check manually instead, set the deferred opt-out flag and call checkDeferredDeepLink() yourself (see the deferred deep links guides).
8. Attribution and Reporting
WarpLink attributes installs to the link that drove them through a match cascade: a referrer signal (Play Install Referrer) on Android, a device ID (IDFV) on iOS, and an enriched fingerprint as a probabilistic fallback on both platforms, with a confidence score on every result. See the iOS attribution guide (or the Android and React Native equivalents) for match types, confidence bands, and privacy details.
WarpLink does not replace Adjust as a mobile measurement partner for paid ad network postbacks: Adjust ingests SKAdNetwork conversion-value payloads and enriches them with campaign metadata for named ad-network partners, runs a Fraud Prevention Suite (an anonymous-IP filter, a click-injection filter, and click-to-install-time distribution modeling), and offers in-dashboard audience segmentation with retargeting sync to ad networks. If Adjust also serves as your measurement partner for paid campaigns or fraud filtering, keep that integration in place alongside WarpLink.
If you run Adjust and WarpLink side by side during the transition, avoid registering both SDKs for the same URL scheme or Associated Domains entry. Running two attribution SDKs against the same domain risks double-counting installs or conflicting deep link handling; stagger the cutover by app version rather than leaving both SDKs live indefinitely.
Beyond that, running both SDKs for a period is a normal part of a migration: it lets you compare install counts and deep link behavior before retiring Adjust. See Run the Cutover in the general guide for the rollout sequencing.
Testing Checklist
After migration, verify on each platform:
- SDK initializes: enable debug logging and check console output
- Deep links open the app: tap a WarpLink URL on a physical device
- Deep link data resolves: destination and custom parameters are correct
- Deferred deep links work: click link, install, verify match. An uninstall is enough to retest on either platform, because the completion marker goes with the app. That second install is reported as a reinstall and still counts as an install
- AASA/assetlinks verified:
curl https://aplnk.to/.well-known/apple-app-site-association - Error handling: test invalid URLs, expired links, no connectivity
- SKAdNetwork ownership is unambiguous if Adjust is still installed during testing
- All Adjust code removed: no remaining imports or dependencies
- Clean build: no compilation errors
Next Steps
- General migration guide: the provider-agnostic playbook for planning, domains, cutover, and decommissioning.
- Quickstart: create your first link and get an SDK key.
- iOS SDK, Android SDK, and React Native SDK: full setup and API reference.
- Adjust alternative for small teams: cost comparison and positioning for teams evaluating the move.
AppsFlyer Migration
Migrate from AppsFlyer OneLink to WarpLink: link and parameter mapping, SDK swap, and deep linking, install attribution, and analytics.
Kochava Migration
Migrate from Kochava to WarpLink: SmartLink and parameter mapping, SDK swap, and deep linking, install attribution, and analytics.