iOS SDK

iOS SDK - Privacy & Consent

ATT helpers and GDPR / DMA consent for the Pricist iOS SDK.

The iOS SDK exposes two privacy primitives: App Tracking Transparency (ATT) helpers for Apple's IDFA prompt, and a setConsent API for GDPR / DMA. Both are opt-in — if you configure neither, the SDK tracks normally.

App Tracking Transparency (ATT)

Requesting authorization

requestTrackingAuthorization is a thin wrapper around ATTrackingManager.requestTrackingAuthorization. The SDK reads the resulting status itself — you do not need to pass it back:

import Pricist
 
Pricist.shared.requestTrackingAuthorization { status in
    switch status {
    case .authorized:    print("ATT granted")
    case .denied:        print("ATT denied")
    case .restricted:    print("ATT restricted (parental controls)")
    case .notDetermined: print("user dismissed without responding")
    @unknown default:    break
    }
}

Your Info.plist must contain an NSUserTrackingUsageDescription string. Without it, iOS will crash this call.

The live ATT status is attached to every event's context, so if the user changes the setting in iOS Settings later, subsequent events reflect the new value automatically.

Waiting for ATT before the first flush

The first events are the install / attribution signals — flushing them before the user has answered the ATT prompt means going out without IDFA, which weakens deterministic attribution. Set waitForATTAuthorization: true to defer the first flush:

let config = PricistConfiguration(sdkKey: "pk_live_…")
    .with(waitForATTAuthorization: true)
 
Pricist.shared.initialize(with: config)
 
// later, e.g. after onboarding:
Pricist.shared.requestTrackingAuthorization { _ in
    // SDK auto-resumes — events buffered while waiting flush now
}

While waiting, trackEvent(...) calls are buffered in memory (not dropped), and no flush happens until ATT is answered.

Pass a PricistConsent to record the user's decision. When GDPR applies and data-usage consent is denied, the SDK stops dispatching and purges its queue; otherwise consent rides along on each event's context:

Pricist.shared.setConsent(PricistConsent(
    isUserSubjectToGDPR: true,
    hasConsentForDataUsage: true
))

The struct also accepts two ad-network signals that mirror Google Consent Mode v2 (ad_personalization and ad_storage). They are forwarded to ad networks but do not gate dispatch:

Pricist.shared.setConsent(PricistConsent(
    isUserSubjectToGDPR: true,
    hasConsentForDataUsage: true,
    hasConsentForAdsPersonalization: false,
    hasConsentForAdStorage: true
))
FieldEffect on the SDK
isUserSubjectToGDPRWhen false, the per-dimension flags are advisory and the SDK tracks normally.
hasConsentForDataUsageWhen false and isUserSubjectToGDPR == true, the SDK stops dispatching and purges its local queue. A nil value is treated as "not yet answered" and does not block dispatch.
hasConsentForAdsPersonalizationForwarded to ad networks (Google ad_personalization). Does not gate dispatch.
hasConsentForAdStorageForwarded to ad networks (Google ad_storage). Does not gate dispatch.

When the user revokes consent (hasConsentForDataUsage: false with isUserSubjectToGDPR: true):

  • New trackEvent(...) calls are dropped.
  • Any pending events are purged from local storage.
  • Requests already in flight will finish.

To make the SDK do nothing until the user accepts a consent banner, use autoStart: false. The SDK wires up internal state but performs no network activity until you call start():

let config = PricistConfiguration(sdkKey: "pk_live_…")
    .with(autoStart: false)
 
Pricist.shared.initialize(with: config)
 
// after the user accepts your banner:
Pricist.shared.setConsent(PricistConsent(
    isUserSubjectToGDPR: true,
    hasConsentForDataUsage: true
))
Pricist.shared.start()