Adattributionkit
Measure ad effectiveness with privacy-preserving attribution using AdAttributionKit. Use when registering ad impressions, handling attribution postbacks, updating conversion values, implementing re-engagement attribution, configuring publisher or advertiser apps, or replacing SKAdNetwork with AdAttributionKit for ad measurement.
- Skill ID
- dpearson2699/swift-ios-skills/adattributionkit
- Publisher
- dpearson2699
- Repository
- swift-ios-skills
- Installs
- 0
- Files
- 3
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
dpearson2699/swift-ios-skills/adattributionkitInstalls these files- SKILL.md
- evals/evals.json
- references/adattributionkit-patterns.md
What this skill tells the agent
AdAttributionKit
Privacy-preserving ad attribution for iOS 17.4+. AdAttributionKit lets ad networks measure conversions (installs and re-engagements) without exposing user-level data. It supports the App Store and alternative marketplaces, and interoperates with SKAdNetwork.
Three roles exist in the attribution flow: the ad network (signs impressions, receives postbacks), the publisher app (displays ads), and the advertised app (the app being promoted).
Contents
- Overview and Privacy Model
- Publisher App Setup
- Advertiser App Setup
- Impressions
- Postbacks
- Conversion Values
- Re-engagement
- Common Mistakes
- Review Checklist
- References
Overview and Privacy Model
AdAttributionKit preserves user privacy through several mechanisms:
- Crowd anonymity tiers -- the device limits postback data granularity based on the crowd size associated with the ad, ranging from Tier 0 (minimal data) to Tier 3 (most data including publisher ID and country code).
- Time-delayed postbacks -- postbacks are sent 24-48 hours after conversion window close (first window) or 24-144 hours (second/third windows).
- No user-level identifiers -- postbacks contain aggregate source identifiers and conversion values, not device or user IDs.
- Hierarchical source identifiers -- 2, 3, or 4-digit source IDs where the number of digits returned depends on the crowd anonymity tier.
In migration and interoperability reviews, explicitly state that the system evaluates AdAttributionKit and SKAdNetwork impressions together, only one impression wins per conversion, click-through beats view-through, and recency breaks ties within click-through impressions before falling back to the most recent view-through impression.
Publisher App Setup
A publisher app displays ads from registered ad networks. Add each ad network's ID to the app's Info.plist so its impressions qualify for install validation.
Add ad network identifiers
<key>AdNetworkIdentifiers</key>
<array>
<string>example123.adattributionkit</string>
<string>another456.adattributionkit</string>
</array>Ad network IDs must be lowercase. SKAdNetwork IDs (ending in .skadnetwork) are also accepted -- the frameworks share IDs.
Display a UIEventAttributionView
For click-through custom-rendered ads, place one UIEventAttributionView over each tappable ad/control. It must cover the tappable area and stay above views that would intercept touches before handleTap() succeeds.
import UIKit
let attributionView = UIEventAttributionView()
attributionView.frame = adContentView.bounds
attributionView.isUserInteractionEnabled = true
adContentView.addSubview(attributionView)Advertiser App Setup
The advertised app is the app someone installs or re-engages with after seeing an ad. It must call a conversion value update at least once to begin the postback conversion window.
Opt in to receive winning postback copies
Add AttributionCopyEndpoint under the top-level AdAttributionKit Info.plist dictionary so the device sends a copy of the winning postback to your server:
<key>AdAttributionKit</key>
<dict>
<key>AttributionCopyEndpoint</key>
<string>https://example.com</string>
</dict>The system derives the well-known endpoint from the registrable domain in the URL, ignoring subdomains:
https://example.com/.well-known/appattribution/report-attribution/Configure your server to accept HTTPS POST requests at that path. The domain must have a valid SSL certificate.
Opt in for re-engagement postback copies
Add a second key in the same AdAttributionKit dictionary to also receive copies of winning re-engagement postbacks:
<key>AdAttributionKit</key>
<dict>
<key>AttributionCopyEndpoint</key>
<string>https://example.com</string>
<key>OptInForReengagementPostbackCopies</key>
<true/>
</dict>Update conversion value on first launch
Call a conversion value update as early as possible after first launch to begin the conversion window:
import AdAttributionKit
func applicationDidFinishLaunching() async {
do {
try await Postback.updateConversionValue(0, lockPostback: false)
} catch {
print("Failed to set initial conversion value: \(error)")
}
}Impressions
Ad networks create signed impressions using JWS (JSON Web Signature). The publisher app uses AppImpression to register and handle those impressions.
Create an impression from a JWS
import AdAttributionKit
let impression = try await AppImpression(compactJWS: signedJWSString)The JWS contains the ad network ID, advertised item ID, publisher item ID, source identifier, timestamp, and optional re-engagement eligibility flag. See references/adattributionkit-patterns.md for JWS generation details.
Check device support
guard AppImpression.isSupported else {
// Fall back to alternative ad display
return
}View-through impressions
Record a view impression when the ad content has been displayed and dismissed:
func handleAdViewed(impression: AppImpression) async {
do {
try await impression.handleView()
} catch {
print("Failed to record view-through impression: \(error)")
}
}For long-lived ad views, use beginView() and endView() to track view duration:
try await impression.beginView()
// ... ad remains visible ...
try await impression.endView()Click-through impressions
Respond to ad taps by calling handleTap() within 15 minutes of creating the AppImpression; otherwise request a fresh impression. If the advertised app is not installed, the system opens its App Store or marketplace page. If installed, the system launches it directly.
func handleAdTapped(impression: AppImpression) async {
do {
try await impression.handleTap()
} catch {
print("Failed to record click-through impression: \(error)")
}
}A UIEventAttributionView must overlay the ad for handleTap() to succeed.
StoreKit-rendered ads
Pass the impression to StoreKit overlay or product view controller APIs. StoreKit automatically records view-through impressions after 2 seconds of display and click-through impressions on tap.
import StoreKit
let config = SKOverlay.AppConfiguration(appIdentifier: "1234567890",
position: .bottom)
config.appImpression = impressionPostbacks
Postbacks are attribution reports the device sends to ad networks (and optionally to the advertised app developer) after a conversion event.
Conversion windows
Winning attributions can produce multiple postbacks across conversion windows; lower data tiers and nonwinning attributions disclose less. Load references/adattributionkit-patterns.md for the current window and delay matrix.
Time windows for events
Attribution eligibility windows are distinct from conversion/postback windows. Configure and verify view-through, click-through, install-update, and re-engagement limits from the current documentation and the reference; do not merge the two concepts.
Lock conversion values early
Lock the postback to finalize a conversion value before the window ends and receive the postback sooner:
try await Postback.updateConversionValue(
42,
coarseConversionValue: .high,
lockPostback: true
)After locking, the system ignores further updates in that conversion window.
Postback data by tier
More from dpearson2699
Use this skill in a project
Open any RiverX project, search the Skills panel for dpearson2699/swift-ios-skills/adattributionkit, and install it in one click.
