Respectlytics Respect lytics
Menu
Flutter Push notification opt-in Privacy-first

How to track push notification opt-in in Flutter 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 Flutter 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 Flutter, 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 Flutter SDK

yaml Respectlytics
# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  respectlytics_flutter: ^3.0.0

Pure Dart — no platform channels for analytics. Same code on every platform Flutter compiles to (iOS, Android, web, macOS, Windows, Linux). On web, events are sent via the REST API; mobile platforms use the same path.

Initialize Respectlytics in Flutter

dart Respectlytics
import 'package:flutter/material.dart';
import 'package:respectlytics_flutter/respectlytics_flutter.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Respectlytics.configure(appKey: '<YOUR_APP_KEY>');
  runApp(const MyApp());
}

Initialize in `main()` after `WidgetsFlutterBinding.ensureInitialized()` and before `runApp()`. The future completes immediately on configuration; events queued before completion are flushed once the network is available.

Track the event in Flutter

dart Respectlytics
import 'package:respectlytics_flutter/respectlytics_flutter.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

Future<void> requestPushPermission() async {
  final settings = await FirebaseMessaging.instance.requestPermission(
    alert: true, badge: true, sound: true,
  );
  switch (settings.authorizationStatus) {
    case AuthorizationStatus.authorized:
      Respectlytics.track('push_optin');
    case AuthorizationStatus.provisional:
      Respectlytics.track('push_provisional_optin');
    case AuthorizationStatus.denied:
      Respectlytics.track('push_decline');
    case AuthorizationStatus.notDetermined:
      // Don't emit — user hasn't been asked.
      break;
  }
}

If you use a non-Firebase push provider (e.g. `flutter_local_notifications` + your own server), the same status flow applies — request permission, branch on the result, emit one event name per branch.

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.

The Flutter SDK is pure Dart. No `MethodChannel`, no platform-specific iOS or Android plugin code. The same code runs on every platform Flutter supports — including web and desktop targets. This eliminates one common audit surface ("what's the Android implementation doing?").

Always initialize after `WidgetsFlutterBinding.ensureInitialized()` and before `runApp()`. If you skip the binding step, the configure call will throw on platforms that need a binding for asynchronous I/O. The SDK documentation example uses this pattern by default.

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.