skip to content

Search

SKAdNetwork: How Apple Rebuilt Attribution Without the Identifier

Less than one minute read Updated:

A precise, practitioner's walkthrough of how SKAdNetwork actually works — registration, signed ads, device-side attribution, delayed randomized postbacks, conversion values, crowd anonymity, and the move to AdAttributionKit. What it gives you, and what it takes away.

Apple didn’t ask ad networks to stop tracking users. It asked your phone to start lying to them, carefully.

Every ad network in mobile spent 2020 asking the same question. If Apple kills cross-app tracking, how does anyone know an ad worked? Apple’s answer, SKAdNetwork, is not a compromise between privacy and measurement. It is a completely different machine, and most attribution teams are still running the old mental model against it.

I own the data repository under a DSP and an ad exchange that measures 200M+ devices’ worth of ad events a day. SKAN didn’t change a single metric in that pipeline. It changed what I am allowed to know, and that distinction is the whole post.

So that’s today’s post.

Today’s Post

Everything SKAN actually does, in the order it happens on the device.

  • Why Apple moved the attribution join off the network’s servers
  • The five-step handshake behind every SKAN install
  • Squeezing your whole measurement plan into one 6-bit number
  • Why your postback shows up two days late, on purpose
  • The crowd-size math that erases small campaigns
  • What AdAttributionKit adds on top, and what stays the same
  • How I actually run measurement now that counting is gone

1. The core inversion: the device attributes, not the network

The previous post in this track covered App Tracking Transparency, the consent prompt that removed the IDFA for most users. ATT is the wall. SKAN is the door Apple built into that same wall.

Classic mobile attribution ran through a broker. An MMP (a mobile measurement partner: AppsFlyer, Adjust, Branch) saw the ad click, saw the install, and joined the two on a device identifier. AppsFlyer held the join. Adjust held the join. The network paying for the ad never had to.

SKAN deletes the broker and moves the join onto the phone itself, inside a framework only Apple can read. Your device saw the ad. Your device saw the install. Your device, and nothing else, connects them. It then sends one signed message, the postback, to the network. Apple signs it, your phone witnesses it, and you receive a summary after the fact.

That’s the entire design philosophy in one line: measurement happens where the data already lives, and only an aggregate is allowed to leave.

Where the join happens: server versus device Old attribution let the MMP hold the identifier that ties an ad to an install. SKAN moves that join onto the phone. Grey monospace text names the concrete artifact at each step. OLD MODEL: MMP HOLDS THE JOIN Ad network reports the click, with a device ID IDFA or GAID leaves the device device ID MMP server holds the click log and the install log joins both by the same device ID AppsFlyer, Adjust, Branch row-level match Advertiser gets a user-level attributed install identifier visible to a third party Risk: the identifier crosses two servers before you see it. SKAN: THE DEVICE HOLDS THE JOIN Device sees the signed ad and the install StoreKit, no third party present on-device join StoreKit, on the phone matches ad to install locally no network ever sees this step Apple signs, only Apple reads signed aggregate only Ad network gets one signed postback, delayed source ID, conversion value, flags Guarantee: no identifier tying ad to install ever leaves the device. a party outside the device where the old join lived, and its risk the device-held step, and what SKAN sends out Both models end with the network learning an install happened; only SKAN never lets it see the identifier that proves which user.
Both models end with the network learning an install happened. Only one of them lets an identifier leave the device to prove which user. PNG ↓

2. The five-step handshake behind every SKAN install

Four parties touch a SKAN install: the ad network, the publisher app showing the ad, the advertised app being installed, and Apple’s StoreKit sitting between all three.

Step 1, the network registers. Apple issues a network ID and stores its public keys. Only registered networks can participate, and that registration is what lets Apple cryptographically sign every message downstream.

Step 2, Apple signs the ad. The publisher app renders the ad through a StoreKit ad API. The signed payload carries the network ID, the campaign ID, the advertised app’s ID, a source identifier, and a nonce. The signature proves later that a real registered network actually served a real ad.

Step 3, the user installs and opens the app. StoreKit privately records that this install followed an ad it had signed. Nothing about this linkage leaves the device yet.

