Respectlytics Respect lytics
Menu
Kotlin (Android) Notification permission granted Privacy-first

How to track notification permission grants in Kotlin (Android) without personal data

Notification permission outcomes — beyond the simple opt-in moment — include OS-level permission revocations, deferred prompts, and provisional grants. Respectlytics helps developers avoid collecting personal data in the first place: in Kotlin (Android), each permission outcome is its own named event, fired at the moment the system delivers the result. Below: how to wire the call to platform-specific permission callbacks, how to distinguish the states, and what to leave to your push-delivery backend.

Wire each callback path to its own event_name: granted, denied, provisional, deferred. The platform permission API delivers the result asynchronously — fire on the result, not on the request.

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.Manifest
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import androidx.core.content.ContextCompat
import com.respectlytics.android.Respectlytics

fun reportPermissionState(context: Context) {
    val nm = ContextCompat.getSystemService(context, NotificationManager::class.java)!!
    val isGranted = if (Build.VERSION.SDK_INT >= 33) {
        ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) ==
            android.content.pm.PackageManager.PERMISSION_GRANTED
    } else nm.areNotificationsEnabled()
    Respectlytics.track(if (isGranted) "push_optin" else "push_decline")
}

Android 13+ requires POST_NOTIFICATIONS; pre-13 reads notification-channel state via areNotificationsEnabled(). Both are checked here.

Privacy & implementation notes

Notification permission state is asymmetric: granting and revoking go through different OS pathways. Granting fires through your prompt callback; revoking happens silently in Settings, with no event delivered to your app. Detect revocation lazily on next foreground if you need it.

If you prompt at multiple points in the funnel (onboarding, post-first-session, after key feature), use distinct event names per timing — push_prompt_at_onboarding, push_prompt_post_session. Conversion-rate-by-timing falls out of session-grouped event counts.

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

Notification permission eventFirebase AnalyticsMixpanelRespectlytics
Per-user permission stateYes (user property)Yes (profile)Out of scope
Push token / FCM ID storedYesYesNever
Permission outcome states distinguishableManual (params)Manual (params)Distinct event_name per outcome
Time-to-grant after first promptPer-userPer-userSession-scoped

Frequently asked questions

Should we track when the user revokes permission later?

Hard to detect reliably from the app. The OS doesn't deliver an explicit revocation event — you only learn at the next foreground when getNotificationSettings() returns denied. If you do detect it, fire push_revoked_detected (with no metadata) and use it for rate analysis only.

What's the right event for re-prompting after a deferred decision?

If you prompt twice, fire distinct events for each prompt: push_prompt_v1, push_prompt_v2. Apple and Google both have anti-spam policies — a second prompt is allowed only after meaningful product context, and you should instrument that decision point.

How does this differ from `push-opt-in`?

push-opt-in is the narrow event that fires on grant. notification-permission is the broader category that includes all permission outcomes — granted, denied, provisional, deferred, revoked. Use both, with non-overlapping event names per outcome.

What about silent / background-only notification capability?

On iOS, notification permission is independent from background-fetch capability. On Android 13+, POST_NOTIFICATIONS is required for visible notifications regardless of background fetch. If you care about background-only delivery, fire a separate push_background_only event when relevant.

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.