Renewal events ideally come from a server-side webhook (App Store Server Notifications, Google Play RTDN, RevenueCat webhooks). Client-side StoreKit listeners can also fire on renewal but only when the user opens the app — your backend webhook is more reliable. Use one path or the other, not both.
▸Install the Flutter SDK
# 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
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
// Server-side Dart handler for RevenueCat webhook:
import 'package:shelf/shelf.dart';
Future<Response> renewalWebhook(Request req) async {
final body = jsonDecode(await req.readAsString()) as Map<String, dynamic>;
final event = body['event'] as Map<String, dynamic>;
if (event['type'] == 'RENEWAL') {
await respectlyticsServerClient.track(
eventName: 'subscription_renewed',
platform: event['store'] == 'APP_STORE' ? 'ios' : 'android',
country: event['country_code'] as String?,
);
}
return Response.ok('');
}
The Flutter Respectlytics package is for client-side use. Server-side handlers use a generic HTTP client to call the REST API directly.
✦Privacy & implementation notes
Background renewals don't open the app. If you instrument renewal only in your client-side StoreKit listener, you'll miss every renewal where the user doesn't happen to open the app within a few days. Server-side from a billing webhook is the reliable path — fire it via Respectlytics's REST API.
Use Respectlytics for renewal rate by country / platform / plan, and your billing system for MRR. The rate is what tells you whether a product change is moving retention; the dollar number is what your finance team wants. They're the same conceptually but operationally separate.
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
| Subscription renewal | Firebase Analytics | Mixpanel | Respectlytics |
|---|---|---|---|
| Per-user MRR attribution | Yes | Yes | No (use billing system) |
| Plan tier as parameter | Recommended | Recommended | Use distinct event_name |
| Renewal count (1st, 2nd, …) as parameter | Recommended | Recommended | Out of scope |
| Per-cohort retention curve | Per-user | Per-user | Use billing system |
| Renewal *rate* by country / platform | Yes | Yes | Yes (default aggregation) |
❓Frequently asked questions
Should we fire renewal events client-side or server-side?
Server-side, ideally — billing webhooks are authoritative and don't depend on the user opening the app. Use the Respectlytics REST API from your webhook handler, with the same event_name a client would have used.
What's the right event name when we have multiple plan tiers?
Distinct names per tier: subscription_renewed_basic, subscription_renewed_pro. The aggregation gives you per-tier renewal rate. Don't pass the tier as a custom parameter — the API rejects it.
Do we still need event-level renewal tracking if we have billing webhooks?
Maybe not. If your only renewal questions are "how many renewed and how much did they pay", your billing system is enough. Respectlytics adds value when you want to correlate in-app behavior (engagement events, feature usage) with renewal — that needs a session-scoped signal.
What about renewals after a brief lapse (grace period)?
Apple and Google have explicit grace-period states. If you fire renewal events for them, use a distinct name: subscription_renewed_after_grace. Distinguish them downstream because their behavior is different.