Step 4, the app sets a conversion value. On first launch the advertised app registers for attribution and can update a numeric conversion value during a measurement window as the user does things: registers, finishes onboarding, buys something.

Step 5, Apple sends the postback, late. When the window closes, the device builds a signed JSON postback: a source identifier, the conversion value, and some flags. It goes to the network’s registered endpoint, not to you directly, after a randomized delay.

Notice what step 5 leaves out. No IDFA, no device ID, no timestamp precise enough to re-identify anyone, no event log. A source identifier, a number, and a few flags.

The five-step handshake behind every SKAN install One ordered sequence, four parties, and a signature carried through every step. Scroll slowly, this plays once, left to right, and settles. 1 Network registers Apple issues an ID and keys only registered networks sign 2 Apple signs the ad campaign, app ID, nonce StoreKit ad API payload 3 Install and open StoreKit privately records it nothing leaves the device yet 4 Conversion value set app updates it during the window 0 to 63, on-device only 5 Postback, delayed signed JSON to the network no IDFA, no timestamp, no log registration, before any ad runs signed ad through install, still on-device the one number the app controls what finally reaches the network Steps 1 through 4 never touch a network's server. Step 5 sends one signed, stripped-down message, on Apple's schedule.
One signature, carried through all five steps. Nothing before step 5 ever touches a network's server. (animates as you scroll to it) PNG ↓

3. Conversion values: your whole measurement plan in one number

The conversion value is the only channel you have to say “this install was good.” SKAN 3 gave you a single 6-bit integer, 0 to 63. Sixty-four buckets for everything you care about: did they register, did they hit level 5, did they spend $0 to $5 or $50-plus.

That’s a real design constraint, not a technicality. You cannot fit “revenue tier” and “day-1 retention” and “funnel step” into 64 values at full resolution. Most teams partition the bits, low bits for a revenue bucket, high bits for an engagement event, and live with the collisions.

SKAN 4, the version most integrations target now, upgraded the schema on five fronts:

CapabilitySKAN 3SKAN 4
Conversion valueOne 6-bit fine value (0 to 63)A fine value (0 to 63) and a coarse value (none, low, medium, high)
Postbacks per installOneUp to three, across separate windows
Measurement windowsOne short windowWindow 1 (roughly 0 to 2 days), Window 2 (3 to 7 days), Window 3 (8 to 35 days)
GeographyLimitedA hierarchical source identifier, more granularity when volume allows
Privacy gatingThreshold-basedExplicit crowd-anonymity tiers
Lock windowNoneThe app can lock the conversion value early to trigger the postback sooner

The two-tier value is the clever part. The fine value only reaches you when the campaign has enough volume to stay anonymous, and even then only in the first postback window. Windows two and three are always coarse, no matter how large the campaign is. When volume drops, Apple downgrades you to the coarse value (none, low, medium, high), and at the lowest tier even that can be withheld.

The lock window lets you say “I’ve seen enough, send the postback now” instead of waiting out the full window, useful when the signal you care about (a same-session purchase) resolves fast.

One 6-bit schema, three different postbacks The same conversion-value schema behaves differently depending on how many installs it's hiding inside. Grey monospace text is what actually arrives at each volume tier. High volume, 5,000+ installs fine value released, 0 to 63 first window, plus granular source ID, plus up to three postback windows Medium volume, a few hundred installs degraded to coarse: none, low, medium, high fine value withheld, source ID granularity reduced Low volume, a handful of installs zeroed out: "an install happened," nothing else conversion value withheld entirely, crowd too small to hide one person fine value, full resolution coarse value, four buckets withheld, re-identification risk too high bar length is illustrative, not to scale
Same schema, three different postbacks. Volume decides which one you get. PNG ↓

4. Why postbacks arrive late, on purpose

This is the part that trips people up every time, so say it plainly: the delay and the randomization are the privacy mechanism. They are not a limitation Apple forgot to fix.

If a postback arrived the instant an install completed, you could line it up against your own impression log by timestamp and re-identify the user through timing alone. So Apple delays the first postback by a randomized window of roughly 24 to 48 hours after the conversion-value activity, and randomizes the exact send time inside that window.

