JW Player


The minimum supported version for the JW player is 8.17.0. Prior to this version JW didn't expose enough events and data for our plugin to be able to properly collect the needed metrics. Please make sure your players are at least on this version before proceeding to the next steps.


The plugin url is in the form


You must replace *** with the Watching That customer ID received from us.

The best way to add our plugin to a JW player is by adding the plugin configuration options to the JW player init options. This will ensure our plugin is set up and initialised before any important event that we might need to capture happens.

const playerConfig = {
// the rest of the JW player configuration
plugins: {
// make sure to replace '***' with your Watching That customer ID
'https://cdn.watchingthat.net/***.wtat.plugin-jw_ima.min.js': {
apiKey: '<Watching That API key>',
// other plugins here

See the configuration options for some other config params you can use for the plugin (only apiKey is required).

You can retrieve the API key from the Watching That app.

Alternative Setup#

For the rare cases when you might not be able to use the above setup we provide an alternative way:

1. Load the plugin script#

<script src="https://cdn.watchingthat.net/***.wtat.plugin-jw_ima.min.js"></script>

2. Start the plugin#

It is important to run the code below immediately after starting the JW player or as soon as possible. If you delay starting the plugin for too long, it might miss important events that happen after the player starts and before the plugin starts.

The general start call looks like this:

wtAdTracer({ apiKey: '<Watching That API key>' }, playerRef, isReady);


For the playerRef parameter you can use either the instance of the JW player:

const player = jwplayer('videoId').setup({...});
wtAdTracer({ apiKey: '<Watching That API key>' }, player);

or the id you used when starting the JW player:

wtAdTracer({ apiKey: '<Watching That API key>' }, 'videoId');

or the DOM element with that id:

const el = document.getElementById('videoId');
wtAdTracer({ apiKey: '<Watching That API key>' }, el);


If you're starting our plugin from within the player onReady handler then you must let our plugin know about this:

const player = jwplayer('videoId').setup({...});
player.on('ready', () => {
wtAdTracer({ apiKey: '<Watching That API key>' }, player, true); // true as the third param
// more work to be done onReady...

Our plugin might never start working without setting that third parameter to true in this scenario! This is because the wtAdTracer() function sets up its own onReady listener but since the ready event happens only once and it has already happened, the plugin will most likely not be started.

The Anti-pattern#

When you have a CMS or complex frontend code which lets you load scripts you might be tempted to do this:

player.on('ready', () => {
// ...
loadWatchingThatPlugin().then(() => {
wtAdTracer({ apiKey: '<Watching That API key>' }, player, true);
// ...

Loading the plugin only after the player is ready is an anti-pattern because by the time it's loaded and started, the plugin might miss some early player events. In other words the player will not pause and wait for the plugin to load and start, but it will move on and start the video, make ad requests, etc. Once the plugin loads and starts it will capture events from that point onward only.

The better approach would be to load the plugin independently of the player and start it in the onReady handler:

]).then(() => {
const player = jwplayer('videoId').setup({...});
player.on('ready', () => {
wtAdTracer({ apiKey: '<Watching That API key>' }, player, true);
// ...