Blog · SKAN 4
SKAN 4 still has one fine conversion value, and it is only the first postback.
SKAdNetwork 4 did not give you three fine conversion values. It added three windows and a coarse low, medium, high. The 0-63 value still exists, and it only arrives on the first postback, and only when crowd anonymity allows. MMP dashboards that still map a single 0-63 across 35 days are reading a schema Apple does not send.
That mapping looks close enough to ship. There are postbacks, a conversion value, a campaign-shaped id. SKAN 4 renamed the two-digit campaign identifier to a four-digit source identifier, split conversion value into fine and coarse, and tied extra postbacks to fixed windows. The app still calls updatePostbackConversionValue. The payload Apple actually signs on days 8-35 is not a second 6-bit number.
A modeled 0-63 on window 3 is how ROAS looks precise and unfalsifiable. Apple's docs say conversion-value is a fine-grained conversion value available only in the first postback. coarse-conversion-value is what lower privacy tiers get instead, and what the second and third postbacks carry. That is the news. SKAN is not dead. AdAttributionKit is newer and interoperates. The SKAN 4 schema still has one fine value.
Three windows, not three fine values
SKAdNetwork 4 is available in iOS 16.1 and later. Sign ads with version 4.0. The advertised app needs to be App Store-signed on iOS 16.1 or later. Apps built with iOS 16.1 SDK or later can register up to three conversions for the winning impression. Earlier SDKs still register one. Ads in apps need the iOS 16.1 SDK. Web ads need Safari 16.1 or later.
The conversion window begins when the user first launches the app. Window 1 is days 0 to 2. Window 2 is days 3 to 7. Window 3 is days 8 to 35. The app can update conversion values in all three. Multiple postbacks require the network to sign with SKAN 4 or later, and the advertised app to call updatePostbackConversionValue with a coarse value, including the lockWindow variant, during each window. Ads signed with version 3 or earlier still get one winning postback.
WWDC22 said the old single-postback model lost later engagement because the postback had already left. Food Truck could mark the first batch and never the delivery. Version 4 moved to three postbacks tied to those windows. The same session also said only the first postback will get the fine conversion value. The additional postbacks can carry the coarse conversion value. Only the winner and the developer receive the additional postbacks. Nonwinning attributions still get only the first postback. Tier 0 also sends only the first postback.
Crowd anonymity still blanks the number
Crowd anonymity is how SKAN decides how much of the postback you may see. WWDC22 walked the tiers with a source identifier 5739 and a conversion of high 42. At low crowd you get two digits of the source identifier and no conversion value. At medium you get three digits and the coarse value. At high you get four digits and the fine value. Only one of fine or coarse is sent back for that conversion slot. You do not get high and 42 in the same field.
The StoreKit page is more specific about postback data tiers. For the first postback, Tier 3 can include a hierarchical source-identifier, conversion-value if the app provided one, source-app-id or source-domain, and country-code when the country crowd is Tier 3. Tier 2 can include source-identifier and conversion-value. Tier 1 is two-digit source-identifier plus coarse-conversion-value. Tier 0 is two-digit source-identifier and no conversion value. Windows 2 and 3, for Tier 1 through 3, carry a two-digit source-identifier and coarse-conversion-value. Tier 0 does not send postbacks 2 and 3.
Null conversion values still happen. Apple's ad attribution FAQ says conversion-value and source-app-id are conditional and partners may show them as null when thresholds are not met. That is not an MMP outage. It is the privacy tier. Treating null as 0, or filling it from a predicted 0-63, is a modeled number, not a SKAN postback.
The update API ignores fine after window 1
fineValue is an unsigned 6-bit integer, 0 through 63. coarseValue is SKAdNetwork.CoarseConversionValue: low, medium, or high. The app defines what those mean. lockWindow true tells the system the value is final for the current window and to prepare the postback without waiting for the window to end. lockWindow false keeps accepting updates until the window closes. Invalid fine values return SKANError invalidConversionValue. The system ignores the out-of-range call. Valid updates before or after that call remain.
For ads signed with SKAN 4 or later, both fineValue and coarseValue represent conversion values. The method ignores fineValue after the first conversion window. You can keep calling the API in windows 2 and 3. The fine argument is not what the later postbacks contain. For ads signed with SKAN 3 or earlier, fineValue is the conversion value, coarseValue and lockWindow are ignored, and the period is still a rolling 24-hour timer that restarts when the app sends a valid value greater than the previous one. SKAN 4 conversion values may increase or decrease. Copying a SKAN 3 monotonically increasing mapper into a 4.0 signed campaign is a different miss from stuffing 0-63 into window 3.
Timing is not a dashboard refresh. After the window ends, or after a lock, the first postback waits a random 24-48 hours. Postbacks 2 and 3 wait 24-144 hours. SKAN 3 finalized after a 24-hour idle timer, then a 0-24 hour delay, which also totaled 24-48 hours after the final update. Locking in version 4 does not make the first postback faster than that 24-48 hour floor. An MMP that charts a purchase on day 0 from a SKAN postback is not reading Apple's delay.
The row people will store first
A 0-63 fine value on the third window. Apple sends coarse-conversion-value on postbacks 2 and 3, not conversion-value.
{
"skan_version": "4.0",
"window": "8-35",
"conversion_value": 42,
"modeled_revenue_usd": 19.99
}
That object is a legal internal schema if your MMP invented it. It is not a SKAN 4 postback. Window 3 may include coarse-conversion-value high, medium, or low, a two-digit source-identifier, and no conversion-value. Mapping 42 across 35 days, then multiplying by an average order value, is how a SKAN 3 revenue model survives a schema that dropped the 6-bit number after day 2.
Hierarchical source identifiers replace campaign ids. Winning postbacks contain two, three, or four digits depending on the privacy tier. WWDC22 asked you to treat the four digits as a hierarchy, not as 10,000 flat campaigns. At low crowd you only see the last two. A dashboard that still columns campaign-id 0-99 and conversion-value 0-63 for every postback-sequence is SKAN 2 storage on a 4.0 postback.
Names that do not translate
- SKAN 2 campaign-id (two digits) is SKAN 4 source-identifier (up to four digits, truncated by tier).
- A single conversion-value 0-63 is fineValue, and only window 1 may return it as conversion-value.
- Windows 2 and 3 send coarse-conversion-value: low, medium, or high. They do not send a second 0-63.
- SKAN 3 rolling 24-hour timer is not a SKAN 4 window. Version 4 windows are days 0-2, 3-7, and 8-35 from first launch.
- did-win false is a nonwinning first postback. It is not a window 2 copy, and it does not get the extra postbacks.
- MMP S2S in-app events are not SKAN postbacks. A server event with a fine value does not fill conversion-value on window 3.
- AdAttributionKit is a separate framework. It interoperates. It does not mean SKAN 4 stopped shipping.
AdAttributionKit is newer. SKAN still answers
Apple's SKAdNetwork page now tells you to use AdAttributionKit for app ad campaigns on the App Store and alternative marketplaces, and to read the interoperability article. That is a product direction. It is not a shutdown notice. SKAN 4 still signs ads, still sends up to three postbacks, still ignores fineValue after window 1. Devices still send did-win true to one network and did-win false to up to five others for SKAN 3 and later installs.
Interoperability is explicit. If the stack uses both, call both update APIs. Ad network IDs with .adattributionkit and .skadnetwork are compatible across both. Only one impression wins a conversion, whether it came from SKAN or AdAttributionKit. Click-through beats view-through. Recency breaks remaining ties. SKAN updatePostbackConversionValue can bridge into AdAttributionKit. Treating that bridge as a second fine value on a late SKAN window is still the wrong schema.
You do not need App Tracking Transparency to call SKAN APIs. You can call them regardless of tracking authorization. That does not restore IDFA. It does not make window 3 a 0-63. MMP S2S remains a different hop for events the SDK never saw. Do not fold a SKAN coarse postback into the same column as an AppsFlyer eventTime purchase.
What the MMP must parse
WWDC22 told ad networks to make servers capable of parsing the new source identifiers and coarse conversion values. That work is the minimum. Store postback 1's conversion-value separately from postbacks 2 and 3 coarse-conversion-value. Do not coerce high to 42. Do not chart a 35-day conversion-value sparkline. If the advertised app never calls the coarse update APIs during windows 2 and 3, those postbacks do not exist to parse.
lockWindow is an app decision per window. It does not change which fields the postback may contain. Developer copies of winning postbacks are the same payload the network gets, when the app opts in with NSAdvertisingAttributionReportEndpoint. They are not a richer fine value.
Only the first postback will get the fine conversion value. The additional postbacks can carry the coarse conversion value.
WWDC22: What's new with SKAdNetwork
What to do
Keep one internal engagement stream: install, first open, purchase, subscription. At the SKAN edge, map window 1 to a 0-63 plus a coarse bucket, and map windows 2 and 3 to coarse only. Persist postback-sequence, source-identifier digits received, conversion-value, and coarse-conversion-value as different columns. Null is a privacy tier, not zero.
Do not point a SKAN 3 revenue model at a 4.0 postback. Lint the postback you actually store. The SKAN contract is StoreKit: receiving postbacks in multiple conversion windows, the 4.0 release notes, and updatePostbackConversionValue. AdAttributionKit is the newer install and re-engagement path. It does not delete SKAN 4.
This post is the market fact: SKAN 4 still has one fine conversion value, and it is only the first postback. Pixellint is not affiliated with Apple or any MMP. Passing a linter means the artifact matches a published envelope. It does not mean Apple attributed the install, and it does not detect fraud.
Checklist
- Sign eligible ads with SKAdNetwork version 4.0. Earlier signatures still get one winning postback.
- Call updatePostbackConversionValue with fine 0-63, coarse low|medium|high, and lockWindow as a per-window decision.
- Expect conversion-value only on postback 1, and only at tiers that allow it. Windows 2 and 3 are coarse-conversion-value.
- Store source-identifier as two, three, or four digits. Do not keep a campaign-id 0-99 column as the SKAN 4 campaign.
- Do not map a single 0-63 across 35 days. Do not fill null with a modeled fine value and call it SKAN.
- Keep MMP S2S and SKAN postbacks in different tables. AdAttributionKit interoperates; it does not replace the SKAN 4 field list.
Sources
Contract pages
The dated argument is above. These pages are the field lists.