Glossary/iOS platform and privacy
SKAN Postback
Definition
A SKAN postback is a signed JSON report that iOS sends from the device to an ad network's server after an advertised app is installed, containing the campaign identifier and any conversion value the install's privacy tier permits.
It is the only output of SKAdNetwork, which makes its shape the whole contract. There is no query API, no backfill, and no way to request a postback that never came — if your endpoint drops one, that install is unmeasured forever. Postbacks are also delayed by design, arrive out of order, and routinely omit fields you were counting on.
Who receives one, and how you get a copy
The device posts to the ad network registered in the advertised app's SKAdNetworkItems. You, the advertiser, are not a recipient by default — you receive copies only of the postbacks your app *wins*, and only if you declare an endpoint.
<key>NSAdvertisingAttributionReportEndpoint</key>
<string>https://postbacks.example.com</string>| Recipient | Endpoint | Gets |
|---|---|---|
| Ad network | /.well-known/skadnetwork/report-attribution/ | Wins and losses (did-win: false) |
| Advertiser | The host in NSAdvertisingAttributionReportEndpoint | Winning postbacks only |
The copy is worth having even when an MMP already parses the network's feed: it is the one version of the record that did not pass through a party with an interest in the numbers, which makes it the tiebreaker in a discrepancy argument.
Every field, and what it means when it is missing
{
"version": "4.0",
"ad-network-id": "example123.skadnetwork",
"source-identifier": "5239",
"app-id": 525463029,
"transaction-id": "6aafb7a5-0170-41b5-bbe4-fe71dedf1e28",
"redownload": false,
"source-app-id": 1234567891,
"fidelity-type": 1,
"did-win": true,
"postback-sequence-index": 0,
"conversion-value": 20,
"coarse-conversion-value": "high",
"attribution-signature": "MEQCIQD..."
}| Field | Always present | If absent, it means |
|---|---|---|
version | Yes | — |
ad-network-id | Yes | — |
transaction-id | Yes | — use it as the idempotency key |
app-id | Yes | — |
source-identifier | Yes | — but 2, 3 or 4 digits by tier |
conversion-value | No | Tier below 3, or index > 0. Not zero |
coarse-conversion-value | No | Tier 0 — nothing was measurable |
source-app-id / source-domain | No | The publisher cohort was too small to name |
fidelity-type | No | Treat as unknown, not as a click |
did-win | No | Older versions; absent implies a win |
redownload | Yes | — |
Absent is not zero
The most expensive parsing bug in SKAN is defaulting a missing conversion-value to 0. Zero means "installed and did nothing"; absent means "the cohort was too small to tell you". Conflating them creates a phantom population of worthless users, which then teaches your bidding to avoid the campaigns that were merely small.
The three timers
Every delay in SKAN is deliberate: arrival time must not leak conversion time. Three separate clocks stack up between the install and your dashboard.
| Postback | Measurement window | Randomised delay | Realistic arrival |
|---|---|---|---|
| Index 0 | Days 0–2 | 24–48 hours | Day 3 to day 5 |
| Index 1 | Days 3–7 | 24–144 hours | Day 8 to day 13 |
| Index 2 | Days 8–35 | 24–144 hours | Day 36 to day 41 |
- Postbacks for one install are not correlatable across indices — there is no shared install ID, only the campaign dimensions. Aggregate at the source-identifier level, never at the user level.
lockWindow: truecloses a window early but does not shorten the randomised delay.- Indices arrive out of order across a cohort. A day-13 report is not late; it is index 1.
- Cohort reporting must stay open for six weeks. A campaign judged at day 7 has seen one third of its postbacks.
Verifying the signature
The endpoint is a public URL that accepts unauthenticated POSTs, so anyone who finds it can send you installs. attribution-signature is an ECDSA signature over specific fields concatenated in a fixed order, verifiable against Apple's public key.
# Fields are joined with U+2063 (INVISIBLE SEPARATOR) in the order
# Apple documents for the postback's version — the order differs
# between 3.0 and 4.0, so branch on the version field.
printf '4.0example123.skadnetwork5239525463029...' > payload.txt
# Apple publishes the verification key; the signature is base64 DER ECDSA.
openssl dgst -sha256 \
-verify apple-skan-public-key.pem \
-signature <(base64 -d <<< "$SIGNATURE") \
payload.txtReject before you count
Verify the signature, then deduplicate on transaction-id, then count. Skipping either step means your install numbers are writable by anyone on the internet, and inflated SKAN volume that reconciles against nothing is indistinguishable from a fraud problem in your own reporting.
The exact field order is version-specific and Apple's documentation is the only authority on it; validate against a known-good live postback rather than trusting a copied implementation.
SKAN conversion value builder
The postback's conversion value is only useful if the schema behind it was designed for six bits and one window. Our builder produces that mapping, including what your dashboard should show when the field is absent rather than zero.
Open the skan conversion value builder →Frequently asked questions
- What is a SKAN postback?
- It is the signed JSON attribution report iOS sends from the device to an ad network after a user installs an advertised app. It contains the ad network ID, a hierarchical source identifier for the campaign, the app ID, a transaction ID, and — when the install cohort's privacy tier allows it — a conversion value describing post-install behaviour.
- How many postbacks does one install generate?
- Up to three in SKAdNetwork 4.0, one per conversion window, identified by a postback-sequence-index of 0, 1 or 2. They cannot be linked back to a single install because no shared identifier is included, so they must be aggregated at the campaign level rather than counted as three separate installs.
- Why does my postback have no source-app-id?
- Because the cohort of installs from that publisher app was too small for Apple to name the source without risking re-identification. The same crowd anonymity thresholds that strip the conversion value also strip the publisher identity, which is why granular publisher-level reporting is unavailable on low-volume campaigns regardless of instrumentation.
- How do I verify a SKAdNetwork postback is genuine?
- Verify the attribution-signature field, which is an ECDSA signature over a version-specific concatenation of postback fields joined by the U+2063 invisible separator character, checked against Apple's published public key. Because the endpoint accepts unauthenticated POST requests, skipping verification means anyone who discovers the URL can inject fabricated installs into your reporting.
- Can I get a postback resent if my server was down?
- No. There is no retry guarantee, no query API and no backfill, so a postback your endpoint fails to accept is lost permanently along with that install's measurement. Return a 200 quickly and do the parsing asynchronously, and keep the raw body so a parsing bug can be replayed without needing the postback again.
Related terms
- SKAdNetwork — SKAdNetwork is Apple's StoreKit framework that attributes app installs to advertising campaigns without exposing a device identifier, by having the operating system send a delayed, aggregated postback to the ad network that won the install.
- Conversion Value — A conversion value is a 6-bit integer between 0 and 63 that an iOS app sets after install to describe post-install behaviour, and which the operating system reports to the ad network in an attribution postback.
- Crowd Anonymity — Crowd anonymity is Apple's privacy mechanism that decides how much campaign and conversion detail an attribution postback may contain, based on whether the install cohort is large enough that the report cannot identify an individual.
- Webhook — A webhook is an HTTP request a service sends to a URL you control when an event occurs, delivering the event's data without your system having to poll for it.