The confusion here is mostly vocabulary. Three frameworks, three consent stories, three data shapes — and most explainers are written by MMP vendors with a subscription to sell. Here's the map as it stands in 2026, sized for a solo developer rather than a growth team.
The mental model: one deterministic island, everything else aggregate
Sort the three systems by the question they answer and the picture gets simple:
| System | Covers | Granularity | Needs ATT? |
|---|---|---|---|
| AdServices | Apple Search Ads only | Per user: campaign, ad group, keyword | No (consent adds click detail) |
| SKAdNetwork 4 | Any registered ad network | Aggregate: campaign + conversion value | No |
| AdAttributionKit | Successor to SKAdNetwork; adds alternative marketplaces, re-engagement | Aggregate, same model | No |
AdServices exists because Apple owns both sides of a Search Ads install — the ad and the store — so it can attribute deterministically without tracking anyone across companies. Everyone else's ads go through the aggregate lane. That asymmetry is the whole landscape; the rest is detail.
AdServices: the half you can fully trust
Your app asks the framework for an attribution token, posts it to Apple's
API, and gets back either attribution: false (organic) or the
campaign, ad group, and keyword IDs behind the install. It's per-user, it's
exact, and the standard payload needs no consent — only the click timestamp
is held back for users who declined ATT. Attach the result to your user
record and "which keyword produced subscribers" becomes an ordinary query.
Because this is the deterministic half, it deserves its own walkthrough — token retries, payload fields, the ID-to-name mapping — which we've written up separately. The one-sentence version: if Apple Search Ads is your only paid channel, AdServices alone replaces an MMP.
SKAdNetwork 4: what the aggregate lane actually delivers
For Meta, TikTok, Reddit, or any other network, attribution arrives as postbacks: signed messages from Apple to the ad network (with a copy to you, if you register for it) saying "an install from campaign X reached conversion value Y." No device ID, no user, deliberately delayed. The version-4 specifics that matter:
- Three postbacks per install, covering activity windows of roughly days 0–2, 3–7, and 8–35. Each is sent after a further random delay, so the signal lands days after the behavior.
- Conversion values come in two resolutions. A fine value (0–63) can arrive in the first postback only; the later windows carry at most a coarse low/medium/high. Whatever you want to know about day-30 quality has to compress into three buckets.
- Crowd anonymity decides what you receive. Small campaigns — which, for an indie, is most campaigns — get fields nulled or coarsened. Below the thresholds you may learn only that installs happened.
- Hierarchical source identifiers give up to four digits of campaign structure, but again only when install volume clears the tiers.
Two practical consequences for an indie budget. First, register to
receive your own postback copies — add the
NSAdvertisingAttributionReportEndpoint key to your Info.plist
pointing at an endpoint you control, and Apple sends you a copy of what the
ad network gets. Without it, your only view of your own attribution is the
network's dashboard. Second, concentrate spend: crowd
anonymity is per campaign, so five small campaigns can each fall below the
thresholds while one consolidated campaign would have cleared them. Fewer,
bigger campaigns buy you better data, which is backwards from how web
advertisers structure things and worth internalizing early.
The honest summary: SKAdNetwork tells a small advertiser which campaigns produce installs that reach milestones you chose in advance. It does not tell you who, when exactly, or what they did next.
AdAttributionKit: same contract, new container
AdAttributionKit shipped in iOS 17.4, originally so attribution could work on alternative app marketplaces in the EU, and has been absorbing SKAdNetwork's role since. It adds re-engagement attribution (ads that reopen an installed app, from iOS 18) and better developer testing, and it interoperates with SKAdNetwork campaigns during the migration, so nothing breaks while ad networks move over.
What it pointedly does not change is the privacy model: postbacks, conversion windows, crowd anonymity, aggregate only. If you were hoping the successor framework would quietly return user-level data — it doesn't, and Apple's direction of travel makes that a safe long-term assumption. Cover AdAttributionKit in your planning because your ad networks will require it, not because it unlocks anything new.
What you cannot know, in writing
Worth stating plainly, because a lot of tooling is marketed as if these were still purchasable:
- Which specific user came from which paid-social ad. Gone with IDFA consent rates; fingerprinting workarounds violate Apple's rules and get apps rejected.
- Per-user LTV curves by campaign for non-Apple networks. The best you get is conversion-value distributions per campaign.
- Fast feedback. Postback delays plus conversion windows mean paid-social signal is days old by arrival. Budget decisions run on a lag.
- Small-campaign detail. Privacy thresholds bite hardest exactly at indie spend levels.
None of this blocks running ads profitably. It blocks pretending to precision — which, at indie scale, was mostly noise anyway. The same sample-size honesty we argued for in measuring onboarding against paid conversion applies double behind a privacy threshold.
The one lever you control: what conversion values mean
You can't widen the pipe, but you decide what flows through it. The 0–63 fine value and the coarse buckets are yours to define, and the common mistake is spending them on vanity milestones (opened the app twice) instead of money-correlated ones (started trial, finished onboarding, reached the value moment). Two rules from doing this on live apps:
- Encode the funnel steps that predict revenue, which you only know if behavior and purchases already join on one user record — the one-ID pattern again. Your own joined data tells you which early actions correlate with paying; the conversion value should encode those.
- Keep the mapping server-side. Conversion-value schemes need iteration, and an app-update round trip per tweak means you'll stop iterating. A config-driven mapping lets you retune what 0–63 means without shipping a build.
FAQ
Do I need an MMP like AppsFlyer or Adjust?
Apple-only spend: no — AdServices covers it deterministically. Several non-Apple networks at once: an MMP's real job today is collecting and deduplicating SKAdNetwork/AdAttributionKit postbacks across networks, which is worth paying for at a scale most indies haven't reached.
Can SKAdNetwork tell me which users came from which campaign?
No, and no setting changes that. Campaign-level counts and conversion values are the entire product. Anything claiming user-level paid-social on iOS is either modeled (estimates) or fingerprinting (against the rules).
Is AdAttributionKit replacing SKAdNetwork?
Yes, gradually — same aggregate model, plus alternative marketplaces and re-engagement, with interoperability during the transition. Adopt it when your ad networks ask; expect no new user-level data from it.
Should I still show the ATT prompt?
If your measurement is AdServices plus conversion values, skipping the prompt costs you almost nothing — consent mainly adds click-level detail to the Search Ads payload. One less scary dialog in onboarding is usually worth more than the extra field.