Video Telemetry & QoE Metrics
The Enterprise telemetry engine collects real-time playback health and Quality of Experience (QoE) metrics across your audience.
Standard video players leave you blind once video leaves your CDN. When streams stall, users exit or complain without actionable context. Better Player Enterprise measures startup latency, rebuffer frequency, bitrate transitions, and errors, buffering events locally when connections drop and delivering them to Bitmovin Analytics, Mux Data, or your own ingest servers.
What It Measures
- Startup Latency: Time to First Frame (TTFF) and player initialization duration.
- QoE & Buffering: Rebuffer stall count, total stall time, and rebuffer ratio.
- Renditions & Bitrate: Live ASMS/HLS track switches, bandwidth shifts, and resolution changes.
- Viewer Engagement: Actual playtime, pause duration, seek count, seek latency, and playhead completion percentage.
- Exit Before Video Start (EBVS): Tracks viewers who bounce before the first frame renders.
- VAST Ad Isolation: Freezes content QoE timers during ad breaks so pre-rolls and mid-rolls do not inflate your video startup metrics.
License Setup
Enterprise capabilities require license verification during app startup:
import 'package:better_player_enterprise/better_player_enterprise.dart';
import 'package:flutter/widgets.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await BetterPlayerEnterprise.initialize(
licenseId: 'YOUR_ENTERPRISE_LICENSE_KEY',
);
runApp(const MyApp());
}
Quickstart
Attach BetterPlayerMetricsExtension directly to your BetterPlayerController:
import 'package:better_player/better_player.dart';
import 'package:better_player_enterprise/better_player_enterprise.dart';
final metricsExtension = BetterPlayerMetricsExtension(
configuration: BetterPlayerMetricsConfiguration(
exporter: BetterPlayerHttpMetricsExporter(
endpointUrl: 'https://telemetry.yourdomain.com/v1/metrics',
),
heartbeatInterval: const Duration(seconds: 15),
batchSize: 10,
customData: const <String, dynamic>{
'userId': 'usr_94821',
'plan': 'pro',
},
),
);
final controller = BetterPlayerController(
PlayerConfiguration(
aspectRatio: 16 / 9,
autoPlay: true,
extensions: [metricsExtension],
),
betterPlayerDataSource: PlayerDataSource(
DataSourceType.network,
'https://example.com/hls/stream.m3u8',
),
);
BetterPlayer(controller: controller);
Accessing Live QoE Stats
Read live metrics from the extension anytime:
final stats = metricsExtension.playbackStats;
if (stats != null) {
print('TTFF: ${stats.timeToFirstFrame?.inMilliseconds} ms');
print('Rebuffer Ratio: ${(stats.rebufferRatio * 100).toStringAsFixed(2)}%');
print('Total Watch Duration: ${stats.totalWatchDuration.inSeconds}s');
print('Active Bitrate: ${stats.bitrateBps} bps');
}
Or listen to real-time changes in your UI via ValueListenable:
ValueListenableBuilder<BetterPlayerPlaybackStats>(
valueListenable: metricsExtension.statsListenable!,
builder: (context, stats, child) {
return Text(
'Rebuffer: ${(stats.rebufferRatio * 100).toStringAsFixed(1)}% '
'(${stats.rebufferCount} stalls)',
);
},
);
Cloud Exporters
Bitmovin Analytics
Stream telemetry into your Bitmovin Analytics dashboard:
final exporter = BetterPlayerBitmovinMetricsExporter(
apiKey: 'YOUR_BITMOVIN_ANALYTICS_KEY',
customData: const <String, dynamic>{
'customData1': 'premium_tier',
},
);
Mux Data
Stream QoE beacons into Mux Data:
final exporter = BetterPlayerMuxMetricsExporter(
propertyKey: 'YOUR_MUX_ENVIRONMENT_KEY',
customData: const <String, dynamic>{
'viewer_plan': 'enterprise',
},
);
Multi-Destination Fan-Out
Broadcast telemetry events to multiple analytics backends simultaneously:
final exporter = BetterPlayerCompositeMetricsExporter(
exporters: [
BetterPlayerBitmovinMetricsExporter(apiKey: 'YOUR_BITMOVIN_KEY'),
BetterPlayerMuxMetricsExporter(propertyKey: 'YOUR_MUX_KEY'),
BetterPlayerHttpMetricsExporter(
endpointUrl: 'https://internal-bi.company.com/ingest',
),
],
);
Offline Storage & Resilience
When viewers lose internet connectivity (in tunnels, airplanes, or poor reception), telemetry events are queued to local persistent storage (SharedPreferences):
- Priority-Aware Eviction: If stored events reach the capacity ceiling (
maxPersistedEvents: 500), routine heartbeats are dropped first. Critical milestones (sessionStart,error,sessionEnd) stay protected. - TTL Expiration: Stored offline batches older than 72 hours (
eventTtl) are pruned automatically. - Automatic Drain: Once network returns, the dispatcher drains stored offline batches in sequential order with exponential backoff and jitter.
You can also trigger an immediate flush on demand:
await metricsExtension.flush();
VAST Ad Isolation
When running ads via BetterPlayerVastExtension, ad viewing time must not inflate content startup latency or skew content playback stats.
BetterPlayerMetricsManager automatically links with BetterPlayerVastExtension when both extensions are attached:
- Ad break durations are excluded from content watch and rebuffer timers.
- Dedicated
adBreakevents are dispatched for ad start, quartiles (25%, 50%, 75%, 100%), skip, and completion.