SKAN 4.0 Setup for iOS App Attribution
SKAdNetwork 4.0 (SKAN 4.0) arrived with iOS 16.1 and brought several important changes compared to SKAN 2.x/3.x: three postbacks instead of one, coarse value as fine conversion value supplement, and lockWindow API for explicit timer control. If your app works with ad networks supporting SKAN 4.0—migration is worth it because three postbacks give fundamentally more information about user lifecycle in first 35 days.
What Changed in SKAN 4.0
Three Postbacks Instead of One
In SKAN 2.x/3.x ad network got exactly one postback—when conversion timer expired. SKAN 4.0 introduces three time windows:
| Postback | Time Window | Contents |
|---|---|---|
| First | 0–2 days after install | fine value (0–63) + coarse value + source identifier |
| Second | 3–7 days | coarse value (low/medium/high) |
| Third | 8–35 days | coarse value |
Second and third postbacks send only if user showed activity in that window. This lets ad network see if user stayed active on day 7 and day 35—impossible without first postback.
Fine Value and Coarse Value
Fine conversion value — previous 6 bits (0–63). Stays only in first postback and only at high crowd anonymity (Apple doesn't disclose exact threshold, roughly thousands of installs from single campaign).
Coarse value — new field with three values: low, medium, high. Sends in all three postbacks even at low traffic volumes. Less informative but stable.
Source Identifier
New 2–4 digit field replacing campaign ID. First two digits always in postback, third and fourth only at sufficient crowd anonymity. Allows encoding not just campaign but ad set or single ad.
SKAN 4.0 Integration
Updated updateConversionValue
In SKAN 4.0 method takes three parameters:
import StoreKit
// iOS 16.1+
if #available(iOS 16.1, *) {
SKAdNetwork.updatePostbackConversionValue(
fineValue: 15, // 0–63, only for first window
coarseValue: .medium, // .low, .medium, .high
lockWindow: false, // true = close window immediately, don't wait timer
completionHandler: { error in
if let error = error {
print("SKAN update failed: \(error)")
}
}
)
}
lockWindow: true parameter is new in SKAN 4.0. If called with true, Apple immediately starts postback send without waiting for timer. Useful when you know user did key action and further updates aren't needed.
Backward Compatibility
App must support SKAN 3.x for iOS 14.x–16.0 and SKAN 4.0 for iOS 16.1+. Call both APIs in parallel:
func trackPurchase(revenue: Double) {
let fineValue = encodeFineValue(revenue: revenue)
let coarseValue: SKAdNetwork.CoarseConversionValue = revenue > 20 ? .high : .medium
if #available(iOS 16.1, *) {
SKAdNetwork.updatePostbackConversionValue(
fineValue,
coarseValue: coarseValue,
lockWindow: false
) { _ in }
} else if #available(iOS 14.0, *) {
SKAdNetwork.updateConversionValue(fineValue)
}
}
MMP Configuration
AppsFlyer and Adjust already support SKAN 4.0, but must explicitly enable three postbacks in app settings in dashboard. By default MMP continues working in SKAN 3.x mode.
In AppsFlyer in iOS App Settings → SKAdNetwork: select SKAN 4.0 mode, set coarse value mapping for second and third windows.
Designing Conversion Value Schema for Three Windows
For SKAN 4.0 design three independent schemas—one per postback window:
First window (0–2 days): detailed information about first actions. Fine value encodes, e.g.:
- 0–15: registration without purchase, engagement level
- 16–31: added to cart, product category
- 32–63: made purchase, revenue bucket
Second window (3–7 days): coarse value reflects retention status:
-
low— didn't return -
medium— opened app but no key event -
high— repeat purchase or high engagement
Third window (8–35 days): similar to second but for 2nd month of lifecycle.
Limitations and Reality
Crowd anonymity means for small apps (less than 1000–2000 installs from specific campaign) Apple replaces fine value in first postback with null. Coarse value always comes. Account for this in analysis: missing fine value isn't integration error but privacy protection.
What's Included
- Audit current SKAN integration and SKAdNetwork version in Info.plist
- Design three-level conversion value schema
- Implement
updatePostbackConversionValuesupporting iOS 14–16.1+ - Configure SKAN 4.0 in AppsFlyer / Adjust
- Verify postbacks via test traffic
Timeline
3–5 days. Most time spent on schema design and marketing team alignment, not code. Cost calculated individually.







