Fire the call at meaningful playback milestones: video_play_started, video_25pct_reached, video_50pct_reached, video_75pct_reached, video_completed. Don't pass video ID, content title, 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';
import 'package:video_player/video_player.dart';
class VideoMilestoneTracker {
final VideoPlayerController controller;
bool _m25 = false, _m50 = false, _m75 = false, _done = false;
VideoMilestoneTracker(this.controller) {
controller.addListener(_check);
}
void _check() {
final duration = controller.value.duration.inMilliseconds;
if (duration <= 0) return;
final progress = controller.value.position.inMilliseconds / duration;
if (progress >= 0.25 && !_m25) { _m25 = true; Respectlytics.track('video_25pct_reached'); }
if (progress >= 0.50 && !_m50) { _m50 = true; Respectlytics.track('video_50pct_reached'); }
if (progress >= 0.75 && !_m75) { _m75 = true; Respectlytics.track('video_75pct_reached'); }
if (progress >= 0.99 && !_done) { _done = true; Respectlytics.track('video_completed'); }
}
}
Construct one VideoMilestoneTracker per video — disposing one and constructing another resets the flags. Call controller.removeListener(_check) in dispose.
✦Privacy & implementation notes
Tracking exact playback position generates 30+ events per minute of viewing and dilutes every other signal in your analytics pipeline. Four milestones (25, 50, 75, 100%) per video carry essentially the same product signal at 1/100th the volume.
Your CMS already stores video titles, descriptions, durations, and content categories. Joining video_completed_movie events to your CMS's view-count-per-video data answers most product questions; storing the title as analytics metadata duplicates a system of record without adding signal.
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
| Video completion event | Firebase Analytics | Mixpanel | Respectlytics |
|---|---|---|---|
| Video ID as parameter | Recommended | Recommended | Forbidden (use top-N event_names) |
| Content category / genre | Recommended | Recommended | Use distinct event_name (top-N) |
| Watch duration in seconds | Recommended | Recommended | Out of scope (use milestones) |
| Per-user watch history | Yes | Yes | Out of scope (use content backend) |
| Completion *rate* by country / platform | Yes | Yes | Yes (default) |
❓Frequently asked questions
How do we know which videos are most-watched?
Your content backend already has play counts per video — that's where video-level engagement lives. Respectlytics is for product engagement at the feature level ("is the video player surface working?"). Conflating them duplicates a system of record.
Should we track exact playback position?
No — milestones (25 / 50 / 75 / 100%) carry the signal. Exact position produces a flood of low-value events that drown the milestone signal. Player-side analytics (your video player vendor's SDK) has its own per-second tracking if you genuinely need it.
What about content category breakdowns (movies, shows, shorts)?
If you have a small fixed set, distinct event names: video_completed_movie, video_completed_show. For high-cardinality categorization, use your content backend's analytics — it has the metadata you need.
Does this work for live streams?
Conceptually different. Use distinct event names — livestream_joined, livestream_left — and fire on join and leave. Milestones don't apply to live; duration is computed from join → leave timestamp difference.