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 eventFirebase AnalyticsMixpanelRespectlytics
Device push token storedYes (FCM token in user property)Yes (in profile)Never
Per-user opt-in stateYesYesOut of scope (your push backend tracks this)
Prompt timing as event propertyRecommendedRecommendedUse distinct event_name
iOS provisional opt-in distinguishableManual (via param)Manual (via property)Use distinct event_name (push_provisional_optin)
Opt-in rate by country / platformYesYesYes (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.