Documentation
Deferred deep linking
Send a new user to the exact in-app content they tapped — even when the app wasn't installed at click time. Deterministic on Android via the Play Install Referrer, and privacy-friendly probabilistic matching on iOS. It's a single REST endpoint — no heavy SDK, no device fingerprint stored, no cross-app tracking.
How it works
- Click — when someone taps a warplink and doesn't have your app, we send them to the store. On Android we attach an opaque token to the install referrer.
- First open — after install, your app calls
POST /api/v1/deferredwith the token (Android) or device signals (iOS). - Resolve — we return the original destination and params so you can route the user straight to the right screen.
Android — deterministic
Read the install referrer once on first launch, extract the warplink token, and resolve it. ~100% reliable.
// build.gradle: implementation "com.android.installreferrer:installreferrer:2.2"
val client = InstallReferrerClient.newBuilder(context).build()
client.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(code: Int) {
if (code == InstallReferrerResponse.OK) {
val referrer = client.installReferrer.installReferrer // "warplink=<token>&utm_source=warplink"
val token = Uri.parse("?" + referrer).getQueryParameter("warplink")
// POST { "token": token } to /api/v1/deferred, then route to the destination.
client.endConnection()
}
}
override fun onInstallReferrerServiceDisconnected() {}
})iOS — probabilistic
On first launch, send the device signals. We match the most recent click from the same IP within a short, single-use window and return a confidence score. Optionally pass a clipboard token for a deterministic match (see Phase 2).
// First launch only
let body: [String: Any] = [
"platform": "ios",
"fingerprint": [
"os_version": UIDevice.current.systemVersion,
"device_model": modelIdentifier(), // e.g. "iPhone15,2"
"screen": "\(Int(UIScreen.main.bounds.width))x\(Int(UIScreen.main.bounds.height))",
"timezone": TimeZone.current.identifier,
"language": Locale.current.language.languageCode?.identifier ?? "en"
]
]
// POST body to /api/v1/deferred; if matched && confidence is high enough, route.The endpoint
POST https://warpl.ink/api/v1/deferred. The client IP is taken server-side — never send it.
// Request — Android (deterministic)
{ "token": "<install-referrer-token>" }
// Request — iOS (probabilistic, or clipboard-deterministic)
{ "platform": "ios", "clipboard_token": "<optional>",
"fingerprint": { "os_version": "17.4", "device_model": "iPhone15,2",
"screen": "393x852", "timezone": "Europe/Moscow", "language": "en" } }
// Response
{ "matched": true,
"destination": "https://example.com/product/123?utm_source=...",
"link_id": "clx...", // deterministic match only
"params": { },
"match_type": "deterministic" | "probabilistic",
"confidence": 0.0, // 1.0 for deterministic
"match_details": { "ip": true, "time_minutes": 2, "language": true } }
// No match
{ "matched": false }Notes
- Privacy first. No persistent device fingerprint, no cross-app identity, no data brokers. The iOS match is a short, single-use, first-party correlation — outside Apple's definition of tracking. ATT is not required for deferred routing.
- Confidence. For a low-confidence probabilistic match, defer routing until after sign-up to limit the blast radius of a rare mis-match.
- No SDK required. Everything above is plain HTTP. Thin native SDKs (Android/iOS/React Native/Flutter) are on the roadmap to make referrer reading and signal collection one line.