$npx -y skills add rshankras/claude-code-apple-skills --skill ad-attributionPrivacy-preserving ad measurement with AdAttributionKit (SKAdNetwork's successor) — install and re-engagement attribution, conversion-value strategy under crowd anonymity, and end-to-end postback testing. Use when running paid acquisition beyond Apple Ads, measuring re-engagement
| 1 | # Ad Attribution (AdAttributionKit) |
| 2 | |
| 3 | You can't optimize paid traffic you can't measure. AdAttributionKit is Apple's |
| 4 | privacy-preserving attribution framework — interoperable with SKAdNetwork, and the go-forward |
| 5 | path (it also works in alternative marketplaces). This skill covers the *advertised-app* side: |
| 6 | what an indie running paid campaigns must implement and how to design conversion signals that |
| 7 | survive privacy thresholds. |
| 8 | |
| 9 | Note the seam: **Apple Ads attribution uses the AdServices framework, not AdAttributionKit** — |
| 10 | campaigns there are measured in the Apple Ads console (see `app-store/apple-search-ads`). This |
| 11 | skill is for every *other* paid channel (ad networks, social, publishers). |
| 12 | |
| 13 | ## When This Skill Activates |
| 14 | |
| 15 | - Running or planning paid user acquisition outside Apple Ads |
| 16 | - "How do I know which campaign drove installs?" / measuring re-engagement ads |
| 17 | - Designing or debugging conversion values / postbacks |
| 18 | - Migrating from SKAdNetwork (fully interoperable — registered networks need no re-enrollment) |
| 19 | |
| 20 | ## How it works (the 60-second model) |
| 21 | |
| 22 | Ad network signs an ad (compact JWS impression) → publisher app shows it → user installs (or |
| 23 | re-engages) → after a privacy-delayed measurement window, a **postback** with your conversion |
| 24 | info goes to the ad network (and optionally to you). Attribution requires no user tracking; |
| 25 | the price is coarser data, governed by **crowd anonymity**. |
| 26 | |
| 27 | ## Conversion-value strategy (the part that's actually yours) |
| 28 | |
| 29 | - Two granularities: **fine value 0–63** and **coarse low/medium/high**. Low crowd sizes |
| 30 | downgrade fine → coarse and can trim the 4-digit campaign `source-identifier` to as few as |
| 31 | its **first 2 digits** — so encode what matters most (campaign family, geo tier) in the |
| 32 | first two digits, detail in the rest. |
| 33 | - Map values to *revenue-predictive* early behavior (completed onboarding, trial start, first |
| 34 | purchase), not vanity events. 64 slots go fast; reserve ranges (e.g. 0–15 activation, |
| 35 | 16–47 monetization ladder, 48–63 reserved). |
| 36 | - Update with `updateConversionValue(_:)` / `PostbackUpdate`; set `lockPostback` when the value |
| 37 | is final to schedule transmission (still privacy-delayed, never instant). |
| 38 | - Re-engagement postbacks are separate from install postbacks: update them independently via |
| 39 | `conversionTypes` (.install / .reengagement); the **first re-engagement update must land |
| 40 | within 48 hours**. |
| 41 | - Multiple simultaneous re-engagement campaigns need **conversion tags** (iOS 18.4+): read the |
| 42 | tag from the re-engagement URL's query items, store it, and pass it in `PostbackUpdate` — |
| 43 | without a tag, updates hit only the most recent conversion. |
| 44 | |
| 45 | ## Publisher-side mechanics (if your app also *shows* ads) |
| 46 | |
| 47 | - Click-through: `UIEventAttributionView` over the tappable ad + `appImpression.handleTap()` |
| 48 | within **15 minutes** of creating the impression. |
| 49 | - View-through: `beginView()`/`endView()` on the same instance; **≥2 seconds** on screen to |
| 50 | count; one open view-through per network per advertised app. |
| 51 | - `SKOverlay` / `SKStoreProductViewController`: attach the impression — they count view on |
| 52 | present, click on tap. |
| 53 | |
| 54 | ## Attribution windows & cooldowns (iOS 18.4+ configurability) |
| 55 | |
| 56 | - Defaults: **30 days click-through, 1 day view-through** (install ads). |
| 57 | - Override per ad network and interaction type in Info.plist |
| 58 | (`AdAttributionKitConfigurations` → `AttributionWindows`); you can ignore "view" or "click" |
| 59 | (not both) per network. |
| 60 | - Set **cooldowns** (`install-cooldown-hours`, `reengagement-cooldown-hours`) so a |
| 61 | re-engagement tap minutes after an install isn't double-attributed. |
| 62 | - Country-level postback data (iOS 18.4): storefront country at install, gated behind an extra |
| 63 | crowd-anonymity tier — a bonus signal when volume allows, never guaranteed. |
| 64 | - Overlapping re-engagement conversions require opting in: |
| 65 | `EligibleForAdAttributionKitOverlappingConversions` = YES in Info.plist. |
| 66 | |
| 67 | ## Testing — never ship blind |
| 68 | |
| 69 | - **Developer Mode → Settings → Developer → Ad Attribution Testing**: removes time |
| 70 | randomization, shortens all conversion windows, sends postbacks on demand — full end-to-end |
| 71 | rehearsal in minutes instead of days. |
| 72 | - Point development postbacks at a **separate dev endpoint**, never production: they're signed |
| 73 | with a different key (`kid`), the network ID is always `development.adattributionkit`, and |
| 74 | the advertised item ID may be 0 from Xcode. |
| 75 | - ✅ Verify the postback pipeline before spending a dollar. ❌ Debugging attribution *after* |
| 76 | a live campaign burns bu |