Respectlytics Respect lytics
Menu
Kotlin (Android) Subscription cancellation Privacy-first

How to track subscription cancellations in Kotlin (Android) 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 Kotlin (Android), 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 Kotlin (Android) SDK

kotlin Respectlytics
// build.gradle.kts (app module)
dependencies {
    implementation("com.respectlytics:respectlytics-kotlin:3.0.0")
}

Pure Kotlin coroutines implementation. No Java dependencies, no Google Play Services dependencies. ~300KB DEX overhead — compare to roughly 3.8MB for Firebase Analytics (a measurable cold-start improvement on lower-end devices).

Initialize Respectlytics in Kotlin (Android)

kotlin Respectlytics
import com.respectlytics.android.Respectlytics

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        Respectlytics.configure(this, appKey = "<YOUR_APP_KEY>")
    }
}

Initialize once in Application.onCreate. No additional permissions in the manifest — INTERNET is sufficient. The SDK does not request AD_ID, does not query AdvertisingIdClient, and does not declare ACCESS_NETWORK_STATE.

Track the event in Kotlin (Android)

kotlin Respectlytics
import android.content.Intent
import android.net.Uri
import com.respectlytics.android.Respectlytics

fun openSubscriptionManagement(context: Context, sku: String, packageName: String) {
    Respectlytics.track("subscription_cancel_initiated")
    // Deep-link to Google Play's subscription management:
    val uri = Uri.parse("https://play.google.com/store/account/subscriptions?sku=$sku&package=$packageName")
    context.startActivity(Intent(Intent.ACTION_VIEW, uri))
}

Effective cancellation fires from your server via Google Play RTDN's SUBSCRIPTION_CANCELED. Pass event_name = "subscription_cancelled" in that handler.

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.

Many teams discover the com.google.android.gms.permission.AD_ID permission in their merged manifest only after Google Play flags them — usually because a transitive dependency dragged it in. Respectlytics's Kotlin SDK has no Google Play Services dependency at all, so it cannot contribute to that merge.

The SDK is implemented as pure Kotlin coroutines with no Java sources, no RxJava, and no platform channels. Events are queued in a Channel<Event> buffered to a small ring (RAM-only), drained by a coroutine that flushes every 30 seconds or on backgrounding. There is no SharedPreferences usage.

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.