The result: you cannot join a postback to your impression log by clock time. The cheapest re-identification trick in the old playbook is gone by design. This is also why SKAN reporting always lags. There is no such thing as a real-time SKAN dashboard. If your finance team asks for D0 ROAS from SKAN, the honest answer is that the number does not exist yet, and it never will for that day.

5. Crowd anonymity: the math that erases small campaigns

This is the single most important operating concept in SKAN, and the one that wrecks small advertisers’ measurement fastest.

SKAN 4 formalizes this as four crowd-anonymity tiers, Tier 0 through Tier 3. Tier 0 returns almost nothing. Each tier above it unlocks one more layer: the coarse value, then a more granular source identifier, then the fine value. A postback can only carry as much detail as the crowd around it can hide an individual inside.

If 5,000 installs in a region share a campaign, one install disappears into that crowd easily, and Apple releases the fine value and a granular source identifier. If only 8 installs match, releasing the fine value could fingerprint a real person, so Apple withholds it, often the coarse value too, and can strip campaign granularity down to almost nothing.

By volume, mapped onto those tiers:

  • High-volume campaigns get fine values, multiple postback windows, and granular source IDs.
  • Mid-volume campaigns get coarse values and reduced granularity.
  • Low-volume campaigns get a bare “an install happened” postback with the conversion value zeroed out. You cannot tell what those users did.

The part that surprises every team new to SKAN: you cannot fix this by fragmenting a campaign into finer ad sets. Splitting volume thinner pushes more slices below the anonymity threshold, not fewer. SKAN structurally rewards consolidation, fewer and larger campaigns, which runs against the granular-optimization habit the industry spent a decade building.

Four crowd-anonymity tiers, one threshold each A postback can only carry as much detail as the crowd around it can hide one person inside. Grey monospace text is the install-volume band that unlocks each tier. Tier 0 almost nothing returned no conversion value, no source detail smallest campaigns, install volume near zero unlocks: just "an install happened" Tier 1 coarse value unlocked none, low, medium, or high low install volume, still thin unlocks: coarse conversion value Tier 2 granular source ID more geography, still coarse value medium install volume unlocks: hierarchical source identifier Tier 3 fine value unlocked the full 0 to 63, first window only high install volume, 5,000+ typical unlocks: fine value and multiple windows Fragmenting a campaign into finer ad sets pushes slices below their tier, not above it: SKAN rewards fewer, larger campaigns.
Fragmenting a campaign pushes slices below their tier, not above it. SKAN rewards fewer, larger campaigns. PNG ↓

6. What SKAN gives you, what it takes, and what AdAttributionKit adds

SKAN’s install attribution is genuinely fraud-resistant. The cryptographic signing on every ad and every postback rules out a whole class of fake-click fraud that plagued the old MMP model. You get a coarse post-install quality signal through the conversion value, and aggregate campaign performance good enough for budget calls at the campaign level.

Here’s the other side, stated as plainly. SKAN gives you no user-level rows, no per-user funnel, no cohort you can re-query later. Everything lags by days. You decide your conversion-value schema up front and cannot re-cut history, because the underlying events never left the device. There is no cross-app journey, no LTV curve built from raw events, and no retargeting audience derived from any of it. Small campaigns get erased by crowd anonymity, full stop.

Apple’s successor to SKAN, AdAttributionKit, introduced at WWDC 2024, keeps every one of those trade-offs and extends the model two directions. First, re-engagement attribution: SKAN measured new installs well and lapsed-user re-engagement poorly, and AAK closes that gap with first-class support for it. Second, alternative app marketplaces: the EU’s Digital Markets Act forced iOS to permit non-App-Store marketplaces, and AAK is built so attribution works across those too, instead of assuming the App Store is the only door.

AAK runs alongside SKAN today. The conversion-value and postback concepts carry over unchanged, so everything in this post transfers directly. Treat SKAN as the foundation and AAK as the same machine with two more doors on it.

7. The practitioner’s reckoning: modeling instead of counting

Here’s what changes when your whole career has been event-level joins and SKAN becomes a primary signal.

Sitting under a DSP and an exchange, my instinct is to join my way out of uncertainty. Impression log, click log, bid log, install event, in-app event: pick a key, join, count, trust the rows. SKAN removes the key on purpose. There is no row to join. There is a source identifier, a number from 0 to 63, and a few flags, arriving two days late, sometimes not arriving at all.

