Install Attribution
Understand how the WarpLink iOS SDK attributes installs, including match types, confidence scores, and privacy considerations.
WarpLink uses two tiers of attribution matching to connect app installs to the links that drove them.
Match Cascade
When the app opens, the SDK collects device signals and sends them to the WarpLink API. The server compares them against stored click signals.
| Tier | Method | Signal | Confidence |
|---|---|---|---|
| 1 | Deterministic | IDFV | 1.0 |
| 2 | Probabilistic | Enriched fingerprint | Up to 0.85 |
Deterministic Matching (IDFV)
Used for re-engagement, when the app was previously installed on the same device.
- Signal:
UIDevice.current.identifierForVendor(IDFV) - Match type:
.deterministic - Confidence: always 1.0
- Does not require ATT permission
IDFV is a UUID unique to the combination of your app and the device. It persists across reinstalls on the same device.
Probabilistic Matching (Enriched Fingerprint)
Used for first-install attribution, when the app was not previously installed.
- Signals: IP address (derived server-side) + normalized primary language + timezone
- Match type:
.probabilistic - Confidence: varies by fingerprint variant and elapsed time
Fingerprint Variants
| Variant | Timezone component | Sent by |
|---|---|---|
enriched_tz | IANA zone name, for example America/Toronto | SDKs that collect a zone name |
enriched | Minute offset | Older SDKs, and devices that cannot resolve a zone |
basic | None | Fallback when neither matches |
The zone name carries far more entropy than the offset (roughly 340 zones against 38 offsets) and does not shift at a daylight-saving boundary, which previously broke a click-then-install pair across the change. It therefore earns a higher confidence ceiling.
Confidence by Elapsed Time
| Time Since Click | enriched_tz | enriched | basic |
|---|---|---|---|
| < 1 hour | 0.85 | 0.80 | 0.70 |
| < 3 hours | 0.65 | 0.60 | 0.50 |
| < 6 hours | 0.50 | 0.45 | 0.35 |
| < 24 hours | 0.30 | 0.25 | 0.20 |
Past 24 hours there is no match at all. The 24 hour band only applies to links whose match window is set past the 6 hour default.
Two further signals can only reduce the score, because a confident wrong answer is worse than an honest uncertain one:
- Bucket ambiguity. More than one claimable click shared the fingerprint: x0.6
- IP sharing. Carrier-grade NAT or a private address: x0.6. A household IPv4 address: x0.9. IPv6: x1.0
Reinstalls
A reinstall counts as an install. When a device deletes your app and installs it again, the SDK runs attribution again and the result lands in your install numbers like any other install.
The attribution request carries is_reinstall: true in that case. The SDK reads it from a Keychain marker that outlives an app delete, while the marker that stops a duplicate check inside one install lives in a backup-excluded file and does not. The flag labels the install and never blocks the request. See App Reinstall.
Interpreting Results
The WarpLinkDeepLink includes matchType, matchConfidence, and matchGuaranteed:
WarpLink.checkDeferredDeepLink { result in
if case .success(let deepLink) = result, let deepLink = deepLink {
let confidence = deepLink.matchConfidence ?? 0
switch confidence {
case 0.5...:
navigateTo(deepLink.destination)
case 0.3..<0.5:
showSuggestion(deepLink.destination)
default:
showOnboarding()
}
}
}
| Confidence | Recommended Action |
|---|---|
| 1.0 (deterministic) | Route directly to content |
| > 0.5 (probabilistic) | Route to content: high confidence |
| 0.3–0.5 | Show content with confirmation ("Were you looking for...?") |
| < 0.3 | Show generic onboarding |
Gate Sensitive Actions on matchGuaranteed
matchGuaranteed is true only for a deterministic match, which on iOS means IDFV. Gate anything sensitive, such as auto sign-in or showing personal data, on this flag rather than on a matchConfidence threshold. A probabilistic match is a best guess made from a network-shaped fingerprint and can name the wrong user.
if deepLink.matchGuaranteed {
restoreSession(for: deepLink)
} else {
navigateTo(deepLink.destination) // public content only
}
App Tracking Transparency
The WarpLink SDK:
- Does not use IDFA (Advertising Identifier)
- Does not prompt for ATT permission
- Uses only IDFV, which is exempt from ATT
- Does not interfere with your app's own ATT strategy
Privacy
Signals Collected
| Signal | Purpose | Source |
|---|---|---|
| Preferred language | Fingerprint component (server normalizes to the primary subtag) | Locale.preferredLanguages.first |
| Timezone name | Fingerprint component, sent as timezone by SDKs that collect a zone name | TimeZone.current.identifier |
| Timezone offset | Fingerprint component, the fallback for older SDKs | TimeZone.current.secondsFromGMT() |
| IDFV | Deterministic matching | UIDevice.current.identifierForVendor |
The IP address is the third fingerprint component. The SDK never sends it: the server derives it from the request. User-Agent and screen dimensions are not collected. They never match reliably from a browser to a native app.
Not Collected
- IDFA (Advertising Identifier)
- Location data
- Contacts or personal data
- App usage data
- Cross-app identifiers
All signals are sent over HTTPS and used solely for attribution matching. No cross-app tracking is performed.