Analytics Module

A sample code module for sending player and lifecycle events to Google Analytics

The analytics module provides support for sending events to the Google Analytics platform. It's a single JavaScript file, available in this repo along with a readme file that explains its usage.

The module can be used to easily track what content the viewer watches. It attaches to either the Shaka Player or the Remote Player, so once you've connected it up it requires zero additional lines of code as your app runs!

It takes advantage of a unique capability of Senza to send analytics data at the end of a session. So you can capture raw events, a single summary of the entire session, or both. And it has support for live streams, so if your content changes while playing the same manifest you can capture one viewing session per program.

It also helps you log lifecycle state changes. As with video content, you have the option of capturing raw events as the app moves between foreground and background modes, and/or a single summary at the end of the session that includes the total time spent in foreground and background modes. The Stopwatch functionality has also be integrated into the analytics module, so you can see the time spent in each mode on screen during development.

The analytics module also has a facility to geolocate the user, so you can capture their actual location. That way the analytics system doesn't think that all your users live in data centers.

Setup

Clone the repo above, and copy the analytics.js file into your app.

You can import the singleton instance of the SenzaAnalytics class like this:

import analytics from './analytics.js';

Call analytics.init() with the name of your app, and a config object.

await analytics.init("App Name", {
  google: {gtag: googleAnalyticsId, debug: true},
  ipdata: {apikey: ipDataAPIKey},
  userInfo: {username: "andrewzc"},
  lifecycle: {raw: false, summary: true},
  player: {raw: false, summary: true},
  disconnect: {delay: 10}
});

Here are the properties of the config object, all of which are optional:

  • google.gtag: A key for identifying your app to Google Analytics (instructions).
  • google.debug: Causes events show up immediately in the debug view. Defaults to false.
  • ipdata.apikey: An API key from ipdata.co, enabling geolocation.
  • userinfo: An object containing values to be included in the user properties.
  • lifecycle.raw: Whether to send all raw lifecycle state changes. Defaults to false.
  • lifecycle.summary: Whether to send a single summary when disconnecting. Defaults to true.
  • player.raw: Whether to send all raw playback events, like load, play and pause. Defaults to false.
  • player.summary: Whether to send a summary at the end of each playback session. Defaults to true.
  • disconnect.delay: Remain connected for a few extra seconds so you can view console output in the debugger. Defaults to 0, maximum is 10 seconds.

You can also call analytics.config() if you want to change some of the configuration options later. You can pass a sparse object, and it will apply just the properties that you have specified.

Local Player

To track playback in the local player, call trackPlayerEvents() like this, passing the player and the video element.

const player = new senza.ShakaPlayer();
await player.attach(video);

analytics.trackPlayerEvents(player, video, getMetadata);

await player.load(url);
await video.play();

This works with either the standard Shaka Player or the Senza Shaka player. The Senza Shaka player keeps the remote player synced with the local player, but for our purposes we can get all the analytics we need just from the local player.

The analytics module will then track everything you do with the player and video, including loading, playing, pausing, skipping, etc. Once it has been configured, you don't need to add any additional code.

Remote Player

To track playback in the Remote Player only, call trackRemotePlayerEvents().

analytics.trackRemotePlayerEvents(getMetadata);

await senza.remotePlayer.load(url);
await senza.remotePlayer.play();

The analytics module will then track everything you do with the remote player. This is useful if your app only plays video in background mode and doesn't have a local player.

Metadata

The last argument to both of the functions above is optional, and can be either a static metadata object like this:

{
  contentId: "bbb_30fps",
  title: "Big Buck Bunny",
  description: "Big Buck Bunny tells the story of a giant rabbit."
}

…or a function that is called every time a new stream is loaded and returns the metadata for that stream:

function getMetadata(ctx) {
  const contentId = filename(ctx.url);
  return {contentId, description: descriptions[contentId]};
}

The function is passed a context object with player, video and url properties. It can optionally be asynchronous, which is useful if you need to call an API to get the metadata.

Live streams

If playing a live stream, the content may change even if the manifest URL stays the same. In that case you can call analytics.contentChanged(getMetadata) to indicate that the content has changed. You can pass:

  • A new metadata object for the current content
  • A new function, if the logic has changed
  • Nothing, which will call the previous function or use the previous object

If using a function, it should return a different result based on the current time and the schedule data.

❗️

Warning

Be careful about using the Alarm Manager to wake up your app at specific clock times, such as the top of the hour. It would cause excessive load on the Senza platform if every instance of your app moved to foreground at the same time. If you need to do this, it would be better to distribute the alarms over a period of time.

Viewing events

  1. The simplest way to see events being sent is in the Remote Debugger, where the analytics module logs all events that it sends to Google Analytics. Handy tip: to keep the debugger open a little longer so you can see events that are sent when the app disconnects, set the disconnect.delay to 10 seconds.
  2. In the Google Analytics dashboard, go to Property Settings > Data Display > Debug View. Select a debug device (i.e. "Google"), and you'll see a live display of events received if google.debug is set to true.

Adapting for other platforms

Want to use a different analytics platform than Google Analytics, or a different service for geolocation? You can easily use this module as a starting point, since the code that is specific to GA4 and ipdata.co is actually just a small part of the module. Just change the code in init() and logEvent() as needed.