SKAdNetwork & iOS Attribution
Why Apple Built Its Own Attribution Framework
SKAdNetwork (SKAN) is Apple's privacy-preserving alternative to device-level, IDFA-based attribution. Instead of an MMP matching a specific device's click to a specific device's install, SKAN has the *operating system itself* perform the attribution and report back only aggregated, privacy-thresholded results to the ad network — no app, advertiser, or MMP ever sees which individual user converted. This architecture exists because Apple's App Tracking Transparency (ATT) framework requires explicit opt-in consent before any app can access the IDFA, and most users decline, making traditional device-matched attribution unavailable for the majority of iOS installs.
How the Postback Actually Works
When a user installs an app after tapping a SKAN-registered ad, iOS itself (not the app, not the ad network) tracks the click-to-install and, after a randomized delay following any conversion-value updates, sends a postback directly from the device to the ad network's registered endpoint. That postback contains a campaign ID, a source app ID, and a conversion value — a single 6-bit number (0–63) that the app can set to encode post-install signal, plus (as of SKAN 4) a coarse value (low/medium/high) and lock state. Crucially, the ad network never learns which specific device sent which postback — only aggregated counts per campaign, filtered by a minimum install threshold ("crowd anonymity") before any data is released at all.
| SKAN Version | Key Addition | Limitation Addressed |
|---|---|---|
| SKAN 2.0 | Source app ID, 24-hour fixed postback window | Baseline postback mechanism |
| SKAN 3.0 | Conversion value updates with a timer lock | Allowed post-install event signal, not just install |
| SKAN 4.0 | Up to 3 postbacks, coarse-grained value, source identifier granularity tiers | Addressed the 'one postback, one snapshot in time' problem |
The Conversion Value Timer Is a Trap for the Unprepared
updateConversionValue(), it resets a timer window (24 hours in SKAN 3, configurable per postback in SKAN 4). If you update the value too early, you lock in a low-signal value before meaningful post-install behavior (like a purchase) has happened. If you wait too long, the timer can expire and fire a postback with whatever value was last set — potentially zero. Designing the conversion value schema is fundamentally a time-boxed data compression problem, not just an event-mapping exercise.Encoding Business Signal Into 6 Bits
64 possible values is not much room to represent user quality. A typical approach buckets values into tiers: values 0 ignored or low activity (e.g., no action within 24h), a mid-range band encoding specific milestone events (tutorial complete, first search, first add-to-cart) and a top band reserved for monetization events (trial start, purchase, with the value also bucketed by revenue range). Because the value is a flat integer with no inherent schema, every ad network must be told out-of-band (via a mapping doc or dashboard config) what each value number means — there's no way to query 'what does conversion value 42 mean' from SKAN data itself.
import StoreKit
func reportPurchaseEvent(revenueTier: Int) {
// revenueTier: 0-7, pre-bucketed by the app's own purchase logic
// Encode: bits 5-3 = event type (purchase = 0b101),
// bits 2-0 = revenue tier
let eventTypeBits = 0b101 << 3
let conversionValue = eventTypeBits | revenueTier
if #available(iOS 16.1, *) {
SKAdNetwork.updatePostbackConversionValue(
conversionValue,
coarseValue: .high
) { error in
if let error = error {
print("SKAN postback update failed: \(error)")
}
}
} else {
SKAdNetwork.updateConversionValue(conversionValue)
}
}Crowd Anonymity and Data Sparsity
Apple withholds the source app ID, campaign ID, or conversion value from a postback entirely if the install volume for that combination falls below Apple's anonymity threshold — meaning small or highly-segmented campaigns routinely get null or stripped postbacks. This creates a structural tension: the more granular your campaign targeting (useful for optimization), the more likely you fall below the crowd-anonymity floor and lose attribution data entirely. Broad campaigns report more reliably under SKAN; narrow ones report less, which pushes advertisers toward consolidating campaign structures purely to preserve measurement, sometimes at the cost of targeting precision.
SKAN and MMP-Based Attribution Are Not Mutually Exclusive
What's Next?
SKAN is Apple's answer to a broader shift away from persistent cross-app identifiers, a shift that is reshaping ad targeting and measurement well beyond mobile install attribution.
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.