Usage (Web)¶
The SDK can be used either with the generic ClientAnalytics class for plain HTML5 video, or with player-specific adapters that provide tighter integration with popular video players.
Plain HTML5 Video¶
Create a ClientAnalytics instance with your API key, then call measure() on the video element:
<script src="surfmeter-client-analytics.js"></script>
<script>
const sca = new surfmeter.ClientAnalytics('YOUR_API_KEY', {});
const video = document.querySelector('video');
const handler = sca.measure(video, {
streamId: 'my-stream-id',
metadata: {
userId: 'user123',
channelId: 'channel456',
},
});
</script>
Video.js¶
Use the VideoJsClientAnalytics class. For HLS/DASH streaming with quality tracking, configure Video.js to use MSE rather than native playback:
<link href="https://vjs.zencdn.net/8.16.1/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/8.16.1/video.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/videojs-contrib-quality-levels@4/dist/videojs-contrib-quality-levels.min.js"></script>
<script src="surfmeter-videojs-analytics.js"></script>
<video-js id="my-player" class="vjs-default-skin" controls width="640" height="360"></video-js>
<script>
var player = videojs('my-player', {
html5: {
vhs: { overrideNative: true },
nativeAudioTracks: false,
nativeVideoTracks: false,
},
});
player.src({ src: 'https://example.com/stream.m3u8', type: 'application/x-mpegURL' });
var analytics = new surfmeter.VideoJsClientAnalytics('YOUR_API_KEY', {});
var handler = analytics.measure(player, { streamId: 'YOUR_STREAM_ID' });
</script>
The videojs-contrib-quality-levels plugin is recommended for tracking bitrate, resolution, and frame rate changes. Without it, the adapter still collects standard HTML video element metrics but cannot track player-level quality switches.
Shaka Player¶
Use the ShakaplayerAnalytics class. Call measure() after the player has loaded a source:
<script src="https://cdn.jsdelivr.net/npm/shaka-player/dist/shaka-player.compiled.js"></script>
<script src="surfmeter-shaka-player-analytics.js"></script>
<script>
const analytics = new surfmeter.ShakaplayerAnalytics('YOUR_API_KEY', {});
const video = document.getElementById('video');
const player = new shaka.Player(video);
player.load('https://example.com/stream.mpd').then(() => {
const handler = analytics.measure(player, { streamId: 'YOUR_STREAM_ID' });
});
</script>
THEOplayer¶
Use the TheoplayerAnalytics class. Requires THEOplayer v8+:
<script src="https://cdn.jsdelivr.net/npm/theoplayer@10/THEOplayer.js"></script>
<script src="surfmeter-theoplayer-analytics.js"></script>
<script>
const analytics = new surfmeter.TheoplayerAnalytics('YOUR_API_KEY', {});
const player = new THEOplayer.Player(document.getElementById('player'), {
libraryLocation: 'https://cdn.jsdelivr.net/npm/theoplayer@10/',
});
player.source = {
sources: [{ src: 'https://example.com/stream.m3u8', type: 'application/x-mpegurl' }],
};
const handler = analytics.measure(player, { streamId: 'YOUR_STREAM_ID' });
</script>
ES Module Usage¶
All adapters can also be used as ES modules:
// Plain HTML5 video
import { ClientAnalytics } from '@surfmeter/client-analytics';
// Video.js
import { VideoJsClientAnalytics } from '@surfmeter/videojs-analytics';
// Shaka Player
import { ShakaplayerAnalytics } from '@surfmeter/shaka-player-analytics';
// THEOplayer
import { TheoplayerAnalytics } from '@surfmeter/theoplayer-web-analytics';
// // Chromecast
// import { ChromecastAnalytics2, TheoChromecastAnalytics } from '@surfmeter/chromecast-analytics';
API Reference¶
Constructor Options¶
All adapters accept the same constructor signature: new Analytics(apiKey, opts).
apiKey(string) — your Surfmeter API key.opts(object):fingerprint(string | () => string | Promise\<string>) — a unique identifier for the device or session, used to correlate measurements across page reloads. When omitted, the library generates one automatically using FingerprintJS (open-source edition), withcrypto.randomUUID()as a fallback.
Measurement Options¶
analytics.measure(player, options?) starts monitoring. The options object supports:
streamId— a stable identifier for the content being played (video ID, channel ID, etc.). Recommended for all MSE-based players (Video.js, Shaka, THEOplayer), since the<video>element'ssrcwill be ablob:URL rather than the actual stream URL. If the SDK cannot determine the video source, it silently skips sending data.metadata— arbitrary key-value object attached to the measurement. Useful for segmenting data in the dashboard (e.g., user ID, channel, content title).params— additional parameters for the measurement.
Handler¶
The object returned by measure() exposes:
surfmeterMonitoringId— unique identifier for this measurement session.destroy()— stop monitoring, remove all event listeners, and clean up. Call this when you tear down the player or navigate away.-
onPlaybackError(error?)— manually report an error from your application code (e.g., DRM failures, network errors caught outside the player). Accepts either a plain string or a structured object:-// Simple string message handler.onPlaybackError('Some Error Message'); // Structured error details handler.onPlaybackError({ message: 'Failed to load segment', errorType: 'NETWORK', errorCode: '404', });onAdBreakStarted()— signal that an ad break has started. -onAdBreakEnded()— signal that an ad break has ended.
Setting Metadata After Initialization¶
You can update metadata on a running measurement:
analytics.setMetadata(handler.surfmeterMonitoringId, {
userId: 'user123',
channelId: 'channel456',
});
Similarly, you can set additional parameters:
Warning
Please make sure that if you send personal data such as customer IDs, names, or email addresses, you have the necessary consent of the user to do so.
What It Monitors¶
All adapters collect the following metrics:
- Playback state transitions (playing, paused, seeking, stalling, ended)
- Buffering and stalling events
- Video and audio codec changes
- Bitrate changes (video and audio)
- Resolution changes (width, height)
- Frame rate changes
- Playback errors
- Time updates and duration
- Display size
Player-specific adapters additionally track quality information from the player's own API (e.g., quality levels in Video.js, track/variant data in Shaka Player, media track qualities in THEOplayer).
On WebKit browsers (Safari, iOS), bitrate is estimated from decoded byte counts on the video element rather than from player-level APIs.
Debug Logging¶
All adapters export an enableDebugLogs() function. Call it before creating the analytics instance to see detailed logs in the browser console:
import { enableDebugLogs } from '@surfmeter/videojs-analytics';
enableDebugLogs('trace'); // 'trace' | 'debug' | 'info' | 'warn' | 'error'
Cleanup¶
Always call handler.destroy() when you are done with the player:
This removes all event listeners, stops data collection, and sends any remaining buffered data.