So measurement stops being a counting problem and becomes a modeling and design problem.

Your conversion-value schema is your instrumentation. You cannot add a metric after the fact. If revenue tiers weren’t encoded into the bits, that information is gone for that cohort, permanently. I treat schema design the way I’d treat a database migration: slow, reviewed, and irreversible once it ships.

You reconcile two truths that never tie out. My own DSP and exchange logs give me rich, real-time, deterministic data on the served side of every ad. SKAN gives me privacy-degraded outcome data on the other side. They will not match at the row level, and the discipline is not forcing them to. I calibrate the modeled view against the SKAN aggregate, never the reverse.

You optimize one altitude coarser. Campaign-level budget calls, not creative-level micro-optimization, because that’s the resolution crowd anonymity actually supports. A dashboard that claims more resolution than the privacy budget allows is a dashboard that lies confidently.

You build the org’s calendar around the lag. Today’s number does not exist today. Set that expectation once, or you’ll spend every Monday explaining why Friday’s spend has no results yet.

SKAN’s contract with you is different from the old one, not worse. The old contract said measure everything and trust the rows. This one says measure inside a privacy budget, model the rest, and be honest about the uncertainty you cannot model away. For an industry that built its entire optimization culture on event-level granularity, that’s a change in worldview, not a change in tooling.

Takeaways

A postback built to tell you less than it could Seven sections on how SKAdNetwork moves attribution onto the device, and what AdAttributionKit adds Hoshank Ailani · hoshank.vercel.app 1. The join moves to the device No MMP server ever sees the identifier StoreKit matches ad to install locally Only one signed aggregate leaves the phone Measurement happens where the data lives old model: AppsFlyer, Adjust, Branch held the join on their servers, keyed on IDFA or GAID device witnesses, Apple notarizes, network gets a receipt 2. The five-step handshake 1 Network registers with Apple 2 Apple signs the ad payload 3 User installs, StoreKit records it 4 App sets the conversion value 5 Postback sent, delayed and signed no IDFA, no timestamp precise enough to re-identify, in the message that finally arrives four parties, one signature carried through all five steps 3. Your whole plan in one number SKAN 3: one 6-bit integer for everything SKAN 4: adds a coarse value, up to three postback windows, and a lock window 64 values the entire budget for revenue tier, funnel step, and retention decided before launch, because the underlying events never leave the device to be re-cut later 4. Late, on purpose Randomized 24 to 48 hour delay breaks the cheapest re-identification trick: joining a postback to your impression log by clock time 24 to 48h there is no same-day SKAN number, and there never will be a D0 ROAS request against SKAN is a request for a number that does not exist yet 5. Crowd anonymity erases small campaigns 0 Almost nothing, install volume near zero 1 Coarse value, low volume 2 Granular source ID, medium volume 3 Fine value, 5,000+ installs typical fragmenting a campaign pushes slices below their tier, not above it: fewer, larger campaigns win 6. AdAttributionKit keeps the model Same device-side join, same postback shape Adds re-engagement attribution as first-class Adds alternative App Store marketplaces Every trade-off in this post carries straight over announced WWDC 2024, runs alongside SKAN EU Digital Markets Act forced the marketplace door open treat SKAN as the foundation, AAK as two more doors on it SKAN measures inside a privacy budget; the rest is modeled, not counted. Your conversion-value schema is your instrumentation plan, decided once, before launch, and never re-cut. Full post: hoshank.vercel.app/posts/adtech-track-skadnetwork-aak Takeaways
The whole post on one card. Save it, share it, argue with it. PNG ↓

Seven sections, one mechanism. The device witnesses, Apple notarizes, and you get a receipt built to tell you less than it could.

Final Words

Pick one campaign you’re running on SKAN right now and check its volume against the anonymity tiers in section 5. If it’s fragmented thin enough to be losing the fine value, that’s the fix to make this week, not a bigger creative test.

In the final post of this track I’ll cover the other half of the story: every way the industry works around these walls, server-side conversions, fingerprinting, clean rooms, modeled conversions, and first-party identity, and which of those actually produce numbers you can trust when you own the reconciliation layer.

Cheers, Hoshank