Respectlytics Respect lytics
Menu
Swift (iOS) Subscription cancellation Privacy-first

How to track subscription cancellations in Swift (iOS) without personal data

Subscription cancel is the cleanest churn event you can collect — and the most tempting place to attach "reason for cancelling" survey responses, which always balloon into free-text PII. Respectlytics helps developers avoid collecting personal data in the first place: in Swift (iOS), cancel is one named event. Cancellation reason belongs in your customer-support tooling, not your analytics pipeline. Below: where to fire, how to compute churn rate, and the survey trap.

Like renewals, cancellation events ideally come from your billing system's webhooks. Cancellation initiated in your app (a settings-screen "cancel subscription" CTA) is also fair game for a client-side fire, but use the same event_name so the two paths aggregate together.

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 StoreKit

// In a settings screen, when the user taps 'Manage Subscriptions':
Button("Cancel subscription") {
    // The user is *initiating* cancel — actual cancellation may happen on the App Store.
    Respectlytics.track("subscription_cancel_initiated")

    // Open the App Store subscription management screen:
    if let url = URL(string: "https://apps.apple.com/account/subscriptions") {
        UIApplication.shared.open(url)
    }
}

The actual subscription_cancelled event (effective at billing-period end) should fire from your backend on App Store Server Notification V2's DID_CHANGE_RENEWAL_STATUS.

Privacy & implementation notes

Free-text cancellation surveys produce two outputs: useful product insight, and PII soup ("my name is X and I'm leaving because…"). Respectlytics's API rejects free-text fields outright — survey responses belong in a customer-support tool with proper retention controls and access policies, not in analytics.

Cancel-initiated and cancel-effective are different events with different product implications. Conflating them under one subscription_cancelled event loses the save-rate signal between them — typically the most actionable churn metric a subscription product has.

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

Subscription cancel eventFirebase AnalyticsMixpanelRespectlytics
Cancellation reason as parameterRecommendedRecommendedUse distinct event_name
Free-text reason / feedback surveyCommonCommonForbidden (PII)
Per-user identityYesYesNever
Cancel-then-resubscribe linkagePer-userPer-user (Identity Merging)Out of scope
Churn *rate* by country / platformYesYesYes (default aggregation)

Frequently asked questions

How do we know *why* users cancel without storing reasons?

Two layers. For quantitative reasons (tier, payment-method failure, platform), use distinct event names: subscription_cancelled_voluntary, subscription_cancelled_payment_failed. For qualitative reasons ("feature X was missing"), run a customer-support intake — that's not analytics' job.

Should we fire when the user *initiates* cancel, or when it actually takes effect?

Both, with distinct event names: subscription_cancel_initiated (immediate intent signal) and subscription_cancelled (effective at billing-period end). Some teams convince ~10% of initiated-cancels to stay; the funnel between the two events is your save rate.

What about involuntary cancels (failed payment, account closed)?

Distinct event name: subscription_cancelled_involuntary. The reasons differ fundamentally from voluntary cancels, and so do the product responses (you might dunning-retry payment-failed, but not voluntary).

Do we still need this in Respectlytics if our billing system has cancellation data?

Yes — for in-app correlations. "What feature did users last touch before initiating cancel?" needs both the cancellation event and other in-app events in the same analytics pipeline. Your billing system can't answer that.

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.