Fire on level-completion success — after the win-state animation begins, before any post-level dialog. Encode the level into the event name (level_complete_1, level_complete_2). Don't pass score, attempts, or duration.
▸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
import 'package:respectlytics_flutter/respectlytics_flutter.dart';
void reportLevelComplete(int levelNumber) {
if (levelNumber <= 50) {
Respectlytics.track('level_complete_$levelNumber');
} else {
final bucket = ((levelNumber - 1) ~/ 50) * 50 + 1;
Respectlytics.track('level_complete_${bucket}_${bucket + 49}');
}
}
Pair with level_failed_N events to surface difficulty walls — the failed/complete ratio per level is the highest-leverage games-product signal.
✦Privacy & implementation notes
Per-player progression — score curves, leaderboard positions, skill ratings, items inventory — lives in your game backend. That's where it has authority and where the gameplay logic reads from. Mirroring it into product analytics duplicates a system of record without adding signal you can't get from the game backend's own reporting.
Most game-product decisions are about rate ("is this level a difficulty wall for new players?") rather than skill ("how quickly does this player progress?"). The rate question is session-grouped. The skill question is per-player and lives in your game backend.
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
| Level complete event | Firebase Analytics | Mixpanel | GameAnalytics | Respectlytics |
|---|---|---|---|---|
| Level number as parameter | Yes | Yes | Yes | Use distinct event_name |
| Score stored | Recommended | Recommended | Yes | Out of scope (game backend) |
| Attempts to complete | Recommended | Recommended | Yes | Out of scope (game backend) |
| Time-to-complete | Recommended | Recommended | Yes | Server-side derivation |
| Per-player progression curve | Yes | Yes | Yes | Out of scope (game backend) |
❓Frequently asked questions
Won't we run out of distinct event names if we have 1000 levels?
For high-level-count games, bucket: level_complete_1_50, level_complete_51_100, etc. The Respectlytics aggregation handles either shape. Per-level granular progression is a game-backend signal — your leaderboards and skill-rating system already have it.
How do we measure difficulty without per-player attempts?
Per-session. The rate of sessions where level_complete_N follows level_complete_N-1 is your level-N completion rate. Country-bucketed and device-platform-bucketed shows where the difficulty cliff sits.
What about retries?
Distinct event name: level_failed_N. The rate of level_failed_N to level_complete_N over a session is your level-N retry signal.
Should we instrument every level individually?
If you have under 50 levels, yes — distinct event names per level. Past that, bucket. The principle is to keep your event-name taxonomy navigable; 1000 distinct level event names is functionally a parameter.