pixellint

Blog · AdAttributionKit

AdAttributionKit re-engagement has no runner-up postbacks. SKAN 2 mappings do not apply.

AdAttributionKit re-engagement is not a SKAN 2 postback with a new name. It launched after install conversions, it is click-only, and it has no runner-up copies. MMP stacks that still join did-win false and campaign-id 0-99 onto a reengagement conversion-type are reading a schema Apple does not send.

That mapping looks close enough to ship. There are postbacks, a conversion value 0-63, a source identifier, a winning network. SKAN 2 taught a two-digit campaign and a 6-bit value that only moved up. SKAN 3 added did-win false copies for installs. AdAttributionKit install conversions still have a winner and up to five nonwinning networks. Re-engagement does not. The framework does not generate runner-up postbacks for reengagements.

A did-win false row on a reengagement conversion is how two networks both look credited and neither matches Apple. WWDC25 added conversion tags and overlapping conversions on iOS 18.4. Those are bookmarks for concurrent re-engagement windows. They are not campaign-id. That is the news. SKAN still interoperates for installs. It does not describe this conversion.

Installs in 17.4, click re-engagement in 18

AdAttributionKit launched with iOS 17.4 and included support for install conversions. WWDC25 said that in one sentence, then: re-engagement support arrived with iOS 18. Apple's Ad Attribution page says App AdAttributionKit attributes installations based on clicks or views in iOS 17.4 and iPadOS 17.4 or later. Click-through install: 30 days to install. View-through install: 24 hours. Re-engagement information is iOS 18 and iPadOS 18 or later, click-through, so you can measure when users open the app after they already have it.

The receiving-ad-attributions page is stricter on re-engagement mechanics. Reengagement conversions occur when someone already has the advertised app installed and taps a custom rendered ad, or taps Open on a StoreKit rendered ad. Reengagement only involves the impression that drives the conversion, so there are no nonwinning postbacks. The system only processes reengagement conversions as a result of click interactions. It does not create reengagement postbacks from view-through ads.

Time windows differ by conversion type. After an install, the device has 60 days to send the first conversion value update. After a reengagement, it has 2 days. Minimum time to receive a postback is still 24 to 48 hours after the conversion value path, same order of magnitude as SKAN. Developer Mode can shrink that to 5 to 10 minutes in testing. Production re-engagement is not a SKAN 2 immediate campaign ping, and it is not a view-through install with a 24-hour view window pasted onto an open.

did-win false is an install story

For install conversions, AdAttributionKit represents postbacks as download or redownload in conversion-type. When multiple impressions qualify, the device sorts them and selects one winner. The system considers impressions from both AdAttributionKit and SKAdNetwork. Install conversions produce winning postbacks if there is a qualifying impression, subject to crowd anonymity. Each ad network receives only one postback, winning or nonwinning. Up to five other networks receive one nonwinning postback each. Sort is recency plus click-through versus view-through. Click-through takes precedence.

The overview page says the same thing in the install diagram: one network gets did-win true across multiple conversion windows. Up to five others get did-win false if they qualified and lost. Then the reengagement sentence: a single ad network may receive winning postbacks in multiple conversion windows. The framework does not generate runner-up postbacks for reengagements. Copying a SKAN 3 runner-up table onto conversion-type reengagement is a join Apple will never send.

The system does not always produce postbacks after a reengagement. The device is subject to reengagement limits on a monthly per-app basis and a yearly per-device basis. Apple does not publish those integers as a developer-tunable quota on the page I fetched. The URL parameter is still present even when postbacks are not created. Counting AdAttributionKitReengagementOpen hits as conversions is a different number from postbacks received.

Overlapping windows need conversion tags, not campaign-id

Until iOS 18.3, an app could have only one active re-engagement conversion at a time. As of iOS 18.4, multiple active re-engagement windows can overlap. Conversion tags act as bookmarks that specify which re-engagement to update. WWDC25's example is two discount ads: the user taps discount 1, leaves, taps discount 2, then purchases discount 1. Without a tag, the update hits the most recent conversion. That is the pre-18.4 behavior, and it is still what happens if you omit conversionTag.

Opt in with EligibleForAdAttributionKitOverlappingConversions set to YES in Info.plist. Without that key, prior conversions continue to lock when they overlap, as they did before. Once opted in, conversion tags are appended to the re-engagement URL. The tag is the value of AdAttributionKit's re-engagement open parameter, AdAttributionKitReengagementOpen. Persist the tag with your own internal id. The internal identifier is bookkeeping. It has no role in the API.

PostbackUpdate in iOS 18.4 accepts an optional conversionTag string. Pass it into updateConversionValue. If the framework finds that conversion, it updates it. If you do not specify a tag, AdAttributionKit updates the most recent conversion. You can also target conversion types: install versus reengagement. If you pass nil, or use an API without conversion types, the system defaults to updating all types. A SKAN 2 mapper that only knows campaign-id and a rising 0-63 has nowhere to put a tag, no overlap flag, and no conversion-type filter.

