Skip to main content

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/deferred with 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.