ReflectDocs
Browse docsOverview
Unity SDK · iOS

SKAN & AdAttributionKit

Two Apple-mediated attribution frameworks on iOS. SKAdNetwork (SKAN) on iOS 15-17.3, AdAttributionKit (AAK) on iOS 17.4+. The SDK's job is the same for both — update the conversion value at meaningful in-app moments. Reflect handles the postback receipt, signature verification, and decoding server-side.

What is SKAN?

SKAdNetwork (SKAN) is Apple's privacy-preserving install attribution framework. Ad networks receive postbacks from iOS with a conversion value (0-63) that encodes post-install behavior (revenue tier, level reached, etc.). Reflect handles postback receipt and decoding server-side — the SDK's job is to update the conversion value at the right moments in your app.

AdAttributionKit (iOS 17.4+)

AdAttributionKit (AAK) is Apple's successor to SKAN, default on iOS 17.4+ and now the dominant attribution path for >50% of iOS installs. AAK extends SKAN with four conversion windows, signed JWT postbacks, re-engagement support, and a new source-domain field for web-to-app attribution. The SDK API is unchanged — ReflectSDK.UpdateConversionValue(…) writes to whichever framework iOS exposes — but the postback path differs server-side.

How AAK differs from SKAN

AspectSKAN 4.0AdAttributionKit
iOS version15.0+ (4.0 features on 16.1+)17.4+
Postback signatureApple-signed JSON (attribution-signature field)JWS (ES256-signed JWT compact form)
Conversion windows3 (0-2h, 2-72h, 72-360h)4 (configurable, plus an explicit lock-window flag)
Re-engagementNot supportedSupported (re-engagement: true in payload)
Web-to-appLimitedFirst-class via source-domain
Postback URL fieldNSAdvertisingAttributionReportEndpoint in Info.plistSame Info.plist key, separate registration on Apple side

Postback endpoint

Reflect receives AAK postbacks at:

POST https://api.reflect.cloud/aak-postback Content-Type: application/jwt Body: <compact JWS — header.payload.signature>

Reflect verifies the JWS against Apple's published ES256 keys (JWKS fetched + KV-cached for 1h), persists the full raw JWT plus the decoded payload, and resolves the install destination via publisher-app-id → apps.store_id. Postbacks for unresolved apps are still saved to R2 audit for later backfill.

How to register Reflect for your app's AAK postbacks

  1. In your Info.plist, set NSAdvertisingAttributionReportEndpoint to https://api.reflect.cloud (the path /aak-postback is appended by Apple).
  2. If you also use SKAN (iOS 15-17.3 devices in your install base), keep the existing SKAN postback URL registered alongside — Apple sends to both endpoints based on device version. Reflect handles both at /skan-postback and /aak-postback.
  3. In your app's SKAN → CV Schema page in the admin panel, define how to decode the 0-63 fine-conversion-value back into revenue tiers / engagement levels. The schema applies to both SKAN and AAK postbacks (the fine value semantics are identical).
  4. Within ~24 hours of your first AAK install, postbacks land in the SKAN/AAK dashboard under your app. The reporting UI distinguishes SKAN rows from AAK rows so you can compare windows.
iOS 17.4+ users now default to AAK
If your install base is iOS-heavy and you don't yet have an AAK postback URL registered, you're losing attribution data on every iOS 17.4+ install. SKAN postbacks continue for older devices but the volume shrinks every quarter as users upgrade.

API

// Simple — just a fine value (0-63)
ReflectSDK.UpdateConversionValue(12);

// Full — fine value + coarse + lock window + callback
ReflectSDK.UpdateConversionValue(
    fineValue:   42,
    coarseValue: "high",        // "low", "medium", "high", or null
    lockWindow:  false,         // true = lock the current postback window
    onComplete:  (ok, err) => {
        if (!ok) Debug.LogWarning("SKAN update failed: " + err);
    }
);

Platform behavior

PlatformBehavior
iOS 17.4+Uses AdAttributionKit (Apple's successor to SKAN)
iOS 16.1+Uses SKAdNetwork 4.0 — supports fine value, coarse value, and lock window
iOS 15.xLegacy SKAN — fine value only, coarse value ignored
Android / EditorNo-op (Editor logs the call for debugging)

When to call it

Call UpdateConversionValue whenever the user crosses a meaningful threshold:

// Example: encode revenue tiers
void OnPurchase(double revenueUsd) {
    int cv = revenueUsd >= 50 ? 63
           : revenueUsd >= 20 ? 48
           : revenueUsd >= 10 ? 32
           : revenueUsd >= 5  ? 16
           : revenueUsd >= 1  ? 8
           : 4;
    ReflectSDK.UpdateConversionValue(cv, coarseValue: cv >= 32 ? "high" : "medium");
}

// Example: encode level progress
void OnLevelComplete(int level) {
    int cv = Math.Min(level, 63);
    ReflectSDK.UpdateConversionValue(cv);
}

Conversion value schema (admin)

In the admin panel, go to SKAN → CV Schema to define how Reflect decodes the 0-63 value back into human-readable metrics (revenue ranges, engagement tiers). This mapping is used when displaying SKAN reports and doesn't affect the SDK.

SKAN is complementary to Reflect's own attribution
Reflect attributes installs using deterministic (Play Referrer / AdServices) and fingerprint methods. SKAN postbacks provide an independent, Apple-verified signal. Use both: Reflect for real-time granular data, SKAN for privacy-safe validation and networks that only support SKAN.