A new reengagement while another conversion is active locks the prior postbacks and schedules them. Unregistered postbacks from the prior conversion are removed and replaced by the latest. That is not SKAN 2's rolling 24-hour timer, and it is not SKAN 4's three install windows. Publisher apps in iOS 18 can pass a reengagement URL. The system opens it if the app is installed and the URL is a registered universal link, then appends AdAttributionKitReengagementOpen. Known tracking parameters are stripped before delivery.

The postback people will store first

A SKAN 2 campaign-id plus a SKAN 3 runner-up flag on an AdAttributionKit re-engagement. Apple does not send that mix.

{
  "version": "2.0",
  "campaign-id": 42,
  "conversion-value": 7,
  "did-win": false,
  "conversion-type": "reengagement"
}

That object is what a SKAN 2 warehouse plus a new enum produces. SKAN 2 did not have conversion-type reengagement. SKAN 3 did-win false is an install also-ran. AdAttributionKit re-engagement has no runner-up postbacks. campaign-id is not source-identifier, and it is not a conversion tag. Fine 0-63 still exists for AdAttributionKit the way it does for SKAN: up to 64 signals on an install notification, crowd anonymity permitting. It is not a license to keep SKAN 2 monotonic rules on a reengagement window.

If a person taps a re-engagement ad and the monthly or yearly limit has already fired, the open parameter is still on the URL and the postback may not exist. Downstream MMP 'reinstall' rows that fire on the URL parameter alone will not match the ad network's postback table. Those two pipes are supposed to disagree in that case. Apple said so.

Names that do not translate

SKAN still interoperates. It does not map this

Apple documents interoperability instead of a hard cutover. AdAttributionKit works with the App Store and alternative marketplaces. SKAdNetwork works with the App Store. If the ad network uses both, the advertised app calls both update APIs. If there are no pending postbacks, both calls are ignored. .adattributionkit and .skadnetwork ad network IDs work across both. Only one impression wins a conversion. Clicks beat views. Recency sorts the rest. A maximum of six impressions are considered.

SKAN updatePostbackConversionValue can bridge by mirroring into AdAttributionKit. That bridge is for conversion value updates, not a way to attach did-win false re-engagement copies. WWDC25 closed by saying if you are using SKAdNetwork, now is a great time to migrate to AdAttributionKit. That is Apple's recommendation. The SKAN 4 field list still exists. Re-engagement in AdAttributionKit is still not a SKAN 2 mapping exercise.

You do not need App Tracking Transparency to call AdAttributionKit APIs. You still need ATT if the app tracks. Apple's ad attribution FAQ forbids fingerprinting in conjunction with AdAttributionKit. An MMP that fills missing re-engagement postbacks from device graph fields is not completing Apple's schema.

What developers actually opt into

Winning postback copies go to AttributionCopyEndpoint when the advertised app opts in. Re-engagement copies need a second Info.plist flag: opt in for reengagement postback copies. The developer copy is an exact copy of the winning postback, sent at the same time as the network's. It is not a runner-up. It is not a SKAN 2 developer postback from iOS 15 with a new conversion-type stamped on.

iOS 18.4 also added development postbacks in Settings, under Ad Attribution Testing, so you can test conversion updates from Xcode or ad-hoc builds without a publisher ad. Those postbacks use development.adattributionkit as the ad network identifier. Do not train production MMP mappings on that id.

Reengagement only involves the impression that drives the conversion, so there are no nonwinning postbacks. Additionally, the system only processes reengagement conversions as a result of click interactions on ads. The system does not create reengagement postbacks from view-through ads.

Apple: Receiving ad attributions and postbacks

What to do

Keep install and re-engagement as different internal events. Persist conversion-type, did-win only on installs, conversion tags from AdAttributionKitReengagementOpen, and SKAN postbacks in a separate table. On iOS 18.4, set EligibleForAdAttributionKitOverlappingConversions if you run concurrent re-engagement campaigns, extract the tag on open, and pass conversionTag on PostbackUpdate. Count URL opens and postbacks separately when limits apply.

Do not reuse a SKAN 2 campaign-id plus conversion-value mapper. Lint the postback you store against AdAttributionKit's identifying-parameters docs, not against a SKAN 2 fixture. Apple's SKAN page still exists and still interoperates. Re-engagement is the AdAttributionKit hop.

This post is the market fact: AdAttributionKit re-engagement has no runner-up postbacks, and SKAN 2 mappings do not apply. 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 open, and it does not detect fraud.

Checklist

Sources

Contract pages

The dated argument is above. These pages are the field lists.

Read SKAN Docs