Respectlytics Respect lytics
Menu
Swift (iOS) Push notification opt-in Privacy-first

How to track push notification opt-in in Swift (iOS) without personal data

Push opt-in rate is one of the highest-leverage signals in mobile analytics: it gates every re-engagement channel you have. Respectlytics helps developers avoid collecting personal data in the first place: the opt-in event in Swift (iOS) is just `push_optin` — no device token, no APNs identifier, no Firebase Cloud Messaging registration ID. Below: how to wire the call into the system permission callback on Swift (iOS), how to A/B-test prompt timing without per-user assignment, and the trade-off you make by not storing a per-user opt-in state.

Wire the call into the same callback that receives the system permission result. On success, emit `push_optin`. If you also want to measure declines (most teams do), emit `push_decline` on the negative result. Don't pass the device token or any registration ID as metadata — your push backend already has those.

Install the Swift (iOS) SDK

swift Respectlytics
// Package.swift
dependencies: [
    .package(url: "https://github.com/respectlytics/respectlytics-swift.git", from: "3.0.0")
]
// Or via Xcode → File → Add Packages → paste the URL above.

The SDK ships only via Swift Package Manager. CocoaPods and Carthage are not published — fewer integration paths means fewer surfaces to keep audited.

Initialize Respectlytics in Swift (iOS)

swift Respectlytics
import Respectlytics

@main
struct MyApp: App {
    init() {
        Respectlytics.configure(appKey: "<YOUR_APP_KEY>")
    }
    var body: some Scene { WindowGroup { ContentView() } }
}

Call `configure` once at app launch — typically in your `App` struct's `init`. No `Info.plist` keys are required: the SDK does not call ATTrackingManager and does not request the IDFA, so `NSUserTrackingUsageDescription` should NOT be added.

Track the event in Swift (iOS)

swift Respectlytics
import Respectlytics
import UserNotifications

func requestPushPermission() {
    let center = UNUserNotificationCenter.current()
    center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, _ in
        Respectlytics.track(granted ? "push_optin" : "push_decline")
    }
}

// For provisional authorization:
func requestProvisionalPush() {
    UNUserNotificationCenter.current().requestAuthorization(options: [.provisional, .alert]) { granted, _ in
        if granted { Respectlytics.track("push_provisional_optin") }
    }
}

Provisional authorization is iOS 12+. Distinguish it explicitly with its own event name — its downstream behavior (silent delivery, no prompt) is meaningfully different from explicit opt-in.

Privacy & implementation notes

Your push-delivery backend (APNs, FCM, OneSignal, Pusher Beams, etc.) already has the device push token — that's where it lives operationally. Sending it to Respectlytics would just be re-creating a per-user dataset you've already built elsewhere. The API rejects it.

Most push-related product decisions are about *rate*, not *state*: "does moving the prompt to post-onboarding move our DE iOS opt-in rate?". You don't need per-user opt-in state in your analytics pipeline to answer that — you need session-grouped event counts.

Apple rejected approximately 3% of apps in 2024 for incorrectly omitting `NSUserTrackingUsageDescription` when ATT was required by the SDKs they shipped. Respectlytics doesn't trigger ATT. The corollary is also true: do not add the key on Respectlytics's account — its presence implies you track across apps, even if your code never calls `requestTrackingAuthorization`.

Internally the Swift SDK uses Swift Concurrency: events are queued in an actor-isolated buffer (RAM-only), flushed on a 30-second timer and on `UIApplication.willResignActiveNotification`. Force-quit before flush drops queued events — by design. There is no UserDefaults or file backing.

How this compares to other analytics SDKs

Push opt-in event Firebase Analytics Mixpanel Respectlytics
Device push token stored Yes (FCM token in user property) Yes (in profile) Never
Per-user opt-in state Yes Yes Out of scope (your push backend tracks this)
Prompt timing as event property Recommended Recommended Use distinct event_name
iOS provisional opt-in distinguishable Manual (via param) Manual (via property) Use distinct event_name (push_provisional_optin)
Opt-in rate by country / platform Yes Yes Yes (default aggregation)

Frequently asked questions

How do we know which users opted in if we don't store user state?

You don't, in your analytics. Your push-delivery backend (APNs, FCM, OneSignal, etc.) already has the authoritative opt-in state per device token — that's its job. Respectlytics tells you the opt-in *rate* over sessions, which is the metric you optimize for product decisions.

Can we A/B-test opt-in prompt timing?

Yes — emit distinct event names per prompt-timing variant: `push_optin_at_onboarding`, `push_optin_post_first_session`, etc. The aggregation gives you per-variant conversion rate without any per-user assignment stored.

Should we track when the prompt was *shown* in addition to the result?

Yes, with two event names: `push_prompt_shown` and `push_optin` (or `push_decline`). The session-grouped count gives you prompt → grant rate directly.

What about iOS 15+ provisional authorization?

If you use `provisional` authorization (which doesn't show a prompt and delivers quietly until the user upgrades to full), emit `push_provisional_optin` as a distinct event. It's a different state with different downstream implications, so don't conflate it with the explicit opt-in event.

Related guides

Track what matters. Collect nothing you don't.

Five-field event schema, RAM-only event queue, no IDFA, no AAID, no persistent user IDs. Helps developers avoid collecting personal data in the first place.