<SYSTEM>This is the developer documentation for integrating Mux Data with your player.</SYSTEM>

# Monitor HTML5 video element
This guide walks through integration with any HTML5 video player to collect video performance metrics with Mux data. Use this if Mux does not have an SDK specific for your player.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Available for deployment from a package manager
- Custom Dimensions
- Custom Beacon Domain

```

Notes:

```md
Live Latency is available for Native Safari HLS.
```

## 1. Install mux-embed

Include the Mux JavaScript SDK on every page of your web app that includes video. You can use the Mux-hosted version of the script or install via npm. `mux-embed` follows [semantic versioning](https://semver.org/) and the API will not change between major releases.

If possible, use the SDK for your particular player (e.g. Video.js, JW Player, etc.). While the HTML5 SDK works with any modern HTML5 video player, the player-specific Mux SDK is preferable because it offers a deeper integration and in most cases collects more pieces of data. If you don't see your player listed then use `mux-embed` and let us know so we can prioritize creating an SDK for the player that you are using.

```cdn

<script src="https://src.litix.io/core/4/mux.js"></script>

```

```npm

npm install --save mux-embed

```

```yarn

yarn add mux-embed

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

```html

<script>
  if (typeof mux !== 'undefined') {
    window.muxPlayerInitTime = mux.utils.now();
  }
</script>

<video
  id="my-player"
  src="https://muxed.s3.amazonaws.com/leds.mp4"
  controls
  width="960"
  height="400"
/>

<script>
  // Initialize Mux Data monitoring by passing in the "id" attribute of your video player
  if (typeof mux !== 'undefined') {
    mux.monitor('#my-player', {
      debug: false,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata fields
        player_name: 'Main Player', // any arbitrary string you want to use to identify this player
        player_init_time: window.muxPlayerInitTime // ex: 1451606400000
        // ...
      }
    });
  }
</script>

```

```javascript

import mux from 'mux-embed';

const playerInitTime = mux.utils.now();

// Initialize Mux Data monitoring by passing in the "id" attribute of your video player
mux.monitor('#my-player', {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Metadata fields
    player_name: 'Main Player', // any arbitrary string you want to use to identify this player
    player_init_time: playerInitTime,
    // ...
  }
});

```

```react

import mux from 'mux-embed';
import React, { useEffect, useRef } from 'react';

export default function VideoPlayer () {
  const videoRef = useRef(null);

  useEffect(() => {
    if (videoRef.current) {
      const initTime = mux.utils.now();

      mux.monitor(videoRef.current, {
        debug: false,
        data: {
          env_key: 'ENV_KEY', // required
          // Metadata fields
          player_name: 'Main Player', // any arbitrary string you want to use to identify this player
          player_init_time: initTime,
          // ...
        }
      });
    }
  }, [videoRef]);

  return (
    <video
      controls
      ref={videoRef}
      src="https://muxed.s3.amazonaws.com/leds.mp4"
      style={{ width: '100%', maxWidth: '500px' }}
    />
  );
}

```



Call `mux.monitor` and pass in a valid CSS selector or the video element itself. Followed by the SDK options and metadata. If you use a CSS selector that matches multiple elements, the first matching element in the document will be used.

Log in to the Mux dashboard and find the environment that corresponds to your `env_key` and look for video views. It takes about a minute or two from tracking a view for it to show up on the Metrics tab.

**If you aren't seeing data**, check to see if you have an ad blocker, tracking blocker or some kind of network firewall that prevents your player from sending requests to Mux Data servers.

## 3. Make your data actionable

The only required field in the `options` that you pass into `mux-embed` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` key when calling `mux.monitor`.

```js
mux.monitor('#my-player', {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required

    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'

    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000

    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `monitor`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
const myPlayer = document.querySelector('#my-player');
myPlayer.src = 'https://muxed.s3.amazonaws.com/leds.mp4';

mux.emit('#my-player', 'videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
mux.emit('#my-player', 'programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
mux.monitor('#my-player', {
  debug: false,
  disableCookies: true,
  data: {
    env_key: 'ENV_KEY',
    // ... rest of metadata
  }
}
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
mux.monitor('#my-player', {
  debug: false,
  respectDoNotTrack: true, // Disable tracking of browsers where Do Not Track is enabled
  data: {
    env_key: 'EXAMPLE_ENV_KEY',
    // ... rest of metadata
  }
}
```

### Customize error tracking behavior

By default, `mux-embed` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
mux.emit('#my-player', 'error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

mux.monitor('#my-player', {
  debug: false,
  errorTranslator: errorTranslator,
  data: {
    env_key: 'ENV_KEY', // required

    // ... additional metadata
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
mux.monitor('#my-player', {
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: 'ENV_KEY', // required

    // ... additional metadata
  }
```

### Use TypeScript with mux-embed  <BetaTag />

TypeScript support for mux-embed is currently in beta, so you'll need to take a couple extra steps in order to use it.

Use TypeScript's [triple slash `<reference path="..."/>` directive](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-path-). At the top of your `.ts` or `.tsx` file where you want to use the types, add a line that looks like this:

```ts
/// <reference path="../../node_modules/mux-embed/dist/types/mux-embed.d.ts"/>
```

Note that the triple slash directive requires passing in the relevant path from your .ts or tsx file to the source d.ts file in node\_modules/.

Also, you may have a linting rule that prevents you from using the triple slash directive, you can disable that with and eslint-disable line:

```ts
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
```

Here's an example directory structure and component file:

```sh filename="Directory Structure"
├── node_modules/
│   └── mux-embed/
│       └── dist/
│           └── types/
│               └── mux-embed.d.ts
└── src/
    └── video-component/
        └── video-component.ts
```

```ts filename="video-component.ts"
// NOTE: You may also need to disable linter rules, such as this example for @typescript-eslint
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="../../node_modules/mux-embed/dist/types/mux-embed.d.ts"/>
import mux from 'mux-embed';

// ...

let videoEl?: HTMLVideoElement;

// This should now be type valid, too!
videoEl?.mux.destroy();
```

This opt-in approach is temporary while we're in beta with TypeScript support. If you run into any issues with the types, please let us know so we can improve them.

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
mux.monitor('#my-player', {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: 'ENV_KEY', // required
    // ... additional metadata
  }
});
```


# Monitor HLS.js
This guide walks through integration with [HLS.js](https://github.com/video-dev/hls.js) to collect video performance metrics with Mux data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Available for deployment from a package manager
- Can infer CDN identification from response headers
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Customizable Error Tracking
- Custom Beacon Domain
- Extraction of HLS Session Data
- Live Stream Latency metric

```

Notes:

```md
Average Bitrate Metrics available in v3.2.0 and newer.
```

## 1. Install mux-embed

Include the Mux JavaScript SDK on every page of your web app that includes video. You can use the Mux-hosted version of the script or install via npm. `mux-embed` follows [semantic versioning](https://semver.org/) and the API will not change between major releases.

```cdn

<script src="https://src.litix.io/core/4/mux.js"></script>

```

```npm

npm install --save mux-embed

```

```yarn

yarn add mux-embed

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

```html

<script>
  if (typeof mux !== 'undefined') {
    window.muxPlayerInitTime = mux.utils.now();
  }
</script>

<video
  id="my-player"
  controls
  width="960"
  height="400"
/>

<script>
  if (Hls.isSupported()) {
    let hls = new Hls();

    // we're using a Mux HLS URL in this example, but the Mux Data integration
    // with HLS.js works with any HLS url
    hls.loadSource('https://stream.mux.com/yb2L3z3Z4IKQH02HYkf9xPToVYkOC85WA.m3u8');
    hls.attachMedia(videoEl);

    if (typeof mux !== 'undefined') {
      const videoEl = document.querySelector('#my-player');

      mux.monitor(videoEl, {
        debug: false,
        hlsjs: hls,
        Hls: Hls,
        data: {
          env_key: 'ENV_KEY', // required
          // Metadata fields
          player_name: 'Main Player', // any arbitrary string you want to use to identify this player
          player_init_time: window.muxPlayerInitTime // ex: 1451606400000
          // ...
        }
      });
    }
  }
</script>

```

```javascript

import Hls from "hls.js";
import mux from "mux-embed";

const muxPlayerInitTime = mux.utils.now();
const videoEl = document.querySelector('#my-player');

if (Hls.isSupported()) {
  let hls = new Hls();

  // we're using a Mux HLS URL in this example, but the Mux Data integration
  // with HLS.js works with any HLS url
  hls.loadSource('https://stream.mux.com/yb2L3z3Z4IKQH02HYkf9xPToVYkOC85WA.m3u8');
  hls.attachMedia(videoEl);
  mux.monitor(videoEl, {
    debug: false,
    hlsjs: hls,
    Hls: Hls,
    data: {
      env_key: 'ENV_KEY', // required
      // Metadata fields
      player_name: 'Main Player', // any arbitrary string you want to use to identify this player
      player_init_time: window.muxPlayerInitTime // ex: 1451606400000
      // ...
    }
  });
}

```

```react

import React, { useEffect, useRef } from "react";
import Hls from "hls.js";
import mux from "mux-embed";

export default function VideoPlayer() {
  const videoRef = useRef(null);
  const src = "https://stream.mux.com/yb2L3z3Z4IKQH02HYkf9xPToVYkOC85WA.m3u8";

  useEffect(() => {
    let hls;

    if (videoRef.current) {
      const video = videoRef.current;
      const initTime = mux.utils.now();

      if (video.canPlayType("application/vnd.apple.mpegurl")) {
        // This will run in safari, where HLS is supported natively
        video.src = src;
      } else if (Hls.isSupported()) {
        // This will run in all other modern browsers
        hls = new Hls();
        hls.loadSource(src);
        hls.attachMedia(video);

        mux.monitor(video, {
          debug: false,
          // pass in the 'hls' instance and the 'Hls' constructor
          hlsjs: hls,
          Hls,
          data: {
            env_key: "ENV_KEY", // required
            // Metadata fields
            player_name: "Main Player", // any arbitrary string you want to use to identify this player
            player_init_time: initTime
            // ...
          }
        });
      }
    }

    return () => {
      if (hls) {
        hls.destroy();
      }
    };
  }, [videoRef]);

  return (
    <video
      controls
      ref={videoRef}
      style={{ width: "100%", maxWidth: "500px" }}
    />
  );
}

```



Call `mux.monitor` and pass in a valid CSS selector or the video element itself. Followed by the SDK options and metadata. If you use a CSS selector that matches multiple elements, the first matching element in the document will be used.

In the SDK options, be sure to pass in the `hlsjs` instance and the `Hls` constructor. If the `Hls` constructor is available on the global `window` object then it can be omitted from the SDK options.

Alternatively, if your player does not immediately have access to the HLS.js player instance, you can start monitoring HLS.js at any time in the future. In order to do this, you can call either of the following:

```js
mux.addHLSJS("#my-player", options)
// or
myVideoEl.mux.addHLSJS(options)
```

Log in to the Mux dashboard and find the environment that corresponds to your `env_key` and look for video views. It takes about a minute or two from tracking a view for it to show up on the Metrics tab.

**If you aren't seeing data**, check to see if you have an ad blocker, tracking blocker or some kind of network firewall that prevents your player from sending requests to Mux Data servers.

## 3. Make your data actionable

The only required field in the `options` that you pass into `mux-embed` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` key when calling `mux.monitor`.

```js
mux.monitor('#my-player', {
  debug: false,
  hlsjs: hls,
  Hls,
  data: {
    env_key: 'ENV_KEY', // required

    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'

    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000

    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `monitor`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
mux.emit('#my-player', 'videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
mux.emit('#my-player', 'programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
mux.monitor('#my-player', {
  debug: false,
  disableCookies: true,
  hlsjs: hls,
  Hls,
  data: {
    env_key: 'ENV_KEY',
    // ... rest of metadata
  }
}
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
mux.monitor('#my-player', {
  debug: false,
  hlsjs: hls,
  Hls,
  respectDoNotTrack: true, // Disable tracking of browsers where Do Not Track is enabled
  data: {
    env_key: 'ENV_KEY',
    // ... rest of metadata
  }
}
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `mux-embed` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
mux.emit('#my-player', 'error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

mux.monitor('#my-player', {
  debug: false,
  errorTranslator,
  hlsjs: hls,
  Hls,
  data: {
    env_key: 'ENV_KEY', // required

    // ... additional metadata
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
mux.monitor('#my-player', {
  debug: false,
  automaticErrorTracking: false,
  hlsjs: hls,
  Hls,
  data: {
    env_key: 'ENV_KEY', // required

    // ... additional metadata
  }
```

### Use TypeScript with mux-embed  <BetaTag />

`mux-embed` now provides TypeScript type definitions with the published package! If you want to opt in, you can check out how [here](/docs/guides/monitor-html5-video-element#opt-in-to-using-mux-embed-typescript-type-definitions--).

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
mux.monitor('#my-player', {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  hlsjs: hls,
  Hls,
  data: {
    env_key: 'ENV_KEY', // required
    // ... additional metadata
  }
});
```


# Monitor AVPlayer
This guide walks through integration with iOS and TVOS AVPlayer player to collect video performance metrics with Mux data.
Mux Data integration for AVPlayer supports applications running on iOS 12.0 or newer, tvOS 12.0 or newer, and Mac Catalyst that use `AVPlayerViewController`, `AVPlayerLayer`, or a standalone `AVPlayer` playing audio or if presented with a fixed size. Applications running on visionOS 1.0 and higher are also supported if they use `AVPlayerViewController` or a standalone `AVPlayer` playing audio or if presented with a fixed size.

This integration uses Mux's core Objective-C SDK and the full source can be seen here: [muxinc/mux-stats-sdk-avplayer](https://github.com/muxinc/mux-stats-sdk-avplayer). This SDK is packaged as an xcframework.

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Ads metrics
- Customizable Error Tracking
- Custom Beacon Domain
- Extraction of HLS Session Data
- Live Stream Latency metric

```

Notes:

```md
Packaged with: cocoapods, SPM and carthage. Request Latency is not available.
```

## 1. Install the Mux Data SDK

## Installation

### Installing in Xcode with Swift Package Manager

1. In Xcode click "File" > "Swift Packages" > "Add Package Dependency..."
2. The package repository URL is `https://github.com/muxinc/mux-stats-sdk-avplayer.git`

```
https://github.com/muxinc/mux-stats-sdk-avplayer.git
```

3. Click `Next`.
4. Since the `MUXSDKStats` follows SemVer, we recommend setting the "Rules" to install the latest version and choosing the option "Up to Next Major". [Here's an overview of the different SPM Dependency Rules and their semantics](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app#Decide-on-package-requirements).

### Installing in Package.swift

Open your Package.swift file, add the following to `dependencies`:

```swift
    .package(
      url: "https://github.com/muxinc/mux-stats-sdk-avplayer",
      .upToNextMajor(from: "4.0.0")
    ),
```

Note that `MUXSDKStats` has a dependency on `MuxCore`, so you will see that `MuxCore` gets installed as well.

> As of Xcode 14.3.1 integrating the Mux SDKs as part of a shared framework using Swift Package Manager library targets is now supported. [An example for setting this up is available here](https://github.com/muxinc/examples/tree/main/swift-data-library-installation).

### Installing with CocoaPods

To install with CocoaPods, modify your Podfile to use frameworks by including `use_frameworks!` and then add the following pods to your Podfile:

```
pod 'Mux-Stats-AVPlayer', '~>4.0'
```

This will install `Mux-Stats-AVPlayer` and the latest current release of our [core Objective-C Library](https://github.com/muxinc/stats-sdk-objc).

Next, add correct import statement into your application.

```objc

@import MUXSDKStats;

```

```swift

import MUXSDKStats

```



## 2. Initialize the monitor for your AVPlayer instance

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

The example below uses `monitorAVPlayerViewController(_:withPlayerName:customerData:)`. If you are using `AVPlayerLayer`, use `monitorAVPlayerLayer(_:withPlayerName:customerData:)` instead.

The `playerName` parameter is a string that identifies this instance of your player. When calling `destroyPlayer(_:)` or `videoChange(forPlayer:with:)` later on, you will need this string. Each instance of a player that runs simultaneously in your application should have a different `playerName`.

<Callout type="warning">
  **If you are using SwiftUI**, attach the monitor in the `onAppear` action for your view. This ensures that the Mux Data SDK is able to get the dimensions of the view which is used to calculate video quality metrics.
</Callout>

```objc

MUXSDKCustomerPlayerData *playerData = [[MUXSDKCustomerPlayerData alloc] initWithPropertyKey:@"ENV_KEY"];

MUXSDKCustomerVideoData *videoData = [MUXSDKCustomerVideoData new];
// insert videoData metadata
videoData.videoTitle = @"Title1";
videoData.videoSeries = @"animation";

MUXSDKCustomerData *customerData = [[MUXSDKCustomerData alloc] initWithCustomerPlayerData:playerData
                                                                                videoData:videoData
                                                                                 viewData:nil
                                                                               customData:nil
                                                                               viewerData:nil];

_playerBinding = [MUXSDKStats monitorAVPlayerViewController:_avplayerController 
                                             withPlayerName:@"mainPlayer" 
                                               customerData:customerData];


```

```swift

let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY")
playerData?.playerName = "playerName"

let videoData = MUXSDKCustomerVideoData()
videoData.videoTitle = "Title1"
videoData.videoSeries = "animation"

guard let customerData = MUXSDKCustomerData(
    customerPlayerData: playerData,
    videoData: videoData,
    viewData: nil,
    customData: nil,
    viewerData: nil
) else {
    return
}

let playerBinding = MUXSDKStats.monitorAVPlayerViewController(
    playerViewController,
    withPlayerName: "playerName",
    customerData: customerData
)
// if you're using AVPlayerLayer instead of AVPlayerViewController use this instead:
// MUXSDKStats.monitorAVPlayerLayer(playerLayer, withPlayerName: "playerName", customerData: customerData)

```



For more complete examples check the [demo app in the repo](https://github.com/muxinc/mux-stats-sdk-avplayer/tree/master/Examples).

After you've integrated, start playing a video in your player. A few minutes after you stop watching, you'll see the results in your Mux data dashboard. Login to the dashboard and find the environment that corresponds to your `env_key` and look for video views.

## 3. Make your data actionable

The only required field is `env_key`. But without some more metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Metadata fields are provided via the `MUXSDKCustomerPlayerData` and `MUXSDKCustomerVideoData` objects.

For the full list of properties, see the MuxCore headers in the [latest stats-sdk-objc release](https://github.com/muxinc/stats-sdk-objc/releases/latest).

For more details about each property, view the [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) guide.

```objc

MUXSDKCustomerPlayerData *playerData = [[MUXSDKCustomerPlayerData alloc] initWithPropertyKey:@"ENV_KEY"];
playerData.viewerUserId = @"1234";
playerData.experimentName = @"player_test_A";
playerData.playerName = @"iOS AVPlayer";
playerData.playerVersion = @"1.0.0";

MUXSDKCustomerVideoData *videoData = [MUXSDKCustomerVideoData new];
videoData.videoTitle = @"Big Buck Bunny";
videoData.videoId = @"bigbuckbunny";
videoData.videoSeries = @"animation";
videoData.videoDuration = @(120000); // in milliseconds
videoData.videoIsLive = @NO;
videoData.videoCdn = @"cdn";

MUXSDKCustomerViewData *viewData= [[MUXSDKCustomerViewData alloc] init];
viewData.viewSessionId = @"some session id";

MUXSDKCustomData *customData = [[MUXSDKCustomData alloc] init];
[customData setCustomData1:@"my-data-string"];
[customData setCustomData2:@"my-custom-dimension-2"];

MUXSDKCustomerViewerData *viewerData = [[MUXSDKCustomerViewerData alloc] init];
viewerData.viewerApplicationName = @"MUX DemoApp";

MUXSDKCustomerData *customerData = [[MUXSDKCustomerData alloc] initWithCustomerPlayerData:playerData
                                                                                videoData:videoData
                                                                                 viewData:viewData
                                                                               customData:customData
                                                                               viewerData:viewerData];


_playerBinding = [MUXSDKStats monitorAVPlayerViewController:_avplayerController 
                                             withPlayerName:@"mainPlayer"
                                               customerData:customerData];

```

```swift

guard let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY") else {
    return
}
playerData.playerName = "playerName"
playerData.viewerUserId = "1234"
playerData.experimentName = "player_test_A"
playerData.playerVersion = "1.0.0"

let videoData = MUXSDKCustomerVideoData()
videoData.videoId = "abcd123"
videoData.videoTitle = "My Great Video"
videoData.videoSeries = "Weekly Great Videos"
videoData.videoDuration = 120000 // in milliseconds
videoData.videoIsLive = false
videoData.videoCdn = "cdn"

let viewerData = MUXSDKCustomerViewerData()
viewerData.viewerApplicationName = "MUX video-demo"

guard let customerData = MUXSDKCustomerData(
    customerPlayerData: playerData,
    videoData: videoData,
    viewData: nil,
    customData: nil,
    viewerData: viewerData
) else {
    return
}
let playerBinding = MUXSDKStats.monitorAVPlayerViewController(
    playerViewController,
    withPlayerName: "playerName",
    customerData: customerData
)

// if you're using AVPlayerLayer instead of AVPlayerViewController use this instead:
// MUXSDKStats.monitorAVPlayerLayer(playerLayer, withPlayerName: "playerName", customerData: customerData)

```



## 4. Set or update metadata after monitor

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `monitorAVPlayerLayer`, `monitorAVPlayerViewController`, or `monitorAVPlayer`. Then, once you have the metadata, update it by calling `setCustomerData(_:forPlayer:)`.

```objc

// Sometime later before the player is destroyed you can do this:
// The player name ("mainPlayer" in this example) should be a player that
// you have already called one of the `monitorAVPlayer` methods with
// In this example we are updating videoData, but the same can be done
// for updating playerData, customData or viewData
// Note that the values in customerData passed as nil will keep previously set data
// Note that viewerData can't be updated

MUXSDKCustomerVideoData *videoData = [MUXSDKCustomerVideoData new];
videoData.videoTitle = @"Big Buck Bunny";
videoData.videoId = @"bigbuckbunny";

MUXSDKCustomerData *customerData = [[MUXSDKCustomerData alloc] init];
customerData.customerVideoData = videoData;

[MUXSDKStats setCustomerData:customerData
                   forPlayer:@"mainPlayer"];

```

```swift

// Example: after monitoring, you need to update `customerData` with new metadata.
// In this example we are updating `videoData`, but the same process can be 
// used for updating `playerData`, `customData` or `viewData`.

// Note: The player name ("mainPlayer" in this example) should be a player that
// has been defined in steps 1-3.
// Note: All values in customerData passed as nil will keep previously set data.
// Note: `viewerData` object cannot be updated.

let videoData = MUXSDKCustomerVideoData()
videoData.videoTitle = "Big Buck Bunny"
videoData.videoId = "bigbuckbunny"

guard let customerData = MUXSDKCustomerData(
    customerPlayerData: nil,
    videoData: videoData,
    viewData: nil,
    customData: nil,
    viewerData: nil
) else {
    return
}

MUXSDKStats.setCustomerData(customerData, forPlayer: "mainPlayer")

```



## 5. Advanced

## Changing the Video

There are two cases where the underlying tracking of the video view need to be reset. First, when you load a new source URL into an existing player, and second when the program within a singular stream changes (such as a program within a live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

This is done by calling `videoChange(forPlayer:with:)` which will remove all previous video data and reset all metrics for the video view. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It is required to call `videoChange(forPlayer:with:)` immediately before telling the player which new source to play. This recommendation changed in `v1.2.0`.

It is also required to call `play()` for player after replacing the current item.

If you have new player data you can include it in the `customerData` you pass to `videoChange(forPlayer:with:)`.

```swift

let videoData = MUXSDKCustomerVideoData()
videoData.videoId = "abcd123"
videoData.videoTitle = "My Great Video"
videoData.videoSeries = "Weekly Great Videos"
videoData.videoDuration = 120000 // in milliseconds
videoData.videoIsLive = false
videoData.videoCdn = "cdn"

let customerData = MUXSDKCustomerData(
    customerPlayerData: nil,
    videoData: videoData,
    viewData: nil
)

MUXSDKStats.videoChange(forPlayer: "AVPlayer", with: customerData)

// you should have AVPlayer and AVPlayerItem at this point
player.replaceCurrentItem(with: playerItem)

// call play() on the player here to start playback
player.play()

```



### New program (in single stream)

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, call `programChange(forPlayer:with:)`. This will remove all previous video data and reset all metrics for the video view, creating a new video view. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

```swift

let videoData = MUXSDKCustomerVideoData()
videoData.videoId = "abcd123"
videoData.videoTitle = "My Great Video"
videoData.videoSeries = "Weekly Great Videos"
videoData.videoDuration = 120000 // in milliseconds
videoData.videoIsLive = false
videoData.videoCdn = "cdn"

let customerData = MUXSDKCustomerData(
    customerPlayerData: nil,
    videoData: videoData,
    viewData: nil
)

MUXSDKStats.programChange(forPlayer: "AVPlayer", with: customerData)

```



## Usage with Google Interactive Media Ads (IMA)

If you are using Google Interactive Media Ads, and specifically either the iOS SDK `GoogleAds-IMA-iOS-SDK` or the tvOS SDK `GoogleAds-IMA-tvOS-SDK` then we have another
plugin library that integrates tracking of ad playback events. You should have a fully functioning Google Ads IMA integration working in your iOS or tvOS application first.

<Callout type="info">
  The `v0.14.0` and higher releases of the Mux Google Ads IMA plugin expose a new API. If you've already integrated an earlier version [documentation is available to migrate to the new API](/docs/guides/monitor-avplayer#steps-to-migrate-existing-ima-integration-to-new-api).
</Callout>

### Installation

### Swift Package Manager

#### Installing in Xcode with Swift Package Manager

1. In Xcode click "File" > "Swift Packages" > "Add Package Dependency..."
2. The package repository URL is `https://github.com/muxinc/mux-stats-google-ima.git`

#### Installing as a dependency in Package.swift manifest

In order to install in your iOS application open your `Package.swift` file, add the following to dependencies:

```swift
.package(
  url: "https://github.com/muxinc/mux-stats-google-ima",
  .upToNextMajor(from: "0.14.0")
)
```

### Cocoapods

The Mux Google IMA plugin is available through CocoaPods. To install it, add the following line to your Podfile:

```ruby
pod 'Mux-Stats-Google-IMA'
```

### Steps for new IMA integrations

1. Import the SDK: `import MuxStatsGoogleIMAPlugin` in Swift  `#import <MuxStatsGoogleIMAPlugin/MuxStatsGoogleIMAPlugin.h>` in Objective-C
2. After initializing the Mux monitor with `monitorAVPlayerViewController` or `monitorAVPlayerLayer`, save this value to a variable (below it's called `playerBinding`)
3. Create an `adListener` instance using the `playerBinding` you created above and your applications IMA ads loader by calling `MUXSDKIMAAdListener(playerBinding: playerBinding!, monitoringAdsLoader: yourAdsLoader)`.
4. Add `IMAAdsManager` monitoring by calling `adListener.monitorAdsManager(yourIMAAdsManager)`
5. Notify `adListener` when you send your ad request

* For client-side ads, the most common case, use `imaListener.clientAdRequest(yourIMAAdsRequest)` to forward each `IMAAdsRequest` you initiate
* For server-side ads using [Dynamic Ad Insertion](https://developers.google.com/interactive-media-ads/docs/sdks/ios/dai), use `imaListener.daiAdRequest(yourIMAStreamRequest)` to forward each `IMAAdsRequest` you initiate

6. `MUXSDKIMAAdListener` will automatically intercept `IMAAdsLoader` and `IMAAdsManager` delegate calls

### Steps to migrate existing IMA integration to new API

1. Replace calls to `MuxImaLister` with `MUXSDKIMAAdListener`. `MuxImaListener` supports the same new API so this step is optional, the remaining steps are applicable to `MuxImaListener`. As of `v0.14.0``MuxImaLister` is deprecated and will be removed in a future release.
2. Supply an `IMAAdsLoader` when calling the `MUXSDKIMAAdListener` initializer. Make sure your IMAAdsLoader delegate **is configured before this step**.
3. MUXSDKIMAAdListener will forward `IMAAdsLoaderDelegate` calls to your delegate.
4. When you've created a new `IMAAdsManager`, like you've done with `IMAAdsLoader`, configure your own  `IMAAdsManagerDelegate` first and then call `monitorAdsManager`.
5. MUXSDKIMAAdListener will forward `IMAAdsManagerDelegate` calls to your delegate.
6. Remove calls to `dispatchEvent`, `dispatchError`, and `onContentPauseOrResume` from your integration.

```objc

#import<MuxStatsGoogleIMAPlugin/MuxStatsGoogleIMAPlugin.h>

- (void)viewDidLoad {
  // Follow the instructions from pod 'GoogleAds-IMA-iOS-SDK' to set up
  // your adsLoader and set your ViewController as the delegate
  //
  // From your ViewController, when you call either
  //    monitorAVPlayerViewController:withPlayerName:playerData:videoData:
  //    monitorAVPlayerLayer:withPlayerName:playerData:videoData:
  //
  // You will get back a MUXSDKPlayerBinding object
  [MUXSDKPlayerBinding *playerBinding] = [MUXSDKStats monitorAVPlayerViewController:_avplayerController
                                                                     withPlayerName:DEMO_PLAYER_NAME
                                                                       customerData:customerData];
  //
  // Use the MUXSDKPlayerBinding object to initialize the MuxImaListener class
  //
  _adsListener = [[MUXSDKIMAAdListener alloc] initWithPlayerBinding:playerBinding 
                                                   monitorAdsLoader:adsLoader];

  //...

  // When you send your ad request, you must report it to the IMA listener so it can properly track state
  [_adsListener clientAdRequest:request]; // for Client-Side Ads (the usual case)
  // OR
  [_adsListener daiAdRequest:daiRequest]; // for Dynamic Server-Side Ads (DAI/SSAI)
}
// when the adsLoader fires adsLoadedWithData you get a
// reference to the adsManager. Set your ViewController as the delegate
// for the adsManager
- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
    _adsManager = adsLoadedData.adsManager;
    // Set your adsManager delegate before passing it to adsListener for monitoring
    _adsManager.delegate = self;
    IMAAdsRenderingSettings *adsRenderingSettings = [[IMAAdsRenderingSettings alloc] init];
    adsRenderingSettings.webOpenerPresentingController = self;
    [_adsManager initializeWithAdsRenderingSettings:adsRenderingSettings];
    [_adsListener monitorAdsManager: _adsManager];
}

//
- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdEvent:(IMAAdEvent *)event {
    // When the SDK notified us that ads have been loaded, play them.
    if (event.type == kIMAAdEvent_LOADED) {
        [_adsManager start];
    }
}

- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdError:(IMAAdError *)error {
    [_avplayer play];
}

- (void)adsManagerDidRequestContentPause:(IMAAdsManager *)adsManager {
    [_avplayer pause];
}

- (void)adsManagerDidRequestContentResume:(IMAAdsManager *)adsManager {
    [_avplayer play];
}

```

```swift

import MuxCore
import MUXSDKStats
import GoogleInteractiveMediaAds
import MuxStatsGoogleIMAPlugin

var adsListener: MUXSDKIMAAdListener?

override func viewDidLoad() {
  super.viewDidLoad()
  // Follow the instructions from pod 'GoogleAds-IMA-iOS-SDK' to set up
  // your adsLoader and set your ViewController as the delegate
  //
  // From your ViewController, when you call either
  //    monitorAVPlayerViewController
  //    monitorAVPlayerLayer
  //
  // You will get back a MUXSDKPlayerBinding object

  // Configure your ads loader delegate before initializing MUXSDKIMAAdListener
  adsLoader.delegate = self

  // Setup your content players AVPlayerViewController or AVPlayerLayer
  let playerViewController = AVPlayerViewController()

  let playerBinding = MUXSDKStats.monitorAVPlayerViewController(
    self, 
    withPlayerName: playName, 
    customerData: customerData
  )

  // Use the MUXSDKPlayerBinding object to initialize the MuxImaListener class
  // Save a reference to adsListener, we'll use a property
  let adsListener = MUXSDKIMAAdListener(
    playerBinding: playerBinding!,
    monitorAdsLoader: adsLoader
  )
  self.adsListener = adsListener
  // ... 

  // When you send your ad request, you must report it to the IMA listener so it can properly track state
  adsListener.clientAdRequest(request) // for Client-Side Ads (the usual case)
  // OR
  adsListener.daiAdRequest(daiAdRequest) // for Dynamic Server-Side Ads (SSAI)
}

// the adsLoader delegate will fire this and give access to the adsManager
// the application needs to register as a delegate for the adsManager too
func adsLoader(_ loader: IMAAdsLoader!, adsLoadedWith adsLoadedData: IMAAdsLoadedData!) {
    adsManager = adsLoadedData.adsManager;
    adsManager.delegate = self;
    adsListener?.monitorAdsManager(adsManager)
}

// all of these events get fired by the adsManager delegate
// when this happens, the application needs to do some stuff and send the events
// to our sdk
func adsManager(_ adsManager: IMAAdsManager!, didReceive event: IMAAdEvent!) {
    if (event.type == kIMAAdEvent_LOADED) {
      adsManager.start()
    }
}

func adsManager(_ adsManager: IMAAdsManager!, didReceive error: IMAAdError!)
    avPlayer.play()
}

func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager!) {
    avPlayer.pause()
}

func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager!) {
    avPlayer.play()
}

```



If you have enabled Picture in Picture support and are using the `IMAPictureInPictureProxy`, you will need an additional step in order to track ad related metrics correctly.

```objc

#import<MuxStatsGoogleIMAPlugin/MuxStatsGoogleIMAPlugin.h>

- (void)viewDidLoad {
  // Follow the instructions from pod 'GoogleAds-IMA-iOS-SDK' to set up
  // your adsLoader and set your ViewController as the delegate
  //
  // From your ViewController, when you call either
  //    monitorAVPlayerViewController:withPlayerName:playerData:videoData:
  //    monitorAVPlayerLayer:withPlayerName:playerData:videoData:
  //
  // You will get back a MUXSDKPlayerBinding object
  [MUXSDKPlayerBinding *playerBinding] = [MUXSDKStats monitorAVPlayerViewController:_avplayerController
                                                                     withPlayerName:DEMO_PLAYER_NAME
                                                                       customerData:customerData];
  //
  // Use the MUXSDKPlayerBinding object to initialize the MuxImaListener class
  //
  _adsListener = [[MUXSDKIMAAdListener alloc] initWithPlayerBinding:playerBinding 
                                                   monitorAdsLoader:adsLoader];
  [_adsListener setPictureInPicture:YES];

  //...

  // When you send your ad request, you must report it to the IMA listener so it can properly track state
  [_adsListener clientAdRequest:request]; // for Client-Side Ads (the usual case)
  // OR
  [_adsListener daiAdRequest:daiRequest]; // for Dynamic Server-Side Ads (DAI/SSAI)
}
// when the adsLoader fires adsLoadedWithData you get a
// reference to the adsManager. Set your ViewController as the delegate
// for the adsManager
- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
    _adsManager = adsLoadedData.adsManager;
    // Set your adsManager delegate before passing it to adsListener for monitoring
    _adsManager.delegate = self;
    IMAAdsRenderingSettings *adsRenderingSettings = [[IMAAdsRenderingSettings alloc] init];
    adsRenderingSettings.webOpenerPresentingController = self;
    [_adsManager initializeWithAdsRenderingSettings:adsRenderingSettings];
    [_adsListener monitorAdsManager: _adsManager];
}

//
- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdEvent:(IMAAdEvent *)event {
    // When the SDK notified us that ads have been loaded, play them.
    if (event.type == kIMAAdEvent_LOADED) {
        [_adsManager start];
    }
}

- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdError:(IMAAdError *)error {
    [_avplayer play];
}

- (void)adsManagerDidRequestContentPause:(IMAAdsManager *)adsManager {
    [_avplayer pause];
}

- (void)adsManagerDidRequestContentResume:(IMAAdsManager *)adsManager {
    [_avplayer play];
}

```

```swift

import MuxCore
import MUXSDKStats
import GoogleInteractiveMediaAds
import MuxStatsGoogleIMAPlugin

var adsListener: MUXSDKIMAAdListener?

override func viewDidLoad() {
  super.viewDidLoad()
  // Follow the instructions from pod 'GoogleAds-IMA-iOS-SDK' to set up
  // your adsLoader and set your ViewController as the delegate
  //
  // From your ViewController, when you call either
  //    monitorAVPlayerViewController
  //    monitorAVPlayerLayer
  //
  // You will get back a MUXSDKPlayerBinding object

  // Configure your ads loader delegate before initializing MUXSDKIMAAdListener
  adsLoader.delegate = self

  // Setup your content players AVPlayerViewController or AVPlayerLayer
  let playerViewController = AVPlayerViewController()

  let playerBinding = MUXSDKStats.monitorAVPlayerViewController(
    self, 
    withPlayerName: playName, 
    customerData: customerData
  )

  // Use the MUXSDKPlayerBinding object to initialize the MuxImaListener class
  // Save a reference to adsListener, we'll use a property
  let adsListener = MUXSDKIMAAdListener(
    playerBinding: playerBinding!,
    monitorAdsLoader: adsLoader
  )
  adsListener.setPictureInPicture(true)
  self.adsListener = adsListener
  // ... 

  // When you send your ad request, you must report it to the IMA listener so it can properly track state
  adsListener.clientAdRequest(request) // for Client-Side Ads (the usual case)
  // OR
  adsListener.daiAdRequest(daiAdRequest) // for Dynamic Server-Side Ads (SSAI)
}

// the adsLoader delegate will fire this and give access to the adsManager
// the application needs to register as a delegate for the adsManager too
func adsLoader(_ loader: IMAAdsLoader!, adsLoadedWith adsLoadedData: IMAAdsLoadedData!) {
    adsManager = adsLoadedData.adsManager;
    adsManager.delegate = self;
    adsListener?.monitorAdsManager(adsManager)
}

// all of these events get fired by the adsManager delegate
// when this happens, the application needs to do some stuff and send the events
// to our sdk
func adsManager(_ adsManager: IMAAdsManager!, didReceive event: IMAAdEvent!) {
    if (event.type == kIMAAdEvent_LOADED) {
      adsManager.start()
    }
}

func adsManager(_ adsManager: IMAAdsManager!, didReceive error: IMAAdError!)
    avPlayer.play()
}

func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager!) {
    avPlayer.pause()
}

func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager!) {
    avPlayer.play()
}

```



For a complete example project written in Swift with UIKit, check out the `Example/DemoApp` folder of [muxinc/mux-stats-google-ima](https://github.com/muxinc/mux-stats-google-ima)

You can find more examples in the "/Examples" directory of [muxinc/mux-stats-sdk-avplayer](https://github.com/muxinc/mux-stats-sdk-avplayer) on GitHub. All of these apps have examples with Google IMA ads. `video-demo` is an iOS app written in Swift and `TVDemoApp` is a TVOS app written in objective-c

## Track orientation change events

As of 1.3.0 Mux-Stats-AVPlayer can optionally track `orientationchange` events. To use this functionality, call the `orientationChange(forPlayer:with:)` method.

These events will show up on the events log on the view views page.

```objc

@implementation ViewController

  - (void)viewWillTransitionToSize:(CGSize)size
       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {} completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        [MUXSDKStats orientationChangeForPlayer:DEMO_PLAYER_NAME withOrientation:[self viewOrientationForSize:size]];

    }];
    }

  - (MUXSDKViewOrientation) viewOrientationForSize:(CGSize)size {
      return (size.width > size.height) ? MUXSDKViewOrientationLandscape : MUXSDKViewOrientationPortrait;
  }

@end

```

```swift

class VideoPlayerController: AVPlayerViewController {
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        MUXSDKStats.orientationChange(forPlayer: "playerName", with: self.viewOrientationForSize(size: size))
    }

    func viewOrientationForSize(size: CGSize) -> MUXSDKViewOrientation {
        return (size.width > size.height) ? MUXSDKViewOrientation.landscape : MUXSDKViewOrientation.portrait
    }
}

```



## Usage with AVQueuePlayer

To use with `AVQueuePlayer`  you will need to follow these steps:

1. Listen for `AVPlayerItemDidPlayToEndTime` in your application
2. When that notification fires, call `videoChange(forPlayer:with:)`

Here is an example that sets up a `AVQueuePlayer` with two items, and listener after the first item finishes playing and passes in new `videoData`.

```swift

class AVQueuePlayerViewController: AVPlayerViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        guard let url1 = URL(string: "https://stream.mux.com/xwatk58X7MkCRBA47f01U9bGHt1lklEW5.m3u8") else {
            return
        }
        
        guard let url2 = URL(string: "https://stream.mux.com/HEp7gv53NFjtbZPZB8s02ZiNixXUgYgT7.m3u8") else {
            return
        }
        
        let item1 = AVPlayerItem(url: url1)
        let item2 = AVPlayerItem(url: url2)
        
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(self.playerItemDidReachEnd),
            name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
            object: item1
        )
        
        let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY")
        playerData?.playerName = "AVPlayer"
        
        let videoData = MUXSDKCustomerVideoData()
        videoData.videoIsLive = false
        videoData.videoTitle = "Title1"
        
        guard let customerData = MUXSDKCustomerData(
            customerPlayerData: playerData,
            videoData: videoData,
            viewData: nil
        ) else {
            return
        }
        
        MUXSDKStats.monitorAVPlayerViewController(self, withPlayerName: "AVPlayer", customerData: customerData)
        
        player = AVQueuePlayer(items: [item1, item2])
        player?.play()
    }
    
    @objc func playerItemDidReachEnd(notification: NSNotification) {
        let videoData = MUXSDKCustomerVideoData()
        videoData.videoTitle = "Title2"
        videoData.videoId = "RollerbladingCoder2"
        
        guard let customerData = MUXSDKCustomerData(
            customerPlayerData: nil,
            videoData: videoData,
            viewData: nil
        ) else {
            return
        }
        
        MUXSDKStats.videoChange(forPlayer: "AVPlayer", with: customerData)
    }
}

```



## Overriding device metadata

By default, the Mux Data SDK for iOS collects data about your users' device to report on the dashboard. If you wish to provide your own device metadata, you can use `CustomerViewerData` to override the detected values.

```objc

// ... set up videoData, playerData, etc

MUXSDKCustomerViewerData *viewerData = [[MUXSDKCustomerViewerData alloc] init];
viewerData.viewerApplicationName = @"MUX DemoApp";
viewerData.viewerDeviceCategory = "kiosk";
viewerData.viewerDeviceModel = "ABC-12345";
viewerData.viewerDeviceManufacturer = "Example Display Systems, Inc";
MUXSDKCustomerData *customerData = [[MUXSDKCustomerData alloc] initWithCustomerPlayerData:playerData
                                                                                videoData:videoData
                                                                                  viewData:viewData
                                                                                customData:customData
                                                                                viewerData:viewerData];
_playerBinding = [MUXSDKStats monitorAVPlayerViewController:_avplayerController withPlayerName:DEMO_PLAYER_NAME customerData:customerData];


```

```swift

// ... set up videoData, playerData, etc

let viewerData = MUXSDKCustomerViewerData()
viewerData.viewerDeviceCategory = "kiosk"
viewerData.viewerDeviceModel = "ABC-12345"
viewerData.viewerDeviceManufacturer = "Example Display Systems, Inc"

let customerData = MUXSDKCustomerData(
    customerPlayerData: playerData,
    videoData: videoData,
    viewData: viewData,
    customData: customData,
    viewerData: viewerData
)

```



## Handling errors manually

By default, `automaticErrorTracking` is enabled which means the Mux SDK will catch errors that the player throws and track an `error` event. Error tracking is meant for fatal errors. When an error is thrown it will mark the view as having encountered an error in the Mux dashboard and the view will no longer be monitored.

If you want to disable automatic error tracking and track errors manually, you can do so by passing `false` as the `automaticErrorTracking` parameter to the `monitorAVPlayerLayer`, `monitorAVPlayerViewController`, or `monitorAVPlayer` method you are using.

Whether automatic error tracking is enabled or disabled, you can dispatch errors manually with `dispatchError(_:withMessage:forPlayer:)`.

```objc

_avplayer = player;
_avplayerController.player = _avplayer;

NSString *playerName = @"iOS AVPlayer"
NSString *environmentKey = @"yourEnvironmentKey";

MUXSDKCustomData *customData = [[MUXSDKCustomData alloc] init];
[customData setCustomData1:@"my-custom-dimension"];

MUXSDKCustomerPlayerData *playerData = [[MUXSDKCustomerPlayerData alloc] initWithEnvironmentKey:environmentKey];

MUXSDKCustomerVideoData *videoData = [[MUXSDKCustomerVideoData alloc] init];
videoData.videoTitle = @"Your Video Title";

MUXSDKCustomerViewData *viewData= [[MUXSDKCustomerViewData alloc] init];
viewData.viewSessionId = @"some session id";

MUXSDKCustomerViewerData *viewerData = [[MUXSDKCustomerViewerData alloc] init];
viewerData.viewerApplicationName = @"MUX DemoApp";

MUXSDKCustomerData *customerData = [[MUXSDKCustomerData alloc] initWithCustomerPlayerData:playerData
                                                                                videoData:videoData
                                                                                 viewData:viewData
                                                                               customData:customData
                                                                               viewerData:viewerData];


_playerBinding = [MUXSDKStats monitorAVPlayerViewController:_avplayerController 
                                             withPlayerName:playerName 
                                               customerData:customerData
                                               automaticErrorTracking: NO];

// later you can dispatch an error yourself
[MUXSDKStats dispatchError: @"1234"
               withMessage: @"Something is not right"
                 forPlayer: playerName];

```

```swift

let playerName = "iOS AVPlayer"

let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY")

let videoData = MUXSDKCustomerVideoData()
videoData.videoTitle = "Your Video Title"

guard let customerData = MUXSDKCustomerData(
    customerPlayerData: playerData,
    videoData: videoData,
    viewData: nil,
    customData: nil,
    viewerData: nil
) else {
    return
}

let playerBinding = MUXSDKStats.monitorAVPlayerViewController(
    playerViewController,
    withPlayerName: playerName,
    customerData: customerData,
    automaticErrorTracking: false
)

// Later, you can dispatch an error yourself
MUXSDKStats.dispatchError(
    "1234",
    withMessage: "Something is not right",
    forPlayer: playerName
)

```



## Error Categorization

Set custom error metadata to distinguish between fatal errors or warnings and classify errors as playback failures or business exceptions. Errors categorized as warnings or as business exceptions are not considered playback failures, meaning these errors are excluded from alerting, giving a more accurate picture of the health of your system with less noise from alerts. You can find [more general information on Error Categorization here](/docs/guides/error-categorization).

This is an example of how to categorize an error event to be a warning.

```objc

_avplayer = player;
_avplayerController.player = _avplayer;

NSString *playerName = @"iOS AVPlayer";
NSString *environmentKey = @"yourEnvironmentKey";

MUXSDKCustomData *customData = [[MUXSDKCustomData alloc] init];
[customData setCustomData1:@"my-custom-dimension"];

MUXSDKCustomerPlayerData *playerData = [[MUXSDKCustomerPlayerData alloc] initWithPropertyKey:environmentKey];

MUXSDKCustomerVideoData *videoData = [MUXSDKCustomerVideoData new];
videoData.videoTitle = @"Your Video Title";

MUXSDKCustomerViewData *viewData= [[MUXSDKCustomerViewData alloc] init];
viewData.viewSessionId = @"some session id";

MUXSDKCustomerViewerData *viewerData = [[MUXSDKCustomerViewerData alloc] init];
viewerData.viewerApplicationName = @"MUX DemoApp";

MUXSDKCustomerData *customerData = [[MUXSDKCustomerData alloc] initWithCustomerPlayerData:playerData
                                                                                videoData:videoData
                                                                                 viewData:viewData
                                                                               customData:customData
                                                                               viewerData:viewerData];

_playerBinding = [MUXSDKStats monitorAVPlayerViewController:_avplayerController 
                                             withPlayerName:playerName 
                                               customerData:customerData];

// later you can dispatch an error yourself
[MUXSDKStats dispatchError: @"1234"
               withMessage: @"Something is not right"
                  severity: MUXSDKErrorSeverityWarning
              errorContext: @"Error context"
                 forPlayer: playerName];

```

```swift

let playerName = "iOS AVPlayer"

let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY")

let videoData = MUXSDKCustomerVideoData()
videoData.videoTitle = "Your Video Title"

guard let customerData = MUXSDKCustomerData(
  customerPlayerData: playerData,
  videoData: videoData,
  viewData: nil,
  customData: nil,
  viewerData: nil
) else {
  return
}

let playerBinding = MUXSDKStats.monitorAVPlayerViewController(
  playerViewController,
  withPlayerName: playerName,
  customerData: customerData
)

// Later, you can dispatch an error yourself
MUXSDKStats.dispatchError(
  "1234",
  withMessage: "Something is not right",
  severity: MUXSDKErrorSeverity.warning,
  errorContext: "Error Context",
  forPlayer: playerName
)

```



This is an example of how to categorize an error event as a business exception.

```objc

// Call this method from the source of the business exception with parameters appropriate to your integration.
- (void)dispatchBusinessExceptionWithPlayerName:(NSString *)playerName
                              playerErrorSeverity:(MUXSDKErrorSeverity)errorSeverity
                              playerErrorCode:(NSString *)playerErrorCode
                              playerErrorMessage:(NSString *)playerErrorMessage
                              playerErrorContext:(NSString *)playerErrorContext {
  [MUXSDKStats dispatchError: playerErrorCode,
                 withMessage: playerErrorMessage,
                    severity: MUXSDKErrorSeverityWarning,
         isBusinessException: YES,
                errorContext: playerErrorContext,
                   forPlayer: playerName];
}

```

```swift

// Call this method from the source of the business exception with parameters appropriate to your integration.
func dispatchBusinessException(playerName: String,
                               playerErrorCode: String,
                               playerErrorMessage: String,
                               playerErrorContext: String) {
  MUXSDKStats.dispatchError(
    playerErrorCode,
    withMessage: playerErrorMessage,
    severity: MUXSDKErrorSeverity.warning,
    isBusinessException: true,
    errorContext: playerErrorContext,
    forPlayer: playerName
  )
}

```



## App Store warning: ITMS-90809: Deprecated API Usage

It has come up a few times that users of our iOS library get this warning from Apple.

> Apple will stop accepting submissions of apps that use UIWebView APIs . See https://developer.apple.com/documentation/uikit/uiwebview for more information.

If you run `grep -r "UIWebView" .` in your project you will see a match coming from the `dSYM/` directory in Mux-Core. At first glance, we too thought our SDK was triggering this warning.

However, after looking into this with several different applications we found that the warning was not being triggered by our SDK. In every case it was coming from another 3rd party.

Note that none of the Mux iOS libraries (including `Mux-Core` and `Mux-Stats-AVPlayer`) use `UIWebView`. If you are getting this warning you must have another SDK that is using `UIWebView`.

The reason there is some confusion around this and the reason you get a match in the `dSYM/` directory in Mux-Core is because our SDK links to `UIKit` and targets a version of iOS that *may include* `UIWebView`.  The `dSYM` files are used for debugging purposes and they do not contain any functional code. You may see that this same confusion came up in other SDKs like Mapbox and Stripe (listed below).

### Resources:

* [Mux issue #32](https://github.com/muxinc/mux-stats-sdk-avplayer/issues/32)
* [Mux issue #53](https://github.com/muxinc/mux-stats-sdk-avplayer/issues/53)
* [Mapbox issue #373](https://github.com/mapbox/ios-sdk-examples/issues/373)
* [Stripe issue #82](https://github.com/stripe/stripe-terminal-ios/issues/82#issuecomment-625406168)


# Monitor AndroidX Media3
This guide walks through integration with Google's Media3 to collect video performance metrics with Mux data.
The Mux Data SDK for Media3 integrates Mux Data with Google's [AndroidX Media3](https://developer.android.com/guide/topics/media/media3) SDK in order to integrate your video app with Mux Data. Our SDK consists of a set of [open-source libraries](https://github.com/muxinc/mux-stats-sdk-media3) capable of observing Media3 for events and data related to your customers' playback experience.

This guide will walk you through a basic integration with Mux Data and your Media3 app. You will add the Mux Data SDK to your project, integrate the SDK with your Media3 `Player` and if necessary, learn to customize our SDK's functionality based on your specific needs

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager
- Can infer CDN identification from response headers
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Customizable Error Tracking
- Custom Beacon Domain
- Extraction of HLS Session Data

```

Notes:

```md
Request Latency is not available.
```

<Callout type="warning" title="Players other than `ExoPlayer`">
  Most of this guide assumes you are using `ExoPlayer`, specifically, as opposed to a `MediaController` or a custom implementation of `Player`. Our SDK does offer support for players other than `ExoPlayer`, but this support is limited by the interface of `Player` and `Player.Listener`. You may supplement the data we are able to collect using your `Player`'s specific APIs by overriding `BaseMedia3Binding` and supplying that object when you create your `MuxStatsSdkMedia3<>` for your custom player.
</Callout>

## 1. Install the Mux Data SDK

## Add our repository to your Gradle project

Add Mux's maven repository to your gradle files. Newer projects require declaring this in `settings.gradle`, and older projects require it to be set in the project-level `build.gradle`.

```gradle\_groovy

// in a repositories {} block
maven {
  url 'https://muxinc.jfrog.io/artifactory/default-maven-release-local' 
}

```

```gradle\_kts

// in a repositories {} block
maven {
  url = uri("https://muxinc.jfrog.io/artifactory/default-maven-release-local")
}

```



## Add a dependency for Mux Data

Add our library to the `dependencies` block for your app. Replace the string `[Current Version]` with the current version of the SDK from the [releases page](https://github.com/muxinc/mux-stats-sdk-media3/releases).

```gradle\_kts

implementation("com.mux.stats.sdk.muxstats:data-media3:[Current Version]")
  
```

```gradle\_groovy

implementation "com.mux.stats.sdk.muxstats:data-media3:[Current Version]"
  
```



## Stay on a version of Media3

By default, we try to support the latest minor release of media3 with our SDK. That is, 1.0, 1.1, etc. When media3 updates, we update our `data-media3` library to support the newest version. If you need an update to the Mux Data SDK, but can't update your media3 integration, you can use one of our `-atX_Y` variants. These variants of our Mux Data SDK receive all the same updates as the default version, but offer support for a specific version of media3.

To stay on a specific version of media3, add the appropriate version to the end of our `artifactId`. For example, to always use Media3 1.0.x, use the library at `com.mux.stats.sdk.muxstats:data-media3-at_1_0:[Current Version]`

```gradle\_kts

// Stay on media3 1.0 while getting the most-recent mux data
implementation("com.mux.stats.sdk.muxstats:data-media3-at_1_0:[Current Version]")
  
```

```gradle\_groovy

// Stay on media3 1.0 while getting the most-recent mux data
implementation "com.mux.stats.sdk.muxstats:data-media3-at_1_0:[Current Version]"
  
```



### Officially Supported Media3 Versions

We try to support all production versions of media3. Currently, we support the following versions:

* 1.10.x
* 1.9.x
* 1.8.x
* 1.6.x
* 1.5.x
* 1.4.x
* 1.3.x
* 1.2.x
* 1.1.x
* 1.0.x

## 2. Integrate this SDK with Media 3 in your app

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

To monitor a `Player`, monitor it using `monitorWithMuxData()`. You must initialize your Mux Data integration with a valid Environment Key.

If your player is newly-created, it's best to do this at around the same time that you call `prepare()` or `play()`. Ideally, you should do it synchronously, either right before calling *or* right after you start preparing/playing.

```java

CustomerData myCustomerData = new CustomerData();
MuxStatsSdkMedia3<ExoPlayer> muxStats =
    new MuxStatsSdkMedia3<>(
        /* context = */ context,
        /* envKey = */ "YOUR MUX DATA ENV KEY HERE",
        /* customerData = */ myCustomerData,
        /* player = */ exoPlayer,
        /* playerView = */ playerView,
        /* playerBinding = */ new ExoPlayerBinding()
    );

// Do these after creating the monitor
player.setPlayWhenReady(true);
player.prepare();


// ... When you are done with your Player
muxStats.release();
player.release();

```

```kotlin

val myCustomerData = CustomerData()
val muxStats = exoPlayer.monitorWithMuxData(
  context = context,
  envKey = "YOUR MUX DATA ENV KEY HERE",
  customerData = myCustomerData,
  playerView = playerView
)

// Do these after creating the monitor
player.playWhenReady = true
player.prepare()

// ... When you are done with your Player
muxStats.release()
player.release()

```



### Reusing `Player` instances

If your `Player`'s state was `IDLE` before calling `monitorWithMuxData()` or `enable()`, you should follow the same advice as if you were working with a new `Player` instance: start monitoring either immediately before or right after calling `prepare()` and `play()`. When you start monitoring again, a new View will be created in Mux Data.

The easiest way to get your player into the `IDLE` state is to call `stop()`, though you'll have to call `prepare()` and `play()` again to start playing.

If you want to start monitoring a `Player` instance that was already created and prepared, you should start start monitoring via `monitorWithMuxData()` or `enable()` immediately after you start the player again or set a new `MediaItem`. When you attach a monitor to the `Player` in this case, a new View will be created in Mux Data. In this case, this order is important; you must monitor the player after setting a new `MediaItem` in order to properly count any buffering the player may do.

## 3. Add Metadata

You can make your data more informative and actionable by supplementing it with data of your own. To supply this data, you can use the `CustomerData` object you created in Step 2.

```java

CustomerData myCustomerData = new CustomerData();
CustomerVideoData customerVideoData = new CustomerVideoData();
customerVideoData.setVideoTitle("Sintel");
CustomerViewerData customerViewerData = new CustomerViewerData();
customerViewerData.setMuxViewerDeviceCategory("kiosk");
customerViewerData.setMuxViewerDeviceManufacturer("Example Display Systems");
customerViewerData.setMuxViewerOsVersion("1.2.3-dev");
CustomData customData = new CustomData();
// You can add up to 10 strings to track your own data
customData.setCustomData1("Hello");
customData.setCustomData2("World");
customData.setCustomData3("From");
customData.setCustomData4("Mux");
customData.setCustomData5(":)");
myCustomerData.setCustomerVideoData(customerVideoData);
myCustomerData.setCustomerViewerData(customerViewerData);

// And now create your monitor object, like in step 2

```

```kotlin

val customerData = CustomerData().apply {
  customerVideoData = CustomerVideoData().apply {
    // Data about this video
    // Add or change properties here to customize video metadata such as title,
    //   language, etc
    videoId = "My Custom Video ID"
  }
  customerViewData = CustomerViewData().apply {
    // Data about this viewing session
    viewSessionId = UUID.randomUUID().toString()
  }
  customerViewerData = CustomerViewerData().apply {
    // Data about the Viewer and the device they are using
    muxViewerDeviceCategory = "kiosk"
    muxViewerDeviceManufacturer = "Example Display Systems"
    muxViewerOsVersion = "1.2.3-dev"
  }
  customData = CustomData().apply {
    // Add values for your Custom Dimensions.
    // Up to 10 strings can be set to track your own data
    customData1 = "Hello"
    customData2 = "World"
    customData3 = "From"
    customData4 = "Mux"
    customData5 = "Data"
  }

  // And now call monitorWithMuxData, like in Step 2.

```



Those examples contain only a few of the fields available. For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

All metadata details are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

Certain metadata can be collected automatically, such as the media title, source URL, and poster art.

## 4. Advanced Features

## Changing the video

There are two cases where the underlying tracking of the video view needs to be reset: first, when you load a new source URL into an existing player, and second, when the program within a single media stream changes (such as a program within a live stream, described more below).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

## New source

When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

This is done by calling `muxStatsExoPlayer.videoChange(CustomerVideoData)` which will remove all previous video data and reset all metrics for the video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

It's best to change the video info immediately after telling the player which new source to play.

## New program (in single stream)

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, call `muxStatsExoPlayer.programChange(CustomerVideoData)`. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

## Manually set when a video is being played full-screen

For most use cases, the SDK is capable of detecting whether or not a video is being played full-screen. Specifically, it can do so in the case where the player view is the same size as the device display (excepting ActionBars and other framework window decoration).

For other uses cases (non-overlaid controls, window decoration via plain `View`s, etc) you may need to tell the SDK when the user switches to full-screen.

If you are using `SimplePlayerView` or a similar ExoPlayer UI component, you can set the full-screen flag from the `OnFullScreenModeChangedListener`.

```kotlin
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // If you are using SimplePlayerView, StyledPlayerView, etc
    playerView = findViewById(R.id.my_player_view)

    playerView.setFullscreenButtonClickListener { isFullScreen ->
      // Set presentation based on which mode is requested
      if(isFullScreen) {
        muxStats.presentationChange(MuxSDKViewPresentation.FULLSCREEN)
      } else {
        muxStats.presentationChange(MuxSDKViewPresentation.NORMAL)
      }
      // Handle moving to fullscreen playback with your code
    }
  }
```

## Error tracking

By default, Mux's integration with ExoPlayer automatically tracks fatal errors as thrown by ExoPlayer. If a fatal error happens outside the context of ExoPlayer and you want to track it with Mux, you can call `muxStats.error(MuxErrorException)` like this:

```kotlin
// Error code: integer value for the generic type of error that
// occurred.
// Error message: String providing more information on the error
// that occurred.
// For an example, the HTML5 video element uses the
// following: https://developer.mozilla.org/en-US/docs/Web/API/MediaError
// for codes and messages. Feel free to use your own codes and messages
val errorCode = 1
val errorMessage = "A fatal error was encountered during playback"
val errorContext = "Additional information about the error such as a stack trace"
val error = MuxErrorException(errorCode, errorMessage, errorContext)
muxStats.error(error)
```

Note that `error(MuxErrorException e)` can be used with or without automatic error tracking. If your application has retry logic that attempts to recover from ExoPlayer errors then you may want to disable automatic error tracking like this:

```kotlin
muxStats.setAutomaticErrorTracking(false)
```

<Callout type="warning">
  It is important that you only trigger an error when the playback has to be abandoned or aborted in an unexpected manner, as Mux tracks fatal playback errors only.
</Callout>

## Usage with Google Interactive Media Ads (IMA)

The Mux Data SDK for Media3 can observe events that occur during Ad playback. To enable this functionality, you need to attach an instance of `MuxStatsSdkMedia3<ExoPlayer>` to your `ImaAdsLoader`.

<Callout type="warning">
  The Mux Data SDK must take over the `AdErrorListener` and `AdEventListener` of your loader, but you can supply your own listeners, as shown in the example.
</Callout>

Fist, add Mux's Media3 IMA Extension to your build:

```gradle\_kts

// in your app's dependencies
implementation("com.mux.stats.sdk.muxstats:data-media3-ima:0.7.1")
  
```

```gradle\_groovy

// in your app's dependencies
implementation "com.mux.stats.sdk.muxstats:data-media3-ima:0.7.1"
  
```



Then, use the extension to monitor your IMA integration.

```kotlin

val newPlayer = ExoPlayer.Builder(this)
.setMediaSourceFactory(DefaultMediaSourceFactory(DefaultDataSource.Factory(this))
.setLocalAdInsertionComponents({ adsLoader }, view.playerView))
// ... rest of builder calls
.build()
val customerData = CustomerData()
// optionally, set properties on CustomerData

muxStats = newPlayer.monitorWithMuxData(context, DATA_ENV_KEY, customerData)
adsLoader = ImaAdsLoader.Builder(this)
// ... rest of builder calls
.monitorWith(
  muxStats = muxStats!!,
  customerAdErrorListener = { /*Optional parameter, your custom logic*/ },
  customerAdEventListener = { /*Optional parameter, your custom logic*/ },
)
.build()
adsLoader.setPlayer(newPlayer)
  
```

```java

ExoPlayer player = new ExoPlayer.Builder(this)
  // ... Add IMA components
  .build();

MuxStatsSdkMedia3<ExoPlayer> muxStats =
  new MuxStatsSdkMedia3<>(
      /* context = */ this,
      /* envKey = */ "YOUR MUX DATA ENV KEY HERE",
      /* customerData = */ myCustomerData, // Populated as in Step 2 of the guide
      /* player = */ player,
      /* playerView = */ playerView,
      /* playerBinding = */ new ExoPlayerBinding()
  );

MuxImaAdsListener muxAdsListener = MuxImaAdsListener.newListener(
  muxStats,
  adEvent -> {}, // If you have handling logic for AdEvents, put it here
  adError -> {} // If you have handling logic for Ad Errors, put it here
);
adsLoader = new ImaAdsLoader.Builder(this)
  .setAdErrorListener(muxAdsListener)
  .setAdEventListener(muxAdsListener)
  // Set up rest of AdsLoader
  .build();
adsLoader.setPlayer(player);
  
```



## Manually set the screen orientation

The Mux SDK supports sending an event when the playback orientation changes. You can trigger this by calling `muxStatsExoPlayer.orientationChange(MuxSDKViewOrientation orientation)`, passing either `MuxSDKViewOrientation.LANDSCAPE` or `MuxSDKViewOrientation.PORTRAIT` depending on the current orientation of the player.

## Migrating from the Mux Data SDK for ExoPlayer

If you are updating from our ExoPlayer SDK, you have to do a short migration. The migration steps below should get you building again:

1. Change your Mux Data SDK dependency to `implementation "com.mux.stats.sdk.muxstats:data-media3:1.0.0"`
2. Change all mentions of `MuxStatsExoPlayer` to `MuxStatsSdkMedia3<ExoPlayer>`
3. **If you are using java**, add `new ExoPlayerBinding()` to the end of the parameters you set when creating your `muxStats`.
4. **If you are using the IMA Ads SDK**: You will need to rewrite your integration as explained in Step 4 of this guide.


# Monitor ExoPlayer
This guide walks through integration with Google's ExoPlayer to collect video performance metrics with Mux data.
This documents integration instructions for [Google's `ExoPlayer` library](https://github.com/google/ExoPlayer), version 2.x. `ExoPlayer` versions before 2.0 are not supported. As of version 3.0.0 of Mux's integration with `ExoPlayer`, only versions of `ExoPlayer` greater than or equal to 2.10.x are supported.

The Mux integration with `ExoPlayer` is built on top of Mux's core Java SDK, and the full code can be seen here: [muxinc/mux-stats-sdk-exoplayer](https://github.com/muxinc/mux-stats-sdk-exoplayer).

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager
- Can infer CDN identification from response headers
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Customizable Error Tracking
- Custom Beacon Domain
- Extraction of HLS Session Data
- Live Stream Latency metric

```

Notes:

```md
Request Latency is not available.
```

## 1. Add a dependency on the Mux Data SDK

## Add Gradle dependency on the Mux ExoPlayer SDK

Add the Mux Maven repository to your Gradle file:

```gradle
repositories {
    maven {
        url "https://muxinc.jfrog.io/artifactory/default-maven-release-local"
    }
}
```

Next, add a dependency on the Mux Data ExoPlayer SDK. Supported versions of ExoPlayer are:

* r2.10.6
* r2.11.1
* r2.12.1
* r2.13.1
* r2.14.1
* r2.15.1
* r2.16.1
* r2.17.1
* r2.18.1
* r2.19.1
* `amznPort` (see below)

There is typically API compatibility within an ExoPlayer major-minor version, so you should be able to pair one of the versions listed above with any player sharing the same major-minor version (e.g., the ExoPlayer r2.12.1 version of the Mux ExoPlayer SDK works with ExoPlayer r2.12.0 and r2.12.2 equally well).

Add a dependency to your Gradle file using the Mux SDK version and an ExoPlayer version listed above in the following format:

```gradle
api 'com.mux.stats.sdk.muxstats:MuxExoPlayer_(ExoPlayer SDK version with underscores):(Mux SDK version)'
```

Example using Mux ExoPlayer SDK 2.7.2 and ExoPlayer version r2.16.1:

```gradle
api 'com.mux.stats.sdk.muxstats:MuxExoPlayer_r2_16_1:2.7.2'
```

## Configure ProGuard/R8

If you're using ProGuard or R8, you'll need to add the following line to your app's proguard rules file (eg, `proguard-rules.pro`). This won't change anything about your app binary, it just suppresses a known warning

```
-dontwarn com.google.ads.interactivemedia.v3.api.**
```

#### Amazon ExoPlayer Port

In addition to the versions above, the Mux Data ExoPlayer SDK also supports [Amazon's official ExoPlayer port for Amazon Devices](https://github.com/amzn/exoplayer-amazon-port). If you are monitoring ExoPlayer on an Amazon device, you can get that version with the following line:

```gradle
api 'com.mux.stats.sdk.muxstats:MuxExoPlayer_amznPort:(Mux SDK version)'
```

For an example integration, you can see the demo application within [muxinc/mux-stats-sdk-exoplayer](https://github.com/muxinc/mux-stats-sdk-exoplayer) which integrates Mux into the ExoPlayer demo application.

## 2. Initialize the monitor with your ExoPlayer instance

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

First, create the `CustomerPlayerData` and `CustomerVideoData` objects as appropriate for your current playback

```kotlin
val customerData = CustomerData().apply {
        customerVideoData = CustomerVideoData().apply {
          // Data about this video
          // Add or change properties here to customize video metadata such as title,
          //   language, etc
          videoTitle = "Mux ExoPlayer Android Example"
          // ExoPlayer doesn't provide an API to obtain this, so it must be set manually
          videoSourceUrl = videoUrl
        }
        customerViewData = CustomerViewData().apply {
          // Data about this viewing session
          viewSessionId = UUID.randomUUID().toString()
        }
        customerViewerData = CustomerViewerData().apply {
          // Data about the Viewer and the device they are using
          muxViewerDeviceCategory = "kiosk"
          muxViewerDeviceManufacturer = "Example Display Systems"
          muxViewerOsVersion = "1.2.3-dev"
        }
        customData = CustomData().apply {
          // Add values for your Custom Dimensions.
          // Up to 5 strings can be set to track your own data
          customData1 = "Hello"
          customData2 = "World"
          customData3 = "From"
          customData4 = "Mux"
          customData5 = "Data"
        }
```

Next, create the `MuxStatsExoPlayer` object by passing your `Context` (typically your `Activity`), your `ENV_KEY`, the `ExoPlayer` instance, and the customer data object you just created.

```kotlin
muxStatsExoPlayer = exoPlayer.monitorWithMuxData(
      context = requireContext(),
      envKey = "YOUR_ENV_KEY_HERE",
      playerView = playerView,
      customerData = customerData
    )
```

If you haven't set your `playerView` already, do so now. We recommend this in order to determine a number of viewer context values as well as track the size of the video player.

```java
muxStatsExoPlayer.setPlayerView(simpleExoPlayerView.getVideoSurfaceView());
```

Finally, when you are destroying the player, call the `MuxStatsExoPlayer.release()` function.

```java
muxStatsExoPlayer.release()
```

After you've integrated, start playing a video in your player. A few minutes after you stop watching, you'll see the results in your Mux data dashboard. Login to the dashboard and find the environment that corresponds to your `env_key` and look for video views.

#### Note For ExoPlayer v2.15 and below

On older supported versions of ExoPlayer, Mux prefers that you pass an instance of `SimpleExoPlayer` specifically, instead of any `ExoPlayer`. In the latter case, however, some metrics and errors may not be available, such as upscaling metrics. Updating to ExoPlayer r2.16.0 or higher will remove this limitation

```kotlin
muxStatsExoPlayer = exoPlayer.monitorWithMuxData(
      context = requireContext(),
      envKey = "YOUR_ENV_KEY_HERE",
      playerView = playerView,
      customerData = customerData
    )

```

or in java:

```java
// Make sure to monitor the player before calling `prepare` on the ExoPlayer instance
muxStatsExoPlayer = new MuxStatsExoPlayer(this, "YOUR_ENV_KEY_HERE", player, playerView, customerData);
```

## 3. Add Metadata

Options are provided to this SDK via the objects within the `CustomerData` object.

All metadata details are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

There is one caveat with ExoPlayer; ExoPlayer does not provide an API to retrieve the current source URL from the player. Due to this, `CustomerVideoData` has a method allowing you to set via `CustomerVideoData.setVideoSourceUrl(String url)`. Setting this value will allow you to see the source URL as well as the dimension Source Hostname within the dashboard.

For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Advanced

## Changing the video

There are two cases where the underlying tracking of the video view need to be reset. First, when you load a new source URL into an existing player, and second when the program within a singular stream changes (such as a program within a live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

## New source

When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

This is done by calling `muxStatsExoPlayer.videoChange(CustomerVideoData)` which will remove all previous video data and reset all metrics for the video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

It's best to change the video info immediately after telling the player which new source to play.

## New program (in single stream)

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, call `muxStatsExoPlayer.programChange(CustomerVideoData)`. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

## Manually set when a video is being played full-screen

For most use cases, the SDK is capable of detecting whether or not a video is being played full-screen. Specifically, it can do so in the case where the player view is the same size as the device display (excepting ActionBars and other framework window decoration).

For other uses cases (non-overlaid controls, window decoration via plain `View`s, etc) you may need to tell the SDK when the user switches to full-screen.

If you are using `SimplePlayerView` or a similar ExoPlayer UI component, you can set the full-screen flag from the `OnFullScreenModeChangedListener`.

```kotlin
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // If you are using SimplePlayerView, StyledPlayerView, etc
    playerView = findViewById(R.id.my_player_view)

    playerView.setFullscreenButtonClickListener { isFullScreen ->
      // Set presentation based on which mode is requested
      if(isFullScreen) {
        muxStats.presentationChange(MuxSDKViewPresentation.FULLSCREEN)
      } else {
        muxStats.presentationChange(MuxSDKViewPresentation.NORMAL)
      }
      // Handle moving to fullscreen playback with your code
    }
  }
```

## Error tracking

By default, Mux's integration with ExoPlayer automatically tracks fatal errors as thrown by ExoPlayer. If a fatal error happens outside the context of ExoPlayer and you want to track it with Mux, you can call `muxStatsExoPlayer.error` like this:

```kotlin
// Error code: integer value for the generic type of error that
// occurred.
// Error message: String providing more information on the error
// that occurred.
// For an example, the HTML5 video element uses the
// following: https://developer.mozilla.org/en-US/docs/Web/API/MediaError
// for codes and messages. Feel free to use your own codes and messages
val errorCode = 1
val errorMessage = "A fatal error was encountered during playback"
val errorContext = "Additional information about the error such as a stack trace"
val error = MuxErrorException(errorCode, errorMessage, errorContext)
muxStatsExoPlayer.error(error)
```

Note that `muxStatsExoPlayer.error(MuxErrorException e)` can be used with or without automatic error tracking. If your application has retry logic that attempts to recover from ExoPlayer errors then you may want to disable automatic error tracking like this:

```kotlin
muxStatsExoPlayer.setAutomaticErrorTracking(false)
```

<Callout type="warning">
  It is important that you only trigger an error when the playback has to be abandoned or aborted in an unexpected manner, as Mux tracks fatal playback errors only.
</Callout>

## Usage with Google Interactive Media Ads (IMA)

If you are using Google's IMA SDK to play back ads within your Android application, you can configure Mux to monitor the ad performance by passing your instance of `AdsLoader` to `muxStatsExoPlayer.monitorImaAdsLoader(adsLoader)`.

### ExoPlayer r2.12.x and Up

```kotlin
// For example, within the r2.12.x demo application
// PlayerActivity.getAdsLoader
adsLoader = ImaAdsLoader.Builder(context = this)
    /*
     * This replaces `monitorImaAdsLoader` method because in r2.12.x ImaAdsLoader
     * will create google.v3.AdsLoader on adRequest, which means that monitorImaAdsLoader
     * Will always receive null pointer and will be unable to recieve add events.
     */
    .setAdErrorListener(muxStats.getAdErrorEventListener())
    .setAdEventListener(muxStats.getAdEventListener())
    .build()
```

### ExoPlayer pre-r2.12.x

```kotlin
// Within setting up the AdsMediaSource
sdkFactory = ImaSdkFactory.getInstance()
adsLoader = sdkFactory.createAdsLoader(this)
muxStatsExoPlayer.monitorImaAdsLoader(adsLoader)
```

As of version `1.3.0` and later, the Mux SDK for ExoPlayer supports firing an event when the playback orientation changes. You can trigger this by calling `muxStatsExoPlayer.orientationChange(MuxSDKViewOrientation orientation)`, passing either `MuxSDKViewOrientation.LANDSCAPE` or `MuxSDKViewOrientation.PORTRAIT` depending on the current orientation of the player.

## Java Build Compatibility

## Java and Android Gradle Plugin Build Compatibility

Starting with version `2.6.0`, the Mux SDK for ExoPlayer requires JDK 11 and version 7.0 or greater of the Android Gradle Plugin. This is only a requirement for build compatibility. The Mux SDK for ExoPlayer will remain bytecode-compatible with Java 1.8.

If you are updating from version `2.5.9` or lower, you may need to:

* Update Android Studio to version `2020.x` or greater
* Update your dependency on the Android Build Tools plugin to `7.0.0` or greater
* Update Gradle in `gradle-wrapper.properties` to `7.0.2` or greater
* Ensure your Android Studio is using JDK 11:
  * Go to Android Studio Settings
  * Go `Build, Execution and Deployment` -> `BuildTools` -> `Gradle`
  * If the `Gradle JDK` option is not set to a Java 11 JDK, click the dropdown and select a Java 11 JDK. It should be the default on Studio `2020.x`


# Monitor dash.js
This guide walks through integration with [dash.js](https://github.com/Dash-Industry-Forum/dash.js?) to collect video performance metrics with Mux data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Can infer CDN identification from response headers
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Customizable Error Tracking
- Custom Beacon Domain

```

Notes:

```md
No notes provided
```

## 1. Install mux-embed

Include the Mux JavaScript SDK on every page of your web app that includes video. You can use the Mux-hosted version of the script or install via npm. `mux-embed` follows [semantic versioning](https://semver.org/) and the API will not change between major releases.

```cdn

<script src="https://src.litix.io/core/4/mux.js"></script>

```

```npm

npm install --save mux-embed

```

```yarn

yarn add mux-embed

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

```html

<script>
  if (typeof mux !== 'undefined') {
    window.muxPlayerInitTime = mux.utils.now();
  }
</script>

<video
  id="my-player"
  controls
  width="960"
  height="400"
/>

<script>
  const dashjsPlayer = dashjs.MediaPlayer().create();
  dashjsPlayer.initialize(videoEl, 'https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd', true);

  // Initialize Mux Data monitoring by passing in the "id" attribute of your video player
  if (typeof mux !== 'undefined') {
    const videoEl = document.querySelector('#my-player');

    mux.monitor(videoEl, {
      debug: false,
      dashjs: dashjsPlayer,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata fields
        player_name: 'Main Player', // any arbitrary string you want to use to identify this player
        player_init_time: window.muxPlayerInitTime // ex: 1451606400000
        // ...
      }
    });
  }
</script>

```

```javascript

import dashjs from "dashjs";
import mux from "mux-embed";

const dashjsPlayer = dashjs.MediaPlayer().create();
const videoEl = document.querySelector('#my-player');

dashjsPlayer.initialize(videoEl, 'https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd', true);

mux.monitor(videoEl, {
  debug: false,
  dashjs: dashjsPlayer,
  data: {
    env_key: 'ENV_KEY', // required
    // Metadata fields
    player_name: 'Main Player', // any arbitrary string you want to use to identify this player
    player_init_time: window.muxPlayerInitTime // ex: 1451606400000
    // ...
  }
});

```

```react

import React, { useEffect, useRef } from "react";
import dashjs from "dashjs";
import mux from "mux-embed";

export default function VideoPlayer() {
  const videoRef = useRef(null);
  const src = "https://dash.akamaized.net/envivio/EnvivioDash3/manifest.mpd";

  useEffect(() => {
    let dashjsPlayer;

    if (videoRef.current) {
      const video = videoRef.current;
      const initTime = mux.utils.now();

      dashjsPlayer = dashjs.MediaPlayer().create();
      dashjsPlayer.initialize(video, src, true);

      mux.monitor(video, {
        debug: false,
        // pass in the 'dashjsPlayer' instance
        dashjs: dashjsPlayer,
        data: {
          env_key: "ENV_KEY", // required
          // Metadata fields
          player_name: "Main Player", // any arbitrary string you want to use to identify this player
          player_init_time: initTime
          // ...
        }
      });
    }

    return () => {
      if (dashjsPlayer) {
        dashjsPlayer.destroy();
      }
    };
  }, [videoRef]);

  return (
    <video
      controls
      ref={videoRef}
      style={{ width: "100%", maxWidth: "500px" }}
    />
  );
}

```



Call `mux.monitor` and pass in a valid CSS selector or the video element itself. Followed by the SDK options and metadata. If you use a CSS selector that matches multiple elements, the first matching element in the document will be used.

In the SDK options, be sure to pass in the `dashjs` player instance.

Alternatively, if your player does not immediately have access to the dash.js player instance, you can start monitoring dash.js at any time in the future. In order to do this, you can call either of the following:

```js
mux.addDashJS("#my-player", options)
// or
myVideoEl.mux.addDashJS(options)
```

Log in to the Mux dashboard and find the environment that corresponds to your `env_key` and look for video views. It takes about a minute or two from tracking a view for it to show up on the Metrics tab.

**If you aren't seeing data**, check to see if you have an ad blocker, tracking blocker or some kind of network firewall that prevents your player from sending requests to Mux Data servers.

## 3. Make your data actionable

The only required field in the `options` that you pass into `mux-embed` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` key when calling `mux.monitor`.

```js
mux.monitor('#my-player', {
  debug: false,
  dashjs: dashjsPlayer,
  data: {
    env_key: 'ENV_KEY', // required

    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'

    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000

    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `monitor`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
mux.emit('#my-player', 'videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
mux.emit('#my-player', 'programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
mux.monitor('#my-player', {
  debug: false,
  disableCookies: true,
  dashjs: dashjsPlayer,
  data: {
    env_key: 'ENV_KEY',
    // ... rest of metadata
  }
}
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
mux.monitor('#my-player', {
  debug: false,
  dashjs: dashjsPlayer,
  respectDoNotTrack: true, // Disable tracking of browsers where Do Not Track is enabled
  data: {
    env_key: 'EXAMPLE_ENV_KEY',
    // ... rest of metadata
  }
}
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `mux-embed` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
mux.emit('#my-player', 'error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

mux.monitor('#my-player', {
  debug: false,
  errorTranslator: errorTranslator,
  dashjs: dashjsPlayer,
  data: {
    env_key: 'ENV_KEY', // required

    // ... additional metadata
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
mux.monitor('#my-player', {
  debug: false,
  automaticErrorTracking: false,
  dashjs: dashjsPlayer,
  data: {
    env_key: 'EXAMPLE_ENV_KEY', // required

    // ... additional metadata
  }
```

### Use TypeScript with mux-embed  <BetaTag />

`mux-embed` now provides TypeScript type definitions with the published package! If you want to opt in, you can check out how [here](/docs/guides/monitor-html5-video-element#use-typescript-with-mux-embed--).

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
mux.monitor('#my-player', {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  dashjs: dashjsPlayer,
  data: {
    env_key: 'EXAMPLE_ENV_KEY', // required
    // ... additional metadata
  }
});
```


# Monitor video.js
This guide walks through integration with [video.js](https://videojs.com/) to collect video performance metrics with Mux Data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Available for deployment from a package manager
- Can infer CDN identification from response headers
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Customizable Error Tracking
- Ads metrics
- Custom Beacon Domain
- Extraction of HLS Session Data
- Live Stream Latency metric

```

Notes:

```md
Request metrics and CDN identification are available using `videojs-contrib-hls` or Video.js v7+. Preroll Ads metrics & metadata available if using `videojs-ima`. Session Data is available with Video.js w/ HLS.js.
```

## 1. Install \`videojs-mux\`

Include the Mux JavaScript SDK on every page of your web app that includes video. You can use the Mux-hosted version of the script or install via npm. `videojs-mux` follows [semantic versioning](https://semver.org/) and the API will not change between major releases.

```cdn

<!-- Include videojs-mux after Video.js -->
<script src="/path/to/video.js"></script>
<!-- Include other videojs plugin files here -->
<script src="https://src.litix.io/videojs/4/videojs-mux.js"></script>

```

```npm

npm install --save videojs-mux

```

```yarn

yarn add videojs-mux

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Call video.js like you normally would and include the Mux plugin options.

```html

<video id="my-player" class="video-js vjs-default-skin"  controls>
  <!-- 
      we're using a Mux HLS URL in this example, but the Mux Data integration
      with HLS.js works with any source that plays with video.js
  -->
  <source src="https://stream.mux.com/yb2L3z3Z4IKQH02HYkf9xPToVYkOC85WA.m3u8" type="application/x-mpegURL">
</video>

<script>
  // EITHER initialize Mux Data monitoring like this
  videojs('my-player', {
    plugins: {
      mux: {
        debug: false,
        data: {
          env_key: 'ENV_KEY', // required

          // Metadata
          player_name: '', // ex: 'My Main Player'

          // ... and other metadata
        }
      }
    }
  });


  // OR call the mux function on the player instance
  // var player = videojs('my-player');
  // player.mux({
  //   debug: false,
  //   data: { ... }
  // });
</script>

```

```javascript

import videojs from "video.js";
import "video.js/dist/video-js.css";
import "videojs-mux";

videojs('my-player', {
  plugins: {
    mux: {
      debug: false,
      data: {
        env_key: 'ENV_KEY', // required

        // Metadata
        player_name: '', // ex: 'My Main Player'

        // ... and other metadata
      }
    }
  }
});

```

```react

import React, { useEffect, useRef } from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
import "videojs-mux";

export default function VideoPlayer() {
  const videoRef = useRef(null);
  const playerRef = useRef(null);
  const src = "https://stream.mux.com/yb2L3z3Z4IKQH02HYkf9xPToVYkOC85WA.m3u8";

  useEffect(() => {
    if (videoRef.current) {
      const video = videoRef.current;

      playerRef.current = videojs(video, {
        sources: [{ src, type: "application/x-mpegURL" }],
        plugins: {
          mux: {
            debug: false,
            data: {
              env_key: "ENV_KEY", // required
              // Metadata
              player_name: "", // ex: 'My Main Player'
              // ... and other metadata
            }
          }
        }
      });
    }

    return () => {
      if (playerRef.current) {
        playerRef.current.dispose();
      }
    };
  }, [videoRef]);

  return (
    <video
      controls
      ref={videoRef}
      style={{ width: "100%", maxWidth: "500px" }}
    />
  );
}

```



## 3. Make your data actionable

The only required field in the `options` that you pass into `videojs-mux` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
videojs('#my-player', {
  plugins: {
    mux: {
      debug: false,
      data: {
        env_key: 'ENV_KEY', // required
        // Site Metadata
        viewer_user_id: '', // ex: '12345'
        experiment_name: '', // ex: 'player_test_A'
        sub_property_id: '', // ex: 'cus-1'
        // Player Metadata
        player_name: '', // ex: 'My Main Player'
        player_version: '', // ex: '1.0.0'
        // There is no need to provide player_init_time, tracked automatically
        // player_init_time: '', // ex: 1451606400000;
        // Video Metadata
        video_id: '', // ex: 'abcd123'
        video_title: '', // ex: 'My Great Video'
        video_series: '', // ex: 'Weekly Great Videos'
        video_duration: '', // in milliseconds, ex: 120000
        video_stream_type: '', // 'live' or 'on-demand'
        video_cdn: '' // ex: 'Fastly', 'Akamai'
      }
    }
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first initialize the Mux SDK. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
// player is the instance returned by the `videojs` function
player.mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance returned by the `videojs` function
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance returned by the `videojs` function
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
videojs('#my-player', {
  plugins: {
    mux: {
      debug: false,
      disableCookies: true,
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
videojs('#my-player', {
  plugins: {
    mux: {
      debug: false,
      respectDoNotTrack: true,
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `videojs-mux` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance returned by the `videojs` function
player.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

videojs('#my-player', {
  plugins: {
    mux: {
      debug: false,
      errorTranslator,
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
videojs('#my-player', {
  plugins: {
    mux: {
      debug: false,
      automaticErrorTracking: false,
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```

### Ads tracking with `videojs-mux`

If you are using [`videojs-ima`](https://github.com/googleads/videojs-ima), Brightcove's IMA3 FreeWheel or OnceUX plugins with VideoJS then `videojs-mux` will track ads automatically. No extra configuration is needed.

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
videojs('#my-player', {
  plugins: {
    mux: {
      debug: false,
      beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```


# Monitor React native video
This guide walks through integration with react-native-video to collect video performance metrics with Mux Data.
<Callout type="warning" title="Beta SDK">
  This SDK is currently beta.
  See the [Known Issues](https://github.com/muxinc/mux-stats-sdk-react-native-video#known-issues) and [Caveats](https://github.com/muxinc/mux-stats-sdk-react-native-video#caveats) in the README on GitHub.
</Callout>

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager

```

Notes:

```md
Video Quality metrics are not available.
```

## 1. Install Mux Data SDK

Include the Mux JavaScript SDK on every page of your web app that includes video.

```npm
npm install --save @mux/mux-data-react-native-video
```

```yarn
yarn add @mux/mux-data-react-native-video
```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Wrap your `Video` component with the `muxReactNativeVideo` higher-order-component.

```jsx
import app from './package.json' // this is your application's package.json
import Video from 'react-native-video'; // import Video from react-native-video like your normally would
import muxReactNativeVideo from '@mux/mux-data-react-native-video';

// wrap the `Video` component with Mux functionality
const MuxVideo = muxReactNativeVideo(Video);

// Pass the same props to `MuxVideo` that you would pass to the
// `Video` element. All of these props will be passed through to your underlying react-native-video component
// Include a new prop for `muxOptions`
<MuxVideo
  style={styles.video}
  source={{
    uri:
      'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8',
  }}
  controls
  muted
  muxOptions={{
    application_name: app.name,            // (required) the name of your application
    application_version: app.version,      // the version of your application (optional, but encouraged)
    data: {
      env_key: 'YOUR_ENVIRONMENT_KEY',     // (required)
      video_id: 'My Video Id',             // (required)
      video_title: 'My awesome video',
      player_software_version: '5.0.2',     // (optional, but encouraged) the version of react-native-video that you are using
      player_name: 'React Native Player',  // See metadata docs for available metadata fields /docs/web-integration-guide#section-5-add-metadata
    },
  }}
/>
```

## 3. Make your data actionable

The required fields in the `muxOptions` that you pass into the `MuxVideo` component are `application_name`, `data.env_key` and `data.video_id`. However, without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
  muxOptions={{
    application_name: app.name,            // (required) the name of your application
    application_version: app.version,      // the version of your application (optional, but encouraged)
    data: {
      env_key: 'ENV_KEY',
      // Site Metadata
      viewer_user_id: '', // ex: '12345'
      experiment_name: '', // ex: 'player_test_A'
      sub_property_id: '', // ex: 'cus-1'
      // Player Metadata
      player_name: '', // ex: 'My Main Player'
      player_version: '', // ex: '1.0.0'
      player_init_time: '', // ex: 1451606400000
      // Video Metadata
      video_id: '', // ex: 'abcd123'
      video_title: '', // ex: 'My Great Video'
      video_series: '', // ex: 'Weekly Great Videos'
      video_duration: '', // in milliseconds, ex: 120000
      video_stream_type: '', // 'live' or 'on-demand'
      video_cdn: '' // ex: 'Fastly', 'Akamai'
    },
  }}
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first initialize the Mux SDK. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
MuxVideo.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Advanced options

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
  muxOptions={{
    application_name: app.name,              // (required) the name of your application
    application_version: app.version,        // the version of your application (optional, but encouraged)
    beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
    data: {
      env_key: 'ENV_KEY',
      // Site Metadata
      viewer_user_id: '', // ex: '12345'
      experiment_name: '', // ex: 'player_test_A'
      sub_property_id: '', // ex: 'cus-1'
      // Player Metadata
      player_name: '', // ex: 'My Main Player'
      player_version: '', // ex: '1.0.0'
      player_init_time: '', // ex: 1451606400000
      // Video Metadata
      video_id: '', // ex: 'abcd123'
      video_title: '', // ex: 'My Great Video'
      video_series: '', // ex: 'Weekly Great Videos'
      video_duration: '', // in milliseconds, ex: 120000
      video_stream_type: '', // 'live' or 'on-demand'
      video_cdn: '' // ex: 'Fastly', 'Akamai'
    },
  }}
});
```


# Monitor Kaltura Web
This guide walks through integration with the [Kaltura web player](https://github.com/kaltura/kaltura-player-js) to collect video performance metrics with Mux data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Custom Beacon Domain
- Extraction of HLS Session Data
- Live Stream Latency metric

```

Notes:

```md
No notes provided
```

## 1. Install @mux/mux-data-kaltura

Include the Mux JavaScript SDK on every page of your web app that includes video.

```npm
npm install --save @mux/mux-data-kaltura
```

```yarn
yarn add @mux/mux-data-kaltura
```

```cdn
<script src="https://src.litix.io/kaltura/1/kaltura-mux.js"></script>
```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Under the Kaltura `plugins` option, pass in the mux configuration with key `mux`.

Log in to the Mux dashboard and find the environment that corresponds to your `env_key` and look for video views. It takes about a minute or two from tracking a view for it to show up on the Metrics tab.

**If you aren't seeing data**, check to see if you have an ad blocker, tracking blocker or some kind of network firewall that prevents your player from sending requests to Mux Data servers.

## 3. Make your data actionable

The only required field in the `options` that you pass into `@mux/mux-data-kaltura` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` key, in the `mux` plugin configuration.

```html

<div id="kalturaPlayer" style="width: 560px; height: 395px"></div>
<script>
  var config = {
    targetId: 'kalturaPlayer',
    sources: {
      progressive: [
        {
          mimetype: 'video/mp4',
          url: 'https://muxed.s3.amazonaws.com/leds.mp4',
        },
      ],
    },
    provider: {
      partnerId: 4298703,
    },
    playback: {
      autoplay: false,
    },
    plugins: {
      mux: {
        data: {
          env_key: '<YOUR_ENV_KEY>', // required
          // Metadata
          player_name: 'Kaltura Player', // ex: 'My Main Player'
          // ... and other metadata
        },
      },
    },
  };
  var DEkalturaPlayer = KalturaPlayer.setup(config);
</script>

```

```javascript

import initKalturaMux from "@mux/mux-data-kaltura";

initKalturaMux(KalturaPlayer);

var config = {
  targetId: 'kalturaPlayer',
  sources: {
    progressive: [
      {
        mimetype: 'video/mp4',
        url: 'https://muxed.s3.amazonaws.com/leds.mp4',
      },
    ],
  },
  provider: {
    partnerId: "<PARTNER ID>",
  },
  playback: {
    autoplay: false,
  },
  plugins: {
    mux: {
      data: {
        env_key: '<YOUR_ENV_KEY>', // required
        // Metadata
        player_name: 'Kaltura Player', // ex: 'My Main Player'
        // ... and other metadata
      },
    },
  },
};

KalturaPlayer.setup(config);

```



For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first initialize the Mux SDK. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
// player is the instance returned by the `KalturaPlayer.setup` function
player.mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance returned by the `KalturaPlayer.setup` function
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance returned by the `KalturaPlayer.setup` function
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
var kalturaPlayer = KalturaPlayer.setup({
  // ...
  plugins: {
    mux: {
      debug: false,
      disableCookies: true,
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
var kalturaPlayer = KalturaPlayer.setup({
  // ...
  plugins: {
    mux: {
      respectDoNotTrack: true,
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `@mux/mux-data-kaltura` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance returned by the `KalturaPlayer.setup` function
player.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

var kalturaPlayer = KalturaPlayer.setup({
  // ...
  plugins: {
    mux: {
      errorTranslator,
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
var kalturaPlayer = KalturaPlayer.setup({
  // ...
  plugins: {
    mux: {
      automaticErrorTracking: false,
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```

### Ads tracking with `@mux/mux-data-kaltura`

Mux supports Kaltura's playkit-js-ima plugin for pre-, mid-, and post-roll ads. Simply configure these plugins as you would normally, and Mux will track ads automatically. No additional configuration is needed.

Other Kaltura ad integrations have not been tested, but may work out of the box. Please contact us with any questions.

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
var kalturaPlayer = KalturaPlayer.setup({
  // ...
  plugins: {
    mux: {
      beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
      data: {
        env_key: "ENV_KEY",
        // ...
      }
    }
  }
});
```


# Monitor Kaltura Player (iOS and tvOS)
This guide walks through integration with iOS and TVOS Kaltura player to collect video performance metrics with Mux data.
Mux Data `Mux-Stats-Kaltura` supports iOS 13.0 or newer and tvOS 13.0 or newer. The Mux integration with Kaltura is built on top of Mux's core Objective-C SDK, and the full code can be seen here: [muxinc/mux-stats-sdk-kaltura-ios](https://github.com/muxinc/mux-stats-sdk-kaltura-ios).

This SDK is built with `XCFramework` bundle type and supports Mac Catalyst.

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Customizable Error Tracking
- Ads metrics

```

Notes:

```md
Packaged with: cocoapods.
```

## 1. Install the Mux Data SDK

## Installing with SwiftPM

1. In Xcode click "File" > "Swift Packages" > "Add Package Dependency..."
2. The package repository URL is `https://github.com/muxinc/mux-stats-sdk-kaltura-ios.git`
3. Click `next`.
4. Select dependency resolution options. We recommend setting the "Rules" to install the latest version and choosing the option "Up to Next Major".

Note that `MUXSDKStatsKaltura` has a dependency on `MuxCore`, so you will see that `MuxCore` gets installed as well.

> As of Xcode 14.3.1 integrating the Mux SDKs as part of a shared framework using Swift Package Manager is now supported.

## Installing with CocoaPods

To install with CocoaPods, modify your Podfile to use frameworks by including `use_frameworks!` and then add the following pods to your Podfile:

```
pod 'Mux-Stats-Kaltura', '~>3.0'
```

This will install `Mux-Stats-Kaltura` and the latest current release of our [core Objective-C Library](https://github.com/muxinc/stats-sdk-objc). There will be no breaking updates in major versions, so you can safely run `pod update` for future versions.

Next, add correct import statement into your application.

```swift
import MUXSDKKaltura
```

## 2. Initialize the monitor for your Kaltura player instance

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

The example below uses `monitorPlayer:player:playerName:customerData:`.

The `playerName` parameter is a string that identifies this instance of your player. When calling `destroyPlayer` later on, you will need this string. Each instance of a player that runs simultaneously in your application should have a different `playerName`.

```swift

let playerName = "iOS KalturaPlayer"
let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY")
playerData?.playerName = self.playerName

let videoData = MUXSDKCustomerVideoData()
videoData.videoTitle = "Title Video Kaltura"
videoData.videoId = "my-video-id"

let viewData = MUXSDKCustomerViewData()
viewData.viewSessionId = "my-session-id"

let customData = MUXSDKCustomData()
customData.customData1 = "my-custom-data"

let viewerData = MUXSDKCustomerViewerData()
viewerData.viewerApplicationName = "my-app-name"

let customerData = MUXSDKCustomerData(
    customerPlayerData: playerData,
    videoData: videoData,
    viewData: viewData,
    customData: customData,
    viewerData: viewerData
)

guard let player = self.kalturaPlayer, let data = customerData else {
    return
}

MUXSDKStats.monitorPlayer(
    player: player,
    playerName: playerName,
    customerData: data
)

```



For more complete examples check the [demo apps in the repo](https://github.com/muxinc/mux-stats-sdk-kaltura-ios/tree/main/apps/DemoApp).

After you've integrated, start playing a video in your player. A few minutes after you stop watching, you'll see the results in your Mux data dashboard. Login to the dashboard and find the environment that corresponds to your `env_key` and look for video views.

## 3. Make your data actionable

The only required field is `env_key`. But without some more metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Metadata fields are provided via the `MUXSDKCustomerPlayerData` and `MUXSDKCustomerVideoData` objects.

For the full list of properties view the header files for this interfaces:

* [MUXSDKCustomerPlayerData.h](https://github.com/muxinc/stats-sdk-objc/blob/master/XCFramework/MuxCore.xcframework/ios-arm64/MuxCore.framework/Headers/MUXSDKCustomerPlayerData.h)
* [MUXSDKCustomerVideoData.h](https://github.com/muxinc/stats-sdk-objc/blob/master/XCFramework/MuxCore.xcframework/ios-arm64/MuxCore.framework/Headers/MUXSDKCustomerVideoData.h)

For more details about each property, view the [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) guide.

```swift

let playerName = "My Main Player"
let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY")
playerData.experimentName = "player_test_A"
playerData.playerName = playerName
playerData.playerVersion = "1.0.0"

let videoData = MUXSDKCustomerVideoData()
videoData.videoId = "abcd123"
videoData.videoTitle = "My Great Video"
videoData.videoSeries = "Weekly Great Videos"
videoData.videoDuration = 120000 // in milliseconds
videoData.videoIsLive = false
videoData.videoCdn = "cdn"

let viewData = MUXSDKCustomerViewData()
viewData.viewSessionId = "my session id"

let customData = MUXSDKCustomData()
customData.customData1 = "Custom data 1"
customData.customData2 = "Custom Data 2"

let viewerData = MUXSDKCustomerViewerData()
viewerData.viewerApplicationName = "MUX Kaltura DemoApp"

let customerData = MUXSDKCustomerData(
    customerPlayerData: playerData,
    videoData: videoData,
    viewData: viewData,
    customData: customData,
    viewerData: viewerData
)

guard let player = self.kalturaPlayer, let data = customerData else {
    return
}

MUXSDKStats.monitorPlayer(
    player: player,
    playerName: playerName,
    customerData: data
)

```



## 4. Set or update metadata after monitor

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call  `monitorPlayer`. Then, once you have the metadata, you can update the metadata with the  `setCustomerDataForPlayer`  method.

```swift

// Sometime later before the player is destroyed you can do this:
// The player name ("iOS KalturaPlayer" in this example) should be a player that
// you have already called `monitorPlayer` method with
let videoData = MUXSDKCustomerVideoData()
videoData.videoTitle = "Big Buck Bunny"
videoData.videoSeries = "Updated animation"
// In this example we are updating videoData, but the same can be done
// for updating playerData, customData or viewData
// the values in customerData passed as nil will keep previously set data
// viewerData can't be updated
guard let customerData = MUXSDKCustomerData(
    customerPlayerData: nil,
    videoData: videoData,
    viewData: nil,
    customData: nil,
    viewerData: nil
) else {
    return
}
MUXSDKStats.setCustomerDataForPlayer(name: "iOS KalturaPlayer", customerData: customerData)

```



## 5. Advanced

## Changing the Video

​
There are two cases where the underlying tracking of the video view need to be reset. First, when you load a new source URL into an existing player, and second when the program within a singular stream changes (such as a program within a live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).
​

### New source

​
When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:
​

* The player advances to the next video in a playlist
* The user selects a different video to play
  ​
  This is done by calling  `videoChangeForPlayer`  which will remove all previous video data and reset all metrics for the video view. You can include any metadata when changing the video but you should only need to update the values that start with  `video_`.
  ​
  It is required to call  `videoChangeForPlayer`  immediately before telling the player which new source to play.
  ​

```swift

// Example of changing the media in Kaltura Player
// Call MUX videoChange before stop, because playkit stop will replace current item for nil
let playerData = MUXSDKCustomerPlayerData(environmentKey: self.environmentKey)
playerData?.playerName = self.playerName
        
let videoData = MUXSDKCustomerVideoData()
videoData.videoTitle = "Apple Video Kaltura"
videoData.videoId = "apple"
videoData.videoSeries = "conference"
        
let viewData = MUXSDKCustomerViewData()
viewData.viewSessionId = "my second session id"
        
let customData = MUXSDKCustomData()
customData.customData1 = "Kaltura test video change"
        
let viewerData = MUXSDKCustomerViewerData()
viewerData.viewerApplicationName = "MUX Kaltura DemoApp"
        
guard let customerData = MUXSDKCustomerData(
    customerPlayerData: playerData,
    videoData: videoData,
    viewData: viewData,
    customData: customData,
    viewerData: viewerData
) else {
    return
}
        
MUXSDKStats.videoChangeForPlayer(name: "iOS KalturaPlayer", customerData: customerData)
// Change media in your player (your steps may vary)
// For example:

// Resets The Player And Prepares for Change Media
self.kalturaPlayer?.stop()
        
// Prepare PlayKit player
self.kalturaPlayer?.prepare(newMediaConfig)
        
// Wait for `canPlay` event to play
self.kalturaPlayer?.addObserver(self, events: [PlayerEvent.canPlay]) { event in
    self.kalturaPlayer?.play()
}

```



​

### New program (in single stream)

​
In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.
​
In this case, call  `programChangeForPlayer:name:customerData`. This will remove all previous video data and reset all metrics for the video view, creating a new video view. You can include any metadata when changing the video but you should only need to update the values that start with  `video`.

## Usage with Google Interactive Media Ads (IMA)

If you are using Google Interactive Media Ads and the `PlayKit_IMA` SDK, you can track ad playback events by installing the `mux-stats-google-ima-kaltura-ios` companion package.

Please note: A fully functioning `PlayKit_IMA` integration is required for ad playback tracking in your iOS or tvOS application.

Add the following to your Podfile and run `pod install`

```
'Mux-Stats-Google-IMA-Kaltura' ~> '2.0.0'
```

Initialize the Mux monitor with `MUXSDKStats.monitorPlayer`. Create an listener instance by calling `MUXSDKImaKalturaListener(playerBinding: playerBinding, player: player)`.
Start dispatching the events by calling `start` on the listener instance.

```swift
import MUXSDKStatsKaltura

// Follow the instructions from pod 'PlayKit_IMA' to set up
// your IMA plugin configuration in the loadPlayer method
//
// When you call `monitorPlayer:withPlayer:playerName:customerData:`
// from your ViewController, you will get back a MUXSDKPlayerBinding object
let playerBinding = MUXSDKStats.monitorPlayer(
  player: player,
  playerName: self.playerName,
  customerData: data
)

// Use the MUXSDKPlayerBinding object and the Player instance to initialize the MUXSDKImaKalturaListener class
// and call start on the listener object
let listener = MUXSDKImaKalturaListener(playerBinding: playerBinding, player: player)
listener.start()
```

You can find a [complete example here](https://github.com/muxinc/mux-stats-sdk-kaltura-ios/tree/main/apps/DemoApp).

## Track orientation change events

You can optionally track  `orientationchange`  events. To use this functionality, call the  `orientationChangeForPlayer`  method.
​
These events will show up on the events log on the view views page.

```swift

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    let orientation = UIDevice.current.orientation.isLandscape ? MUXSDKViewOrientation.landscape : MUXSDKViewOrientation.portrait
    MUXSDKStats.orientationChangeForPlayer(name: "iOS KalturaPlayer", orientation: orientation)
}

```



## Handling errors manually

By default,  `automaticErrorTracking`  is enabled which means the Mux SDK will catch errors that the player throws and track an  `error`  event. Error tracking is meant for fatal errors. When an error is thrown it will mark the view as having encountered an error in the Mux dashboard and the view will no longer be monitored.
​
If you want to disable automatic and track errors manually you can do by passing in  `automaticErrorTracking: false`  to the  `monitorPlayer`  method that you are using.
​
Whether automatic error tracking is enabled or disabled, you can dispatch errors manually with  `dispatchError`.

```swift

let playerName = "iOS KalturaPlayer"   
let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY")
// ...insert player metadata

let videoData = MUXSDKCustomerVideoData()
// ...insert video metadata

let customerData = MUXSDKCustomerData(customerPlayerData: playerData, videoData: videoData, viewData: nil, customData: nil, viewerData: nil)

guard let player = self.kalturaPlayer, let data = customerData else {
    return
}

MUXSDKStats.monitorPlayer(player: player, playerName: self.playerName, customerData: data, automaticErrorTracking: false)

// Later, you can dispatch an error yourself
MUXSDKStats.dispatchErrorForPlayer(name: playerName, code: "1234", message: "Something is not right")

```



# Monitor Kaltura Player (Android)
This guide walks through integration with the [Kaltura PlayKit and TVPlayer for Android](https://github.com/kaltura/playkit-android) to collect video performance metrics with Mux Data.
This documents integration instructions for [Kaltura PlayKit and TVPlayer for Android](https://github.com/kaltura/playkit-android) version v4.16.0 or higher.

The Mux integration with `Kaltura` is built on top of Mux's core Java SDK, and the full code can be seen here: [muxinc/mux-stats-sdk-kaltura-android](https://github.com/muxinc/mux-stats-sdk-kaltura-android).

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Ads metrics
- Ads metadata

```

Notes:

```md
No notes provided
```

## 1. Install the Mux Data SDK

Add the Mux Maven repository to your Gradle file:

```text
repositories {
    maven {
        url "https://muxinc.jfrog.io/artifactory/default-maven-release-local"
    }
}
```

Next, add a dependency to your Gradle file using the Mux SDK version in the following format:

```text
api 'com.mux.stats.sdk.muxstats:MuxKalturaSDK:(Mux SDK version)'
```

Example using Mux Kaltura SDK 0.1.0:

```text
api 'com.mux.stats.sdk.muxstats:MuxKalturaSDK:0.1.0'
```

## 2. Initialize the monitor with your Kaltura player instance

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Our SDK supports Kaltura PlayKit and TVPlayer v4.16.0 or higher.

First, create the `CustomerPlayerData` and `CustomerVideoData` objects as appropriate for your current playback, and be sure to set your `ENV_KEY`.

```java
import com.mux.stats.core.model.CustomerData;
import com.mux.stats.core.model.CustomerPlayerData;
import com.mux.stats.core.model.CustomerVideoData;
import com.mux.stats.core.model.CustomerViewData;
// ...
CustomerPlayerData customerPlayerData = new CustomerPlayerData();
customerPlayerData.setEnvironmentKey("ENV_KEY");
CustomerVideoData customerVideoData = new CustomerVideoData();
customerVideoData.setVideoTitle("The most epic video ever");
CustomerViewData customerViewData = new CustomerViewData();
customerViewData.setViewSessionId("A26C4C2F-3C8A-46FB-885A-8D973F99A998");
CustomerData customerData = new CustomerData(customerPlayerData, customerVideoData, customerViewData);
```

Next, create the `MuxStatsKaltura` object by passing your Android `Context` (typically your `Activity`), the player instance, a player name, and the customer data object. The following example shows how to instantiate the SDK using the TVPlayer "KalturaPlayer" (represented by the variable `player`). For a PlayKit-only player just pass in your raw `com.kaltura.playkit.Player` reference in place of the KalturaPlayer.

```java
MuxNetworkRequests network = new MuxNetworkRequests();
muxStats = new MuxStatsKaltura(this, player, "my-player-name", customerData, new CustomOptions().setSentryEnabled(false), network);
```

In order to correctly monitor if the player is full-screen, provide the screen size to the `MuxStatsKaltura` instance.

```java
Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
muxStats.setScreenSize(size.x, size.y);
muxStats.enableMuxCoreDebug(true, false);
```

Finally, when you are destroying the player, call the `MuxStatsKaltura.release()` method.

```java
muxStats.release()
```

After you've integrated, start playing a video in your player. A few minutes after you stop watching, you'll see the results in your Mux data dashboard. Login to the dashboard and find the environment that corresponds to your `env_key` and look for video views.

## 3. Add Metadata

In the Java SDK, options are provided via the `CustomerPlayerData`, `CustomerVideoData`, and `CustomerViewData` objects.

All metadata details except for `envKey` are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Advanced

## Changing the video

There are two cases where the underlying tracking of the video view must be reset. First, when you load a new source URL into an existing player, and second when the program within a singular stream changes (such as a program within a live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

## New source

When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

This is done by calling `MuxStatsKaltura.videoChange(CustomerVideoData)` which will remove all previous video data and reset all metrics for the video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

It's best to change the video info immediately after telling the player which new source to play.

## New program (in single stream)

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, call `MuxStatsKaltura.programChange(CustomerVideoData)`. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

## Error tracking

By default, Mux's integration with Kaltura automatically tracks fatal errors as thrown by the Kaltura player. If a fatal error happens outside the context of Kaltura player and you want to track it with Mux, you can call `MuxStatsKaltura.error` like this:

```java
// Error code: integer value for the generic type of error that
// occurred.
// Error message: String providing more information on the error
// that occurred.
// For an example, the HTML5 video element uses the
// following: https://developer.mozilla.org/en-US/docs/Web/API/MediaError
// for codes and messages. Feel free to use your own codes and messages
int errorCode = 1;
String errorMessage = "A fatal error was encountered during playback";
MuxErrorException error = new MuxErrorException(errorCode, errorMessage);
muxStats.error(error);
```

Note that `MuxStatsKaltura.error(MuxErrorException e)` can be used with or without automatic error tracking. If your application has retry logic that attempts to recover from Kaltura player errors then you may want to disable automatic error tracking like this:

```java
muxStats.setAutomaticErrorTracking(false)
```

<Callout type="warning">
  It is important that you only trigger an error when the playback has to be abandoned or aborted in an unexpected manner, as Mux tracks fatal playback errors only.
</Callout>

### Sentry

In order to improve our SDKs, Mux utilizes [Sentry](https://sentry.io) to track exceptions that our SDK may throw. No personal data is captured by Mux's SDK in these error reports, but if you want to disable this functionality, you can. This should be managed through the `CustomOptions` object passed to the constructor.

```java
muxStats = new MuxStatsKaltura(this, player, "my-player-name", customerData, new CustomOptions().setSentryEnabled(false), network);
```


# Monitor JW Player
This guide walks through integration with [JW Player](https://www.jwplayer.com/) for the web to collect video performance metrics with Mux data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Available for deployment from a package manager
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Customizable Error Tracking
- Ads metrics
- Custom Beacon Domain
- Extraction of HLS Session Data
- Live Stream Latency metric

```

Notes:

```md
No notes provided
```

## 1. Install \`@mux/mux-data-jwplayer\`

Include the Mux JavaScript SDK on every page of your web app that includes video.

```npm
npm install --save @mux/mux-data-jwplayer
```

```yarn
yarn add @mux/mux-data-jwplayer
```

```cdn

<!-- Include jwplayer-mux after the core JW Player JavaScript file -->
<!--  Note that the KEY in the example should be replaced with the key
provided by JW Player for your account. -->
<script src="https://content.jwplatform.com/libraries/KEY.js"></script>
<script src="https://src.litix.io/jwplayer/4/jwplayer-mux.js"></script>

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

```html

<!--Call jwplayer like you normally would and get a reference to the player.
Call initJWPlayerMux with the player reference and the SDK options.-->

<div id="my-player"></div>
<script>
  const conf = {
    // Insert JW Player configuration here
  };

  const playerInitTime = initJWPlayerMux.utils.now();
  const player = jwplayer('my-player').setup(conf);

  // Initialize Mux Data monitoring
  initJWPlayerMux(player, {
    debug: false,
    data: {
      env_key: 'EXAMPLE_ENV_KEY', // required

      // Metadata
      player_name: '', // ex: 'My Main Player'
      player_init_time: playerInitTime // ex: 1451606400000

      // ... and other metadata
    }
  });
</script>

```

```javascript

import initJWPlayerMux from '@mux/mux-data-jwplayer';

const conf = {
  // Insert JW Player configuration here
};
const playerInitTime = initJWPlayerMux.utils.now();
const player = jwplayer('my-player').setup(conf);

initJWPlayerMux(player, {
  debug: false,
  data: {
    env_key: 'EXAMPLE_ENV_KEY', // required

    // Metadata
    player_name: '', // ex: 'My Main Player'
    player_init_time: playerInitTime // ex: 1451606400000

    // ... and other metadata
  }
});

```



Be sure to call `initJWPlayerMux` immediately after initializing JW Player so that Mux can attach as soon as possible.

## 3. Make your data actionable

The only required field in the `options` that you pass into `@mux/mux-data-jwplayer` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
initJWPlayerMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000, you can use `initJWPlayerMux.utils.now()`
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `initJWPlayerMux`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
// player is the instance returned by the `jwplayer` function
player.mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance returned by the `jwplayer` function
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance returned by the `jwplayer` function
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
initJWPlayerMux(player, {
  debug: false,
  disableCookies: true,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
initJWPlayerMux(player, {
  debug: false,
  respectDoNotTrack: true,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `@mux/mux-data-jwplayer` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance returned by the `jwplayer` function
player.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

initJWPlayerMux(player, {
  debug: false,
  errorTranslator,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
initJWPlayerMux(player, {
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Ads tracking with `@mux/mux-data-jwplayer`

Mux supports JW Player's VAST integration for pre-, mid-, and post-roll ads. Simply configure these plugins as you would normally, and Mux will track ads automatically. No additional configuration is needed.

Other JW Player ad integrations, such as Google IMA and FreeWheel have not been tested, but may work out of the box. Please contact us with any questions.

### Latency metrics with `@mux/mux-data-jwplayer`

Mux supports latency metrics by parsing the incoming HLS manifest. JW Player allows us to intercept the manifest response using an [`onXhrOpen` hook](https://docs.jwplayer.com/players/reference/playlists#playlistsources).
This is not available in Safari browsers where HLS is played natively.

```js
var player = jwplayer('my-player').setup({
  playlist: [{
    sources: [{
      file: 'video.m3u8',
      onXhrOpen: function(xhr, url) {
        player.mux && player.mux.onXhrOpen(xhr, url);
      }
    }]
  }]
});

// Initialize Mux Data monitoring
initJWPlayerMux(player, {
  // ...
});
```

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
initJWPlayerMux(player, {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```


# Monitor JW Player (iOS)
This guide walks through integration with [JW Player](https://www.jwplayer.com/) for the web to collect video performance metrics with Mux data.
In order to integrate Mux Data tracking for your JW Player, you will need to be using JW Player `3.x` or later. You will need to already have a JW Player license key and an iOS app with a working implementation of `JWPlayer-SDK`.

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Live Stream Latency metric

```

Notes:

```md
No notes provided
```

## 1. Install Mux Data SDK

```
pod 'Mux-Stats-JWPlayer', '~> 0.3'
```

This will install `Mux-Stats-JWPlayer` and the latest current release of our [core Objective-C library](https://github.com/muxinc/stats-sdk-objc).

## 2. Initialize the Mux monitor

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Next, import `MUXSDKStatsJWPlayer` into your application and call `MUXSDKStatsJWPlayer.monitorJWPlayerController`, passing in your JW player instance and metadata.

```swift
import MUXSDKStatsJWPlayer;

class VideoPlayerController: UIViewController {
   var player: JWPlayerController?

  override func viewDidLoad ()
      super.viewDidLoad()
    let config = JWConfig()
    config.file = "http://example.com/hls.m3u8"
    player = JWPlayerController(config: config)
  }

  override func viewDidAppear(_ animated: Bool) {
      super.viewDidAppear(animated)
        player!.view!.frame = self.view.bounds
      view.addSubview(player!.view)

      let playName = "iOS JW player"
      let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY");
      // insert player metadata
      let videoData = MUXSDKCustomerVideoData();
      // insert video metada
      MUXSDKStatsJWPlayer.monitorJWPlayerController(player!, name: playName, delegate: nil, playerData: playerData!, videoData: videoData)
            player!.play()
  }
}
```

## Register a delegate (optional)

If your own ViewController implements `<JWPlayerDelegate>` and you want to use it, then pass that in as the delegate argument to `monitorJWPlayerController`. See the example below:

```swift
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    player!.view!.frame = self.view.bounds
    view.addSubview(player!.view)

    let playName = "iOS JW player"
    let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY");
    // insert player metadata
    let videoData = MUXSDKCustomerVideoData();
    // insert video metada
    // pass in `self` as the delegate
    MUXSDKStatsJWPlayer.monitorJWPlayerController(player!, name: playName, delegate: self, playerData: playerData!, videoData: videoData)
    player!.play()
}

// example of implementing a delegate method
func onReady(_ event: JWEvent & JWReadyEvent) {
  // this will get called when JWPlayer triggers onPlay
}
```

## 3. Make your data actionable

The only required field is `env_key`. But without some more metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Metadata fields are provided via the `MUXSDKCustomerPlayerData` and `MUXSDKCustomerVideoData` objects.

For the full list of properties view the header files for this interfaces:

* [MUXSDKCustomerPlayerData.h](https://github.com/muxinc/stats-sdk-objc/blob/master/XCFramework/MuxCore.xcframework/ios-arm64/MuxCore.framework/Headers/MUXSDKCustomerPlayerData.h)
* [MUXSDKCustomerVideoData.h](https://github.com/muxinc/stats-sdk-objc/blob/master/XCFramework/MuxCore.xcframework/ios-arm64/MuxCore.framework/Headers/MUXSDKCustomerVideoData.h)

For more details about each property, view the [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) guide.

```swift
let playName = "iOS AVPlayer"
let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY");
playerData.viewerUserId = "1234"
playerData.experimentName = "player_test_A"
// note that the 'playerName' field here is unrelated to the 'playName' variable above
playerData.playerName = "My Main Player"
playerData.playerVersion = "1.0.0"

let videoData = MUXSDKCustomerVideoData();
videoData.videoId = "abcd123"
videoData.videoTitle = "My Great Video"
videoData.videoSeries = "Weekly Great Videos"
videoData.videoDuration = 120000 // in milliseconds
videoData.videoIsLive = false
videoData.videoCdn = "cdn"

MUXSDKStatsJWPlayer.monitorJWPlayerController(player!, name: playName, delegate: self, playerData: playerData!, videoData: videoData)
```


# Monitor Android MediaPlayer
This guide walks through integration with Android MediaPlayer to collect video performance metrics with Mux data.
This documents integration instructions for Android's MediaPlayer class. This integration supports Android 4.2 (API level 17) and newer, though older versions of Android have spotty support for streaming protocols such as HLS and Dash.

The Mux integration with MediaPlayer is built on top of Mux's core Java SDK, and the full code can be seen here: [muxinc/mux-stats-sdk-mediaplayer](https://github.com/muxinc/mux-stats-sdk-mediaplayer).

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager

```

Notes:

```md
Video Quality metrics are not available.
```

## 1. Install the Mux Data SDK

The easiest way to get the AAR is to download the latest version from: [muxinc/mux-stats-sdk-mediaplayer releases](https://github.com/muxinc/mux-stats-sdk-mediaplayer/releases).

If you would prefer to build it yourself, first clone [the repo](https://github.com/muxinc/mux-stats-sdk-mediaplayer). Then, you can do one of the following:

1. Open the project in Android Studio and build the release variant of the `MuxMediaPlayer` module. You can then Find the AAR in `mux-stats-sdk-mediaplayer/MuxMediaPlayer/build/outputs/aar/MuxMediaPlayer-release.aar`
2. Build the AAR directly:

```sh
./gradlew :MuxMediaPlayer:assembleRelease
```

We recommend using Android Studio's new module tool which can be accessed via `File > New > New Module...`. Select the `Import .JAR/.AAR Package` and then select the `mux.aar` that you downloaded or built. This should correctly configure the IDE as well as modify your build configuration (Gradle/Maven).

For an example integration, you can see the demo application within [this repo](https://github.com/muxinc/mux-stats-sdk-mediaplayer) which integrates Mux into the MediaPlayer demo application.

## 2. Initialize the monitor with your MediaPlayer instance

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

First, create the `CustomerPlayerData` and `CustomerVideoData` objects as appropriate for your current playback, and be sure to set your `ENV_KEY`.

```java
import com.mux.stats.core.models.CustomerPlayerData;
import com.mux.stats.core.models.CustomerVideoData;
// ...
CustomerPlayerData customerPlayerData = new CustomerPlayerData();
customerPlayerData.setEnvironmentKey("ENV_KEY");
CustomerVideoData customerVideoData = new CustomerVideoData();
customerVideoData.setVideoTitle("My great video");
```

Next, Create the `MuxStatsMediaPlayer` object by passing your Android `Context` (typically your `Activity`), the `MediaPlayer` instance, a player name, and the customer data objects.

```java
import com.mux.stats.sdk.muxstats.mediaplayer.MuxStatsMediaPlayer;
...
muxStatsMediaPlayer = new MuxStatsMediaPlayer(this, player, "demo-player", customerPlayerData, customerVideoData);
```

In order to correctly monitor if the player is full-screen, provide the screen size to the `MuxStatsMediaPlayer` instance.

```java
Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
muxStatsMediaPlayer.setScreenSize(size.x, size.y);
```

In order to determine a number of viewer context values as well as track the size of the video player, set the player view.

```java
muxStatsMediaPlayer.setPlayerView(playerView);
```

To allow `MuxStatsMediaPlayer` to listen for various `MediaPlayer` events, add it as a listener. `MediaPlayer` only allows single listeners, so if your activity or application also needs to listen to these events, use the helper methods to wrap your listener implementation with `MuxStatsMediaPlayer`'s listener implementation.

```java
player.setOnCompletionListener(muxStatsMediaPlayer.getOnCompletionListener(myCompletionListener));
player.setOnErrorListener(muxStatsMediaPlayer.getOnErrorListener(myErrorListener));
player.setOnPreparedListener(muxStatsMediaPlayer.getOnPreparedListener(this));
player.setOnInfoListener(muxStatsMediaPlayer.getOnInfoListener(null));  // No wrapped listener.
player.setOnSeekCompleteListener(muxStatsMediaPlayer.getOnSeekCompleteListener(null));  // No wrapped listener.
player.setOnVideoSizeChangedListener(muxStatsMediaPlayer.getOnVideoSizeChangedListener(myVideoSizeChangedListener));
```

Finally, when you are destroying the player, call the `MuxStatsMediaPlayer.release()` method.

```java
muxStatsMediaPlayer.release()
```

## 3. Set up required events

`MediaPlayer` does not provide listener callbacks for all necessary events, so you must add explicit calls into `MuxStatsMediaPlayer` at the same time that certain `MediaPlayer` methods are invoked:

* `start`: [view docs](https://developer.android.com/reference/android/media/MediaPlayer.html#start%28%29)
* `pause`: [view docs](https://developer.android.com/reference/android/media/MediaPlayer.html#pause%28%29)
* `seekTo`: [view docs](https://developer.android.com/reference/android/media/MediaPlayer.html#seekTo%28int%29)

For example, in the demo, a [MediaController view](https://developer.android.com/reference/android/widget/MediaController) is used to control the `MediaPlayer` instance, and the appropriate `MuxStatsMediaPlayer` methods are invoked in the
[MediaPlayerControl](https://developer.android.com/reference/android/widget/MediaController.MediaPlayerControl) implementation used to link the two instances.

```java
private class MediaPlayerControl implements MediaController.MediaPlayerControl,
        MediaPlayer.OnBufferingUpdateListener {
    @Override
    public void start() {
        if (player != null) {
            player.start();
            muxStats.play();
        }
    }

    @Override
    public void pause() {
        if (player != null) {
            player.pause();
            muxStats.pause();
        }
    }

    @Override
    public void seekTo(int pos) {
        if (player != null) {
            player.seekTo(pos);
            muxStats.seeking();
        }
    }
}
```

After you've integrated, start playing a video in your player. A few minutes after you stop watching, you'll see the results in your Mux data dashboard. Login to the dashboard and find the environment that corresponds to your `env_key` and look for video views.

## 4. Make your data actionable

In the MediaPlayer SDK, options are provided via the CustomerPlayerData and CustomerVideoData objects.

All metadata details except for envKey are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

## 5. Advanced options

## Changing the video

There are two cases where the underlying tracking of the video view need to be reset. First, when you load a new source URL into an existing player, and second when the program within a singular stream changes (such as a program within a live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New Source

When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

This is done by calling `muxStatsMediaPlayer.videoChange(CustomerVideoData)` which will remove all previous video data and reset all metrics for the video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

It's best to change the video info immediately after telling the player which new source to play.

### New Program (in single stream)

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, call `muxStatsMediaPlayer.programChange(CustomerVideoData)`. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

## Error tracking

By default, Mux's integration with MediaPlayer automatically tracks fatal errors as thrown by MediaPlayer. In some applications, however, you may want to disable this and track errors on your own, especially if you have retry logic in your application to try to recover from errors that MediaPlayer encounters.

In this case, there are two things that you need to do:

1. Turn off the automatic error tracking. To do this, call `muxStatsExoPlayer.setAutomaticErrorTracking(false)`
2. When your application encounters a fatal error that you cannot recover from, call `muxStatsExoPlayer.error(MuxErrorException e)`, including a message and a code.

The following is an example of firing a custom error.

```java
// Error code: integer value for the generic type of error that
// occurred.
// Error message: String providing more information on the error
// that occurred.
// For an example, the HTML5 video element uses the
// following: https://developer.mozilla.org/en-US/docs/Web/API/MediaError
// for codes and messages. Feel free to use your own codes and messages
int errorCode = 1;
String errorMessage = "A fatal error was encountered during playback";
MuxErrorException error = new MuxErrorException(errorCode, errorMessage);
muxStatsMediaPlayer.error(error);
```

It is important that you only trigger an error when the playback has to be abandoned or aborted in an unexpected manner, as Mux tracks fatal playback errors only.


# Monitor Bitmovin player
This guide walks through integration with Bitmovin player to collect video performance metrics with Mux Data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Available for deployment from a package manager
- Customizable Error Tracking
- Ads metrics
- Ads metadata
- Custom Beacon Domain

```

Notes:

```md
No notes provided
```

## 1. Install \`@mux/mux-data-bitmovin\`

Include the Mux JavaScript SDK on every page of your web app that includes video.

```npm
npm install --save @mux/mux-data-bitmovin
```

```yarn
yarn add @mux/mux-data-bitmovin
```

```cdn

<!-- Include bitmovin-mux after the core Bitmovin javascript file -->
<script src="https://cdn.bitmovin.com/player/web/8/bitmovinplayer.js"></script>
<script src="https://src.litix.io/bitmovin/5/bitmovin-mux.js"></script>

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Call `bitmovin.player.Player` like you normally would. Call `initBitmovinMux` with the player reference and the SDK options.

```html

<div id="my-player"></div>
<script>
  // Record the player init time
  const playerInitTime = initBitmovinMux.utils.now();
  // Configure the player as appropriate for your verion
  const conf = {
      // Insert player configuration here
  };
  // It is preferred to retrieve the reference from the return of
  // the initialization rather than on a player callback so that
  // Mux can track events as soon as possible.
  // For 5.x, 6.x, and 7.x this may look different
  const container = document.getElementById('my-player');
  const source = {
     // Insert source config here
  };
  var player = new bitmovin.player.Player(container, conf);
  player.load(source);

  initBitmovinMux(player, {
    debug: false,
    data: {
      env_key: 'ENV_KEY', // required
      // Metadata
      player_name: '', // ex: 'My Main Player'
      player_init_time: playerInitTime // ex: 1451606400000
      // ... and other metadata
    }
  });
</script>

```

```javascript

import initBitmovinMux from "@mux/mux-data-bitmovin";
// Record the player init time
const playerInitTime = initBitmovinMux.utils.now();
// Configure the player as appropriate for your verion
const conf = {
    // Insert player configuration here
};
// It is preferred to retrieve the reference from the return of
// the initialization rather than on a player callback so that
// Mux can track events as soon as possible.
// For 5.x, 6.x, and 7.x this may look different
const container = document.getElementById('my-player');
const source = {
    // Insert source config here
};
var player = new bitmovin.player.Player(container, conf);
player.load(source);

initBitmovinMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Metadata
    player_name: '', // ex: 'My Main Player'
    player_init_time: playerInitTime // ex: 1451606400000
    // ... and other metadata
  }
}, bitmovin);

```



## 3. Make your data actionable

The only required field in the `options` that you pass into `@mux/mux-data-bitmovin` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
initBitmovinMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000, can use `initBitmovinMux.utils.now()`
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `initBitmovinMux`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
// player is the instance returned by the `bitmovin.player.Player` function
player.mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance returned by the `bitmovin.player.Player` function
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance returned by the `bitmovin.player.Player` function
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
initBitmovinMux(player, {
  debug: false,
  disableCookies: true,
  data: {
    env_key: "ENV_KEY",
    // ...
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
initBitmovinMux(player, {
  debug: false,
  respectDoNotTrack: true,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `@mux/mux-data-bitmovin` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance returned by the `bitmovin.player.Player` function
player.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
  };
}

initBitmovinMux(player, {
  debug: false,
  errorTranslator,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
initBitmovinMux(player, {
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Ads tracking with `@mux/mux-data-bitmovin`

Mux supports Bitmovin's VAST advertising client for pre-, mid-, and post-roll ads. Simply configure these plugins as you would normally, and Mux will track ads automatically. No additional configuration is needed.

The metrics for preroll request and response times, as well as number of requests, are pending an update to Bitmovin's API. Everything else will operate normally, but those metrics may be missing.

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
initBitmovinMux(player, {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```


# Monitor Bitmovin Player Android
This guide walks through integration with the Bitmovin Player Android SDK to collect video performance metrics with Mux data.
This documents integration instructions for [Bitmovin's `Bitmovin Player` library](https://bitmovin.com/docs/player/api-reference/android/android-sdk-api-reference-v3#/player/android/3/docs/index.html), version 3.x and 2.x.

The Mux integration with `Bitmovin Player` is built on top of Mux's core Java SDK, and the full code can be seen here: [muxinc/mux-stats-sdk-bitmovin-android](https://github.com/muxinc/mux-stats-sdk-bitmovin-android).

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager

```

Notes:

```md
No notes provided
```

## 1. Install the Mux Data SDK

Add the Mux SDK to your project using one of the following approaches:

## Add Gradle dependency on the Mux Bitmovin Player SDK

Add the Mux Maven repository to your Gradle file:

```text
repositories {
    maven {
        url "https://muxinc.jfrog.io/artifactory/default-maven-release-local"
    }
}
```

Next, add a dependency on the Mux Data Bitmovin Player SDK. We support both `minapi16` and `minapi21` as separate artifacts.

The current version is `v0.5.1`. Additional releases can be found on our [releases page](https://github.com/muxinc/mux-stats-sdk-bitmovin-android/releases).

### Bitmovin Player support

We support version `3.11.1` of Bitmovin Player. Support for additional versions is planned

```groovy
implementation 'com.mux.stats.sdk.muxstats:muxstatssdkbitmovinplayer_r3_11_1:[CurrentVersion]'
```

## 2. Initialize the monitor with your Bitmovin Player instance

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

First, create the `CustomerPlayerData` and `CustomerVideoData` objects as appropriate for your current playback, and be sure to set your `ENV_KEY`.

```java
import com.mux.stats.sdk.core.model.CustomerPlayerData;
import com.mux.stats.sdk.core.model.CustomerVideoData;
import com.mux.stats.sdk.core.model.CustomerViewData
import com.mux.stats.sdk.core.model.CustomData;
import com.mux.stats.sdk.core.model.CustomerData;

CustomerPlayerData customerPlayerData = new CustomerPlayerData();
customerPlayerData.setEnvironmentKey("YOUR_ENVIRONMENT_KEY_HERE");

CustomerVideoData customerVideoData = new CustomerVideoData();
customerVideoData.setVideoTitle(intent.getStringExtra("YOUR_VIDEO_TITLE"));

CustomerViewData customerViewData = new CustomerViewData();
customerViewData.setViewSessionId("A26C4C2F-3C8A-46FB-885A-8D973F99A998");

CustomData customData = new CustomData();
customData.setCustomData1("YOUR_CUSTOM_STRING_HERE");

CustomerData customerData = new CustomerData(customerPlayerData, customerVideoData, customerViewData);
customerData.setCustomData(customData);
```

Next, create the `MuxStatsSDKBitmovinPlayer` object by passing your Android `Context` (typically your `Activity`), a `Bitmovin PlayerView` instance, a player name, and the customer data objects.

```java
import com.mux.stats.sdk.muxstats.MuxStatsSDKBitmovinPlayer;
...
// Make sure to monitor the player before calling `prepare` on the Bitmovin Player instance
muxStatsBitmovinPlayer = new MuxStatsSDKBitmovinPlayer(
  this, player, "demo-player", customerData);
```

In order to correctly monitor if the player is full-screen, provide the screen size to the `MuxStatsSDKBitmovinPlayer` instance.

```java
Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
muxStatsBitmovinPlayer.setScreenSize(size.x, size.y);
```

In order to determine a number of viewer context values as well as track the size of the video player, set the player view.

```java
muxStatsBitmovinPlayer.setPlayerView(playerView);
```

Finally, when you are destroying the player, call the `MuxStatsSDKBitmovinPlayer.release()` function.

```java
muxStatsBitmovinPlayer.release()
```

After you've integrated, start playing a video in your player. A few minutes after you stop watching, you'll see the results in your Mux data dashboard. Login to the dashboard and find the environment that corresponds to your `env_key` and look for video views.

## 3. Add Metadata

In the Java SDK, options are provided via the objects within the `CustomerData` object.

All metadata details except for `envKey` are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Advanced

## Changing the video

There are two cases where the underlying tracking of the video view need to be reset. First, when you load a new source URL into an existing player, and second when the program within a singular stream changes (such as a program within a live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

## New source

When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

This is done by calling `muxStatsBitmovinPlayer.videoChange(CustomerVideoData)` which will remove all previous video data and reset all metrics for the video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

It's best to change the video info immediately after telling the player which new source to play.

## New program (in single stream)

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, call `muxStatsBitmovinPlayer.programChange(CustomerVideoData)`. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

## Error tracking

By default, Mux's integration with Bitmovin Player automatically tracks fatal errors as thrown by Bitmovin Player. If a fatal error happens outside the context of Bitmovin Player and you want to track it with Mux, you can call `muxStatsBitmovinPlayer.error` like this:

```java
// Error code: integer value for the generic type of error that
// occurred.
// Error message: String providing more information on the error
// that occurred.
// For an example, the HTML5 video element uses the
// following: https://developer.mozilla.org/en-US/docs/Web/API/MediaError
// for codes and messages. Feel free to use your own codes and messages
int errorCode = 1;
String errorMessage = "A fatal error was encountered during playback";
MuxErrorException error = new MuxErrorException(errorCode, errorMessage);
muxStatsBitmovinPlayer.error(error);
```

Note that `muxStatsBitmovinPlayer.error(MuxErrorException e)` can be used with or without automatic error tracking. If your application has retry logic that attempts to recover from Bitmovin Player errors then you may want to disable automatic error tracking like this:

```java
muxStatsBitmovinPlayer.setAutomaticErrorTracking(false)
```

<Callout type="warning">
  It is important that you only trigger an error when the playback has to be abandoned or aborted in an unexpected manner, as Mux tracks fatal playback errors only.
</Callout>


# Monitor castLabs Player (Web)
This guide walks through integration with [castLabs PRESTOplay for Web](https://castlabs.com/prestoplay/web-apps/) to collect video performance metrics with Mux Data.
<Callout type="warning" title="Third-party integration">
  This integration is managed and operated by [castLabs](https://castlabs.com/).
  Feedback should be made by using the [contact form](https://castlabs.com/contact/) or creating a ticket in the [General Helpdesk](https://castlabs.atlassian.net/servicedesk/customer/portal/26).
</Callout>

# Mux Environment Key

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

# Integration Guide

CastLabs maintains an online version of the official documentation which you can check out [here](https://demo.castlabs.com/#/docs/analytics#mux-data).


# Monitor castLabs Player (Android)
This guide walks through integration with [castLabs PRESTOplay for Android](https://castlabs.com/prestoplay/android/) to collect video performance metrics with Mux Data.
<Callout type="warning" title="Third-party integration">
  This integration is managed and operated by [castLabs](https://castlabs.com/).
  Feedback should be made by using the [contact form](https://castlabs.com/contact/) or creating a ticket in the [General Helpdesk](https://castlabs.atlassian.net/servicedesk/customer/portal/26).
</Callout>

# Mux Environment Key

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

# Integration Guide

CastLabs maintains an online version of the official documentation which you can check out [here](https://players.castlabs.com/android/latest/docs/build/html/extensions.html?highlight=mux#id6).


# Monitor Akamai media player
This guide walks through integration with [Akamai Media Player](https://www.akamai.com/us/en/products/media-delivery/adaptive-media-player.jsp) to collect video performance metrics with Mux data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Custom Dimensions

```

Notes:

```md
No notes provided
```

## 1. Load \`@mux/mux-data-akamai\` as a plugin

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

```npm
npm install --save @mux/mux-data-akamai
```

```yarn
yarn add @mux/mux-data-akamai
```

```cdn
<script src="http://src.litix.io/akamai/3/akamai-mux.js"></script>
```



Register the mux plugin with the `akamai` object.

```html

<div id="my-player"></div>
<script>
akamai.amp.AMP.create("#my-player", {
  // ... other player configuration
  plugins: {
    mux: {
      resources: [
        {src: "http://src.litix.io/akamai/3/akamai-mux.js", type: "text/javascript"},
      ],
      debug: false,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata
        player_name: '', // ex: 'My Main Player'
        // ... and other metadata
      }
    }
  }
});
</script>

```

```javascript

import initAkamaiMux from "@mux/mux-data-akamai";

initAkamaiMux(akamai);

akamai.amp.AMP.create("#my-player", {
  // ... other player configuration
  plugins: {
    mux: {
      debug: false,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata
        player_name: '', // ex: 'My Main Player'
        // ... and other metadata
      }
    }
  }
});

```



## 2. Make your data actionable

The only required field in the `data` key that you pass into `plugins.mux` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
akamai.amp.AMP.create("#my-player", {
  // ... other player configuration
  plugins: {
    mux: {
      resources: [
        {src: "http://src.litix.io/akamai/3/akamai-mux.js", type: "text/javascript"},
      ],
      debug: false,
      data: {
        env_key: 'ENV_KEY', // required
        // Site Metadata
        viewer_user_id: '', // ex: '12345'
        experiment_name: '', // ex: 'player_test_A'
        sub_property_id: '', // ex: 'cus-1'
        // Player Metadata
        player_name: '', // ex: 'My Main Player'
        player_version: '', // ex: '1.0.0'
        // Video Metadata
        video_id: '', // ex: 'abcd123'
        video_title: '', // ex: 'My Great Video'
        video_series: '', // ex: 'Weekly Great Videos'
        video_duration: '', // in milliseconds, ex: 120000
        video_stream_type: '', // 'live' or 'on-demand'
        video_cdn: '' // ex: 'Fastly', 'Akamai'
      }
    }
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 3. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance returned by the `akamai.amp.AMP.create` function
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance returned by the `akamai.amp.AMP.create` function
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 4. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
akamai.amp.AMP.create("#my-player", {
  // ... other player configuration
  plugins: {
    mux: {
      resources: [
        {src: "http://src.litix.io/akamai/3/akamai-mux.js", type: "text/javascript"},
      ],
      debug: false,
      disableCookies: true,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata
        player_name: '', // ex: 'My Main Player'
        // ... and other metadata
      }
    }
  }
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
akamai.amp.AMP.create("#my-player", {
  // ... other player configuration
  plugins: {
    mux: {
      resources: [
        {src: "http://src.litix.io/akamai/3/akamai-mux.js", type: "text/javascript"},
      ],
      debug: false,
      respectDoNotTrack: true,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata
        player_name: '', // ex: 'My Main Player'
        // ... and other metadata
      }
    }
  }
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `@mux/mux-data-akamai` will track errors emitted from the video element as fatal errors.

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
  };
}

akamai.amp.AMP.create("#my-player", {
  // ... other player configuration
  plugins: {
    mux: {
      resources: [
        {src: "http://src.litix.io/akamai/3/akamai-mux.js", type: "text/javascript"},
      ],
      debug: false,
      respectDoNotTrack: true,
      errorTranslator,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata
        player_name: '', // ex: 'My Main Player'
        // ... and other metadata
      }
    }
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
akamai.amp.AMP.create("#my-player", {
  // ... other player configuration
  plugins: {
    mux: {
      resources: [
        {src: "http://src.litix.io/akamai/3/akamai-mux.js", type: "text/javascript"},
      ],
      debug: false,
      respectDoNotTrack: true,
      automaticErrorTracking: false,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata
        player_name: '', // ex: 'My Main Player'
        // ... and other metadata
      }
    }
  }
});
```

### Ads tracking with `@mux/mux-data-akamai`

Ad events are tracked automatically if your player is configured for ads. No additional configuration is needed.

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
akamai.amp.AMP.create("#my-player", {
  // ... other player configuration
  plugins: {
    mux: {
      resources: [
        {src: "http://src.litix.io/akamai/3/akamai-mux.js", type: "text/javascript"},
      ],
      // ... various configuration options
      beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata
        player_name: '', // ex: 'My Main Player'
        player_init_time: playerInitTime // ex: 1451606400000
        // ... and other metadata
      }
    }
  }
});
```


# Monitor NexPlayer
This guide walks through integration with [NexPlayer](https://nexplayersdk.com/) to collect video performance metrics with Mux Data.
<Callout type="warning">
  # Third-party integration

  This integration is managed and operated by [NexPlayer](https://github.com/NexPlayer/NexPlayer_HTML5_Mux).
  Feedback should be made on the GitHub repo's [Issues](https://github.com/NexPlayer/NexPlayer_HTML5_Mux/issues) page or by contacting NexPlayer support by [email](mailto:supportmadrid@nexplayer.com).
</Callout>

## 1. Install NexPlayer\_HTML5\_Mux

Add the NexPlayer\_HTML5\_Mux plugin to your project by cloning the [GitHub repo](https://github.com/NexPlayer/NexPlayer_HTML5_Mux) or installing using yarn/npm.

```npm

npm install --save https://github.com/NexPlayer/NexPlayer_HTML5_Mux.git

```

```yarn

yarn add https://github.com/NexPlayer/NexPlayer_HTML5_Mux.git

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Add NexPlayer as you normally would to your solution including recommended CSS styling. In addition, you will need to import the Mux SDK and `NexMuxHandShake.js` into the `<head />` and set the `window.muxPlayerInitTime` to the current date/time.

<Callout type="warning">
  # NexPlayer minimum version

  Be sure to use the NexPlayer SDK v5.5.3.1 as it contains necessary functionality to integrate with Mux.
</Callout>

```html
<head>
  <style type="text/css">
    #player_container {
      position: relative;
      padding-top: 28%;
      padding-bottom: 28%;
      left: 28%;
    }

    #player {
      background-color: #191828;
      position: absolute;
      top: 0%;
      width: 50%;
      height: 50%;
    }
  </style>
  <script type="text/javascript" src="https://src.litix.io/core/4/mux.js"></script>
  <script type="text/javascript" src="https://nexplayer.nexplayersdk.com/5.5.3.1/nexplayer.js"></script>
  <script type="text/javascript" src="../node_modules/NexPlayer_HTML5_Mux/app/NexMuxHandShake.js"></script>
  <script type="text/javascript">window.muxPlayerInitTime = Date.now();</script>
</head>
```

Initialize your instance of NexPlayer with a configuration that includes the NexPlayer\_HTML5\_Mux plugin that activates Mux Data. Be sure to replace the `ENV_KEY` and `NEXPLAYER_KEY` with respective values.

```html

<div id="player_container">
  <div id="player" />
</div>

<script type="text/javascript">
  var muxConfiguration = {
    debug: false,
    data: {
      env_key: 'ENV_KEY'

      // Metadata
      player_name: '', // ex: 'My Main Player'
      player_init_time: window.muxPlayerInitTime // ex: 1451606400000

      // ... and other metadata
    },
  };

  var player = null;
  var videoElem = null;
  let nexMux = null;

  var callBackWithPlayers = function (nexplayerInstance, videoElement) {
    player = nexplayerInstance;
    videoElem = videoElement;

    videoElem.addEventListener("loadeddata", function() {
      nexMux = new NexMuxHandShake();
      nexMux.useAdMetrics = true;
      nexMux.initMuxData(muxConfiguration);
    });
  }

  nexplayer.Setup({
    key: 'NEXPLAYER_KEY',
    div: document.getElementById('player'),
    callbacksForPlayer: callBackWithPlayers,
    src: 'https://stream.mux.com/yb2L3z3Z4IKQH02HYkf9xPToVYkOC85WA.m3u8',
  });
</script>

```



## 3. Make your data actionable

The only required field in the options that you pass into the NexPlayer\_HTML5\_Mux plugin is `ENV_KEY`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `muxConfiguration` on initialization.

```js
var muxConfiguration = {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: 'NexPlayer', // ex: 'My Main Player'
    player_version:  '', // ex: '1.0.0'
    player_init_time: window.muxPlayerInitTime, // ex: 1451606400000
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  },
};
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// nexMux is the instance returned by the 
// `new NexMuxHandShake()` in the above example
nexMux.videoChange({
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// nexMux is the instance returned by the 
// `new NexMuxHandShake()` in the above example
nexMux.programChange({
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 5. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
var muxConfiguration = {
  debug: false,
  disableCookies: true,
  data: {
    env_key: 'ENV_KEY', // required
    ...
  },
};
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
var muxConfiguration = {
  debug: false,
  respectDoNotTrack: true,
  data: {
    env_key: 'ENV_KEY', // required
    ...
  },
};
```

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
var muxConfiguration = {
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: 'ENV_KEY', // required
    ...
  },
};
```

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
var muxConfiguration = {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: 'ENV_KEY', // required
    ...
  },
};
```


# Monitor Ooyala player
This guide walks through integration with Ooyala player to collect video performance metrics with Mux Data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Custom Dimensions
- Customizable Error Tracking
- Ads metrics
- Custom Beacon Domain

```

Notes:

```md
No notes provided
```

## 1. Install \`ooyala-mux\`

Include the Mux JavaScript SDK on every page of your web app that includes video.

```html
<!-- Include ooyala-mux after the core Ooyala javascript files -->
<script src="https://player.ooyala.com/static/v4/stable/latest/core.min.js"></script>
<!-- Insert other Ooyala plugin files here -->
<script src="https://src.litix.io/ooyala/4/ooyala-mux.js"></script>
```

## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Call `OO.player.create` like you normally would. Call `initOoyalaMux` with the player reference in the `onCreate` callback.

```html
<div id="my-player"></div>
<script>
  let playerInitTime;

  // Use a callback for when the player is created to register Mux Data
  function onPlayerCreated (player) {
    initOoyalaMux(player, {
      debug: false,
      data: {
        env_key: 'ENV_KEY', // required
        // Metadata
        player_name: '', // ex: 'My Main Player'
        player_init_time: playerInitTime // ex: 1451606400000
        // ... and other metadata
      }
    }
  });

  const asset = {
    // Insert Ooyala asset configuration here
  };

  const playerConfig = {
    onCreate: onPlayerCreated,
    // Insert other Ooyala player configuration (e.g. autoplay etc) here
  };

  // Create the player with the Mux callback
  OO.ready(function() {
    playerInitTime = initOoyalaMux.utils.now();
    OO.player.create('playerdiv', asset, playerConfig)
  });
</script>
```

## 3. Make your data actionable

The only required field in the `options` that you pass into `ooyala-mux` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
initOoyalaMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance received in the `onCreate` callback
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance received in the `onCreate` callback
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 5. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
initOoyalaMux(player, {
  debug: false,
  disableCookies: true,
  data: {
    env_key: "ENV_KEY",
    // ...
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
initOoyalaMux(player, {
  debug: false,
  respectDoNotTrack: true,
  data: {
    env_key: "ENV_KEY",
    // ...
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `ooyala-mux` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance received in the `onCreate` callback
player.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: 'Additional context for the error'
  };
}

initOoyalaMux(player, {
  debug: false,
  errorTranslator,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
initOoyalaMux(player, {
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Ads tracking with `ooyala-mux`

Mux has been tested with and supports Ooyala's `google-ima-ads-manager`. Configure these plugins as you would normally, and Mux will track ads automatically. No additional configuration is needed.

Other Ooyala ad integrations, such as FreeWheel and VAST/VPAID may work out of the box. Please contact us with any questions.

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
initOoyalaMux(player, {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```


# Monitor Shaka player
This guide walks through integration with Shaka player to collect video performance metrics with Mux Data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Available for deployment from a package manager
- Can infer CDN identification from response headers
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Customizable Error Tracking
- Custom Beacon Domain
- Extraction of HLS Session Data

```

Notes:

```md
Request Latency is not available.
```

## 1. Install \`@mux/mux-data-shakaplayer\`

Include the Mux JavaScript SDK on every page of your web app that includes video.

```npm
npm install --save @mux/mux-data-shakaplayer
```

```yarn
yarn add @mux/mux-data-shakaplayer
```

```cdn
<script src="https://src.litix.io/shakaplayer/5/shakaplayer-mux.js"></script>
```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Call `new shaka.Player` like you normally would and get the return value (a reference to the `player`). Call `initShakaPlayerMux` with the player reference and the SDK options.

```html

<div id="my-player"></div>
<script>
  const playerInitTime = initShakaPlayerMux.utils.now();
  const video = document.querySelector('#my-player');
  const player = new shaka.Player(video);

  // calling initShakaPlayerMux will return a shakaPlayerMux object
  // you will need this for handling any errors when calling
  // player.load()
  const shakaPlayerMux = initShakaPlayerMux(player, {
    debug: false,
    data: {
      env_key: 'ENV_KEY',
      // Metadata
      player_name: 'Custom Player', // ex: 'My Main Player',
      player_init_time: playerInitTime // ex: 1451606400000
      // ... and other metadata
    }
  });

  player.load('https://stream.mux.com/yb2L3z3Z4IKQH02HYkf9xPToVYkOC85WA.m3u8').then(function () {
    // Successfully loaded the manifest. Mux data will begin tracking
  }).catch(function (error) {
    // There was an error loading this manifest. Call shakaPlayerMux.loadErrorHandler(error) so that Mux data can track this error.
    shakaPlayerMux.loadErrorHandler(error);
    // Do the rest of your error handling logic
  })

  // When you are ready to destroy shakaplayer, you must also destroy
  // the mux monitor
  player.destroy()
  player.mux.destroy()
</script>

```

```javascript

import shaka from "shaka-player";
import initShakaPlayerMux from "@mux/mux-data-shakaplayer";

const playerInitTime = initShakaPlayerMux.utils.now();
const video = document.querySelector('#my-player');
const player = new shaka.Player(video);


// calling initShakaPlayerMux will return a shakaPlayerMux object
// you will need this for handling any errors when calling
// player.load()
const shakaPlayerMux = initShakaPlayerMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY',
    // Metadata
    player_name: 'Custom Player', // ex: 'My Main Player',
    player_init_time: playerInitTime // ex: 1451606400000
    // ... and other metadata
  }
}, shaka);

player.load('https://stream.mux.com/yb2L3z3Z4IKQH02HYkf9xPToVYkOC85WA.m3u8').then(function () {
  // Successfully loaded the manifest. Mux data will begin tracking
}).catch(function (error) {
  // There was an error loading this manifest. Call shakaPlayerMux.loadErrorHandler(error) so that Mux data can track this error.
  shakaPlayerMux.loadErrorHandler(error);
  // Do the rest of your error handling logic
})
// When you are ready to destroy shakaplayer, you must also destroy
// the mux monitor:
// player.destroy()
// player.mux.destroy()

```



## Passing in `shaka` global

You'll see the 3rd argument to `initShakaPlayerMux` is `shaka`. This is the global `shaka` object. If you are using a bundler and importing `shaka` with `require` or `import` then you'll need to pass in the `shaka` object.

If no `shaka` object is passed in, then `initShakaPlayerMux` will look for `shaka` on then global `window` object.

## 3. Make your data actionable

The only required field in the `options` that you pass into `@mux/mux-data-shakaplayer` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
initShakaPlayerMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY',
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `initShakaPlayerMux`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
// player is the instance returned by `new shaka.Player`
player.mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance returned by `new shaka.Player`
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance returned by `new shaka.Player`
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
// player is the instance returned by `new shaka.Player`
initShakaPlayerMux(player, {
  debug: false,
  disableCookies: true,
  data: {
    env_key: "ENV_KEY",
    // ...
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
// player is the instance returned by `new shaka.Player`
initShakaPlayerMux(player, {
  debug: false,
  respectDoNotTrack: true,
  data: {
    env_key: "ENV_KEY",
    // ...
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `@mux/mux-data-shakaplayer` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance returned by `new shaka.Player`
player.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

// player is the instance returned by `new shaka.Player`
initShakaPlayerMux(player, {
  debug: false,
  errorTranslator,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
// player is the instance returned by `new shaka.Player`
initShakaPlayerMux(player, {
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Track Ad playback with a custom integration

Our integration for Shaka player does not have a built-in integration for tracking ad playback. If you would like to track ads played within Shaka player, you will need to build a custom integration, which is detailed here: [Build a Custom Integration](/docs/guides/build-a-custom-data-integration).

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
// player is the instance returned by `new shaka.Player`
initShakaPlayerMux(player, {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```


# Monitor THEOplayer (Web)
This guide walks through integration with THEOplayer to collect video performance metrics with Mux Data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Available for deployment from a package manager
- Average Bitrate metrics and `renditionchange` events
- Customizable Error Tracking
- Ads metrics
- Custom Beacon Domain
- Extraction of HLS Session Data
- Live Stream Latency metric

```

Notes:

```md
No notes provided
```

## 1. Install \`@mux/mux-data-theoplayer\`

Include the Mux JavaScript SDK on every page of your web app that includes video.

```npm
npm install --save @mux/mux-data-theoplayer
```

```yarn
yarn add @mux/mux-data-theoplayer
```

```cdn

<!-- Include theoplayer-mux after the core THEOplayer javascript files -->
<script type="text/javascript" src="https://cdn.theoplayer.com/latest/~yourlicense~/theoplayer.loader.js"></script>
<script src="https://src.litix.io/theoplayer/4/theoplayer-mux.js"></script>

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Call `new THEOplayer.Player` like you normally would. Call `initTHEOplayerMux` with a reference to the player instance and the Mux SDK options.

```html

<div id="my-player" class='video-js theoplayer-skin theo-seekbar-above-controls'></div>
<script>
  const playerInitTime = initTHEOplayerMux.utils.now();
  const playerWrapper = document.querySelector('#my-player');

  // Get a reference to your player, and pass it to the init function
  const player = new THEOplayer.Player(playerWrapper, {
    // Insert player configuration here
  });

  player.src = 'https://muxed.s3.amazonaws.com/leds.mp4';

  initTHEOplayerMux(player, {
    debug: false,
    data: {
      env_key: 'ENV_KEY', // required
      // Metadata
      player_name: '', // ex: 'My Main Player'
      player_init_time: playerInitTime // ex: 1451606400000
      // ... and other metadata
    }
  });
</script>

```

```javascript

import * as THEOplayer from 'theoplayer';
import initTHEOplayerMux from '@mux/mux-data-theoplayer';

const playerInitTime = initTHEOplayerMux.utils.now();
const playerWrapper = document.querySelector('#my-player');

// Get a reference to your player, and pass it to the init function
const player = new THEOplayer.Player(playerWrapper, {
  // Insert player configuration here
});

player.src = 'https://muxed.s3.amazonaws.com/leds.mp4';

initTHEOplayerMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Metadata
    player_name: '', // ex: 'My Main Player'
    player_init_time: playerInitTime // ex: 1451606400000
    // ... and other metadata
  }
}, THEOplayer);

```



## Passing in `THEOplayer` global

You'll see the 3rd argument to `initTHEOplayerMux` is `THEOplayer`. This is the global `THEOplayer` object. If you are using a bundler and importing `THEOplayer` with `require` or `import` then you'll need to pass in the `THEOplayer` object.

If no `THEOplayer` object is passed in, then `initTHEOplayerMux` will look for `THEOplayer` on then global `window` object.

## 3. Make your data actionable

The only required field in the `options` that you pass into `initTHEOplayerMux` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
// player here is the instance of THEOplayer.Player
initTHEOplayerMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `initTHEOplayerMux`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
// player is the instance of THEOplayer.Player
let monitor = initTHEOplayerMux(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required

    video_id: 'abcd123',
  }
});

monitor.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

For THEOplayer, you do not need to emit the `videochange` event when the player source property of the player is updated. The `sourcechange` event that is fired when you update the source property of the player is handled automatically. However, you still need to pass the updated video metadata under `metadata.mux`, as shown in the example below.

When this is done, it removes all previous video data and resets all metrics for the video view. Note: the previous method using changeMuxVideo has been deprecated, but will continue to work for 2.x versions of this plugin.

```js
player.source = {
  sources: {
    // ...your source
  },
  metadata: {
    mux: {
      video_id: 'new-ID',
      video_title: 'New title',
      // ... other metadata
    }
  }
}
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance of THEOplayer.Player
let monitor = initTHEOPlayerMux(player, {
  debug: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});

// emit `programchange` when the content within the stream changes
monitor.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
// player here is the instance of THEOplayer.Player
initTHEOplayerMux(player, {
  debug: false,
  disableCookies: true,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
// player is the instance of THEOplayer.Player
initTHEOplayerMux(player, {
  debug: false,
  respectDoNotTrack: true,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `@mux/mux-data-theoplayer` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance of THEOplayer.Player
let monitor = initTHEOPlayerMux(player, {
  debug: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});

// emit the `error` event when an error occurs
monitor.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

// player is the instance of THEOplayer.Player
initTHEOplayerMux(player, {
  debug: false,
  errorTranslator,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
// player is the instance of THEOplayer.Player
initTHEOplayerMux(player, {
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Ads tracking with `@mux/mux-data-theoplayer`

Mux has been tested with and supports [THEOplayer's Ads integration](https://docs.theoplayer.com/how-to-guides/01-ads/00-introduction.md). Simply configure the ads as you would with THEOplayer normally, and Mux will track ads automatically. No additional configuration is needed.

Other THEOplayer ad integrations, such as Google IMA, may work out of the box but have not currently been tested. Please contact us with any questions.

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
// player is the instance of THEOplayer.Player
initTHEOplayerMux(player, {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Destroy the monitor

In some cases, you may want to stop tracking an instance of THEOplayer. To this, we provide a `destroy` method within the returned object of `initTHEOplayerMux`, which will immediately end the active Mux Data view and stop tracking the THEOplayer instance.

```
// player is the instance of THEOplayer.Player
let monitor = initTHEOplayerMux(player, {
  debug: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});

// once ready to destroy the monitor
monitor.destroy();
```


# Monitor THEOplayer (iOS)
This guide walks through integration with THEOplayer to collect video performance metrics with Mux Data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Custom Dimensions
- Customizable Error Tracking

```

Notes:

```md
Packaged with: cocoapods. Supports ad events, ads metadata is not available.
```

## 1. Install the Mux Data SDK

## Requirements:

* THEOplayer.xcframework SDK for iOS (> 5.9)
* A working implementation of `THEOplayer` in your iOS app

Before integrating `Mux-Stats-THEOplayer` into your player, first make sure your THEOplayer implementation is working as expected.

Add `Mux-Stats-THEOplayer` to your podfile

```
pod 'Mux-Stats-THEOplayer', '~> 0.8'
```

Run `pod install` then import `MuxCore` and `MUXSDKStatsTHEOplayer` modules into your application. Call `monitorTHEOplayer` and pass in a reference to your `THEOplayer` instance.

## 2. Initialize the monitor for your THEOplayer instance

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Below is an example configuration for a simple THEOplayer implementation. The key part to pay attention to is `monitorTHEOplayer`. This example is using ads with THEOplayer, which will also be tracked with Mux Data.

```swift
import MuxCore
import MUXSDKStatsTHEOplayer
import THEOplayerSDK
import UIKit

class ViewController: UIViewController {
    let playerName = "demoplayer"
    var player: THEOplayer!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.player = THEOplayer(configuration: THEOplayerConfiguration(chromeless: false))
        self.player.frame = view.bounds
        self.player.addAsSubview(of: view)

        let typedSource = TypedSource(
            src: "https://stream.mux.com/tqe4KzdxU6GLc8oowshXgm019ibzhEX3k.m3u8",
            type: "application/vnd.apple.mpegurl")

        let ad = THEOAdDescription(src: "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/ad_rule_samples&ciu_szs=300x250&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vmap&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpostpod&cmsid=496&vid=short_onecue&correlator=")

        let source = SourceDescription(source: typedSource, ads: [ad], textTracks: nil, poster: nil, analytics: nil, metadata: nil)
        self.player.source = source

        // TODO: Add your env key
        let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY")!

        let videoData = MUXSDKCustomerVideoData()
        videoData.videoTitle = "Big Buck Bunny"
        videoData.videoId = "bigbuckbunny"
        videoData.videoSeries = "animation"

        MUXSDKStatsTHEOplayer.monitorTHEOplayer(self.player, name: playerName, playerData: playerData, videoData: videoData, softwareVersion: "1.1.1")
        self.player.play()
    }
}
```

## 3. Make your data actionable

The only required field is `env_key`. But without some more metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Metadata fields are provided via the `MUXSDKCustomerPlayerData` and `MUXSDKCustomerVideoData` objects.

For the full list of properties view the header files for this interfaces:

* [MUXSDKCustomerPlayerData.h](https://github.com/muxinc/stats-sdk-objc/blob/master/XCFramework/MuxCore.xcframework/ios-arm64/MuxCore.framework/Headers/MUXSDKCustomerPlayerData.h)
* [MUXSDKCustomerVideoData.h](https://github.com/muxinc/stats-sdk-objc/blob/master/XCFramework/MuxCore.xcframework/ios-arm64/MuxCore.framework/Headers/MUXSDKCustomerVideoData.h)

For more details about each property, view the [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) guide.

```swift
let playName = "iOS AVPlayer"
let playerData = MUXSDKCustomerPlayerData(environmentKey: "ENV_KEY");
playerData.viewerUserId = "1234"
playerData.experimentName = "player_test_A"
// note that the 'playerName' field here is unrelated to the 'playName' variable above
playerData.playerName = "My Main Player"
playerData.playerVersion = "1.0.0"

let videoData = MUXSDKCustomerVideoData();
videoData.videoId = "abcd123"
videoData.videoTitle = "My Great Video"
videoData.videoSeries = "Weekly Great Videos"
videoData.videoDuration = 120000 // in milliseconds
videoData.videoIsLive = false
videoData.videoCdn = "cdn"


MUXSDKStatsTHEOplayer.monitorTHEOplayer(self.player, name: playerName, playerData: playerData, videoData: videoData, softwareVersion: "1.1.1")
self.player.play()
```

## 4. Advanced options

## Changing the video

If you want to change the video in the player, you'll need to let the Mux SDK know by calling `videoChangeForPlayer`. From the perspective of Mux Data, this will create a new view.

```swift
let videoData = MUXSDKCustomerVideoData()
videoData.videoTitle = "New Video"
videoData.videoId = "newVideoId"
MUXSDKStatsTHEOplayer.videoChangeForPlayer(name: self.playerName, videoData: videoData)

let typedSource = TypedSource(src: "https://stream.mux.com/tNrV028WTqCOa02zsveBdNwouzgZTbWx5x.m3u8", type: "application/vnd.apple.mpegurl")
let source = SourceDescription(source: typedSource, ads: [], textTracks: nil, poster: nil, analytics: nil, metadata: nil)
self.player.source = source
self.player.play()
```

## Handling Errors manually

By default, `automaticErrorTracking` is enabled which means the Mux SDK will catch errors that the player throws and track an error event. Error tracking is meant for fatal errors. When an error is thrown it will mark the view as having encountered an error in the Mux dashboard and the view will no longer be monitored.

If you want to disable automatic and track errors manually you can do by passing in `automaticErrorTracking` false when calling `monitorTHEOplayer`

Whether automatic error tracking is enabled or disabled, you can dispatch errors manually with `dispatchError`.

```swift
MUXSDKStatsTHEOplayer.monitorTHEOplayer(self.player, name: playerName, playerData: playerData, videoData: videoData, softwareVersion: "1.1.1", automaticErrorTracking: false)
MUXSDKStatsTHEOplayer.dispatchError(name: playerName, code: "1234", message: "Something is not right")
```


# Monitor THEOplayer
This guide walks through integration with the THEOplayer Android SDK to collect video performance metrics with Mux data.
This documents integration instructions for [THEO Technologies' `THEOplayer` library](https://www.theoplayer.com/sdk/android)

The Mux integration with `THEOplayer` is built on top of Mux's core Java SDK, and the full code can be seen here: [muxinc/mux-stats-sdk-theoplayer-android](https://github.com/muxinc/mux-stats-sdk-theoplayer-android).

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Available for deployment from a package manager
- Custom Dimensions
- Average Bitrate metrics and `renditionchange` events
- Ads metrics

```

Notes:

```md
`renditionchange` events are tracked, bitrate metrics are not available
```

## 1. Install the Mux Data SDK

Add the Mux SDK to your project using one of the following approaches:

## Add Gradle dependency on the Mux THEOplayer SDK (preferred)

Add the Mux Maven repository to your Gradle file:

```text
repositories {
    maven {
        url "https://muxinc.jfrog.io/artifactory/default-maven-release-local"
    }
}
```

Next, add a dependency on the Mux Data THEOplayer SDK.

The latest version of our SDK can be found [here](https://github.com/muxinc/mux-stats-sdk-theoplayer-android/releases/latest)

```groovy
implementation 'com.mux.stats.sdk.muxstats:muxstatssdktheoplayer:[CurrentVersion]'
```

## 2. Initialize the monitor with your THEOplayer instance

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

First, create the `CustomerPlayerData` and `CustomerVideoData` objects as appropriate for your current playback, and be sure to set your `ENV_KEY`.

```java
import com.mux.stats.sdk.core.model.CustomerPlayerData;
import com.mux.stats.sdk.core.model.CustomerVideoData;
import com.mux.stats.sdk.core.model.CustomerViewData
import com.mux.stats.sdk.core.model.CustomData;
import com.mux.stats.sdk.core.model.CustomerData;

CustomerPlayerData customerPlayerData = new CustomerPlayerData();
customerPlayerData.setEnvironmentKey("YOUR_ENVIRONMENT_KEY_HERE");

CustomerVideoData customerVideoData = new CustomerVideoData();
customerVideoData.setVideoTitle(intent.getStringExtra("YOUR_VIDEO_TITLE"));

CustomerViewData customerViewData = new CustomerViewData();
customerViewData.setViewSessionId("A26C4C2F-3C8A-46FB-885A-8D973F99A998");

CustomData customData = new CustomData();
customData.setCustomData1("YOUR_CUSTOM_STRING_HERE");

CustomerData customerData = new CustomerData(customerPlayerData, customerVideoData, customerViewData);
customerData.setCustomData(customData);
```

Next, create the `MuxStatsSDKTHEOPlayer` object by passing your Android `Context` (typically your `Activity`), a `THEOplayerView` instance, a player name, and the customer data objects.

```java
import com.mux.stats.sdk.muxstats.MuxStatsSDKTHEOPlayer;
...
// Make sure to monitor the player before calling `prepare` on the THEOplayer instance
muxStatsTHEOplayer = new MuxStatsSDKTHEOPlayer(
  this, player, "demo-player", customerData);
```

In order to correctly monitor if the player is full-screen, provide the screen size to the `MuxStatsSDKTHEOPlayer` instance.

```java
Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
muxStatsTHEOPlayer.setScreenSize(size.x, size.y);
```

In order to determine a number of viewer context values as well as track the size of the video player, set the player view.

```java
muxStatsTHEOplayer.setPlayerView(theoPlayerView);
```

Finally, when you are destroying the player, call the `MuxStatsSDKTHEOPlayer.release()` function.

```
muxStatsTHEOplayer.release()
```

After you've integrated, start playing a video in your player. A few minutes after you stop watching, you'll see the results in your Mux data dashboard. Login to the dashboard and find the environment that corresponds to your `env_key` and look for video views.

## 3. Add Metadata

In the Java SDK, options are provided via the objects within the `CustomerData` object.

All metadata details except for `envKey` are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Advanced

## Changing the video

There are two cases where the underlying tracking of the video view need to be reset. First, when you load a new source URL into an existing player, and second when the program within a singular stream changes (such as a program within a live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

## New source

When you change to a new video (in the same player) you need to update the information that Mux knows about the current video. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

This is done by calling `muxStatsTHEOplayer.videoChange(CustomerVideoData)` which will remove all previous video data and reset all metrics for the video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

It's best to change the video info immediately after telling the player which new source to play.

## New program (in single stream)

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, call `muxStatsTHEOplayer.programChange(CustomerVideoData)`. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

## Detect when a video is being played full-screen

For most use cases, the SDK is capable of detecting whether or not a video is being played full-screen. Specifically, it can do so in the case where the player view is the same size as the device display (excepting ActionBars and other framework window decoration).

For other uses cases (non-overlaid controls, window decoration via plain `View`s, etc) you may need to tell the SDK when the user switches to full-screen.

```java
  @Override
  public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState)

    // If you are using SimplePlayerView, StyledPlayerView, etc
    theoPlayerView = findViewById(R.id.my_player_view);

    theoPlayerView.getFullscreenManager().addFullscreenChangeListener(new FullscreenChangeListener() {
      @Override
      public void onEnterFullscreen() {
        muxStatsTHEOplayer.presentationChange(MuxSDKViewPresentation.FULLSCREEN);
      }
      @Override
      public void onExitFullscreen() {
        muxStatsTHEOPlayer.presentationChange(MuxSDKViewPresentation.PORTRAIT);
      }
    });
  }
```

## Error tracking

By default, Mux's integration with THEOplayer automatically tracks fatal errors as thrown by THEOplayer. If a fatal error happens outside the context of THEOplayer and you want to track it with Mux, you can call `muxStatsTHEOplayer.error` like this:

```java
// Error code: integer value for the generic type of error that
// occurred.
// Error message: String providing more information on the error
// that occurred.
// For an example, the HTML5 video element uses the
// following: https://developer.mozilla.org/en-US/docs/Web/API/MediaError
// for codes and messages. Feel free to use your own codes and messages
int errorCode = 1;
String errorMessage = "A fatal error was encountered during playback";
MuxErrorException error = new MuxErrorException(errorCode, errorMessage);
muxStatsTHEOplayer.error(error);
```

Note that `muxStatsTHEOplayer.error(MuxErrorException e)` can be used with or without automatic error tracking. If your application has retry logic that attempts to recover from THEOplayer errors then you may want to disable automatic error tracking like this:

```java
muxStatsTHEOplayer.setAutomaticErrorTracking(false)
```

<Callout type="warning">
  It is important that you only trigger an error when the playback has to be abandoned or aborted in an unexpected manner, as Mux tracks fatal playback errors only.
</Callout>


# Monitor Flowplayer
This guide walks through integration with Flowplayer to collect video performance metrics with Mux Data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Custom Dimensions
- Customizable Error Tracking
- Ads metrics
- Custom Beacon Domain

```

Notes:

```md
No notes provided
```

## 1. Install \`@mux/mux-data-flowplayer\`

Include the Mux JavaScript SDK on every page of your web app that includes video.

```npm
npm install --save @mux/mux-data-flowplayer
```

```yarn
yarn add @mux/mux-data-flowplayer
```

```cdn

<!-- include flowplayer-mux after the other flowplayer libraries -->
<link rel="stylesheet" href="https://releases.flowplayer.org/7.2.1/skin/skin.css">
<!-- include Flowplayer -->
<script src="https://releases.flowplayer.org/7.2.1/flowplayer.min.js"></script>
<script src="https://src.litix.io/flowplayer/3/flowplayer-mux.js"></script>

```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Call `flowplayer` like you normally would and save a reference to the player. Call `initFlowplayerMux` with the player reference.

```html

<div id="my-player"></div>
<script>
  const playerInitTime = initFlowplayerMux.utils.now();
  const container = document.getElementById('my-player');
  const player = flowplayer(container, {
    /// ... flowplayer config
  });

  // Make sure to call this immediately after the return from flowplayer
  initFlowplayerMux(player, container, {
    debug: false,
    data: {
      env_key: 'ENV_KEY', // required
      // Metadata
      player_name: '', // ex: 'My Main Player'
      player_init_time: playerInitTime
      // ... and other metadata
    }
  });
</script>

```

```javascript

import initFlowplayerMux from "@mux/mux-data-flowplayer";
import flowplayer from "@flowplayer/player";

const playerInitTime = initFlowplayerMux.utils.now();
const container = document.getElementById('my-player');
const player = flowplayer(container, {
  /// ... flowplayer config
});

initFlowplayerMux(player, container, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Metadata
    player_name: '', // ex: 'My Main Player'
    player_init_time: playerInitTime
    // ... and other metadata
  }
}, flowplayer);

```



## Passing in `flowplayer` global

You'll see the 3rd argument to `initFlowplayerMux` is `flowplayer`. This is the global `flowplayer` object. If you are using a bundler and importing `flowplayer` with `require` or `import` then you'll need to pass in the `flowplayer` object.

If no `flowplayer` object is passed in, then `initFlowplayerMux` will look for `flowplayer` on then global `window` object.

## 3. Make your data actionable

The only required field in the `options` that you pass into `@mux/mux-data-flowplayer` is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
initFlowplayerMux(player, container, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000, can use `initFlowplayerMux.utils.now()`
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `initFlowplayerMux`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
// player is the instance that gets returned from the `flowplayer` function
player.mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance that gets returned from the `flowplayer` function
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance that gets returned from the `flowplayer` function
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 6. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
// player is the instance that gets returned from the `flowplayer` function
initFlowplayerMux(player, container, {
  debug: false,
  disableCookies: true,
  data: {
    env_key: "ENV_KEY",
    // ...
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
// player is the instance that gets returned from the `flowplayer` function
initFlowplayerMux(player, {
  debug: false,
  respectDoNotTrack: true,
  data: {
    env_key: "ENV_KEY",
    // ...
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `@mux/mux-data-flowplayer` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance that gets returned from the `flowplayer` function
player.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

// player is the instance that gets returned from the `flowplayer` function
initFlowplayerMux(player, {
  debug: false,
  errorTranslator,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
initFlowplayerMux(player, {
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Ads tracking with `@mux/mux-data-flowplayer`

Mux has been tested with and support Flowplayer's IMA and VAST plugins for ad support. No addition configuration is needed, Mux will track ads automatically.

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
initFlowplayerMux(player, {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```


# Monitor Brightcove (Web)
This guide walks through integration with [Brightcove web player](https://player.support.brightcove.com/) to collect video performance metrics with Mux Data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Custom Dimensions
- Request metrics
- Ads metrics
- Ads metadata
- Custom Beacon Domain

```

Notes:

```md
No notes provided
```

## 1. Install \`videojs-mux\`

Either include the Mux JavaScript SDK for video.js (`videojs-mux`) either via the Brightcove Studio by adding the script `https://src.litix.io/videojs/4/videojs-mux.js` as a new JavaScript line in your Plugins configuration or load `videojs-mux` from the CDN on your web pages.

```npm
npm install --save videojs-mux
```

```yarn
yarn add videojs-mux
```

```cdn
<script src="https://src.litix.io/videojs/4/videojs-mux.js"></script>
```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

Initialize the `videojs` player like you normally would and get a reference to the `player`. Call `player.mux` with the Mux plugin options to initialize monitoring.

```html
<video
  id="my-player"
  data-video-id="..."
  data-account="..."
  data-player="..."
  data-embed="default"
  data-application-id
  class="video-js"
  controls>
>
</video>

<script>
  const playerInitTime = Date.now();
  // Get a reference to your player, and pass it to the init function
  const player = videojs("my-player");
  player.mux({
    debug: false,
    data: {
      env_key: 'ENV_KEY', // required
      // Metadata
      player_name: '', // ex: 'My Main Player'
      player_init_time: playerInitTime // ex: 1451606400000
      // ... and other metadata
    }
  });
</script>
```

## 3. Make your data actionable

The only required field in the `options` that you pass into the `data` options in the `player.mux` function is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata under the `data` on initialization.

```js
// player is the instance returned by the `videojs` function
player.mux({
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

```js
// player is the instance returned by the `videojs` function
player.mux.emit('videochange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

```js
// player is the instance returned by the `videojs` function
player.mux.emit('programchange', {
  video_id: 'abc345',
  video_title: 'My Other Great Video',
  video_series: 'Weekly Great Videos',
  // ...
});
```

## 5. Advanced options

### Disable cookies

By default, Mux plugins for HTML5-based players use a cookie to track playback across subsequent page views in order to understand viewing sessions. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies. For information about the specific data tracked in the cookie, please refer to: [What information is stored in Mux Data HTML cookies](/docs/guides/ensure-data-privacy-compliance#what-information-is-stored-in-mux-data-html-cookies).

This is done by setting `disableCookies: true` in the options.

```js
// player is the instance returned by the `videojs` function
player.mux({
  debug: false,
  disableCookies: true,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Over-ride 'do not track' behavior

By default, Mux plugins for HTML5-based players do not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack: true`.

```js
// player is the instance returned by the `videojs` function
player.mux({
  debug: false,
  disableCookies: true,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `videojs-mux` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
// player is the instance returned by the `videojs` function
player.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

// player is the return value from the `videojs` function
player.mux({
  debug: false,
  errorTranslator,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
// player is the return value from the `videojs` function
player.mux({
  debug: false,
  automaticErrorTracking: false,
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
// player is the return value from the `videojs` function
player.mux({
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```


# Monitor Brightcove (iOS)
This guide walks through integration with [Brightcove iOS player](https://player.support.brightcove.com/) to collect video performance metrics with Mux Data.
Brightcove's native SDK for iOS is based on `AVPlayerLayer`. You will need to be using Brightcove's iOS player version `6.x`.

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics

```

Notes:

```md
No notes provided
```

## 1. Install Mux Data SDK

```
pod 'Mux-Stats-AVPlayer', '~>3.0'
```

This will install `Mux-Stats-AVPlayer` and the latest current release of our [core Objective-C Library](https://github.com/muxinc/stats-sdk-objc). There will be no breaking updates in major versions, so you can safely run `pod update` for future versions.

Next, add correct import statement into your application.

## 2. Initialize AVPlayerLayer monitor

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

In your application, you will need to hook into Brightcove's SDK lifecycle events in order to access the underlying `AVPlayerLayer` instance.

```objc
@import BrightcovePlayerSDK;
@import MUXSDKStats;

@property (nonatomic, copy) NSString *trackedPlayerName;

- (void)playbackController:(id<BCOVPlaybackController>)controller didAdvanceToPlaybackSession:(id<BCOVPlaybackSession>)session
{
    // Destroy previous MUXSDKStats if this signifies the other view ended
    // Note: you may want to handle this in another lifecycle event, if you
    // have one that signifies when the video playback has ended/exited.
    if (self.trackedPlayerName != nil) {
        [MUXSDKStats destroyPlayer:self.trackedPlayerName];
    }

    MUXSDKCustomerPlayerData *playerData = [[MUXSDKCustomerPlayerData alloc] initWithEnvironmentKey:@"ENV_KEY"];
    [playerData setPlayerName: @"Brightcove SDK w/ Mux"];
    // set additional player metadata here
    MUXSDKCustomerVideoData *videoData = [MUXSDKCustomerVideoData new];
    [videoData setVideoId:@"EXAMPLE ID"];
    // set additional video metadata here
    self.trackedPlayerName = @"example_player_name";
    [MUXSDKStats monitorAVPlayerLayer:session.playerLayer withPlayerName:self.trackedPlayerName playerData:playerData videoData:videoData];
}
```

Refer to the detailed guide for AVPlayer to finish setup.

<GuideCard
  title="Detailed AVPlayer guide"
  description="After getting a reference to your AVPlayerLayer instance, finish configuring it."
  links={[
    {title: "Read the guide", href: "/docs/guides/monitor-avplayer"},
  ]}
/>


# Brightcove (Android)
This guide walks through integration with Brightcove's Android player to collect video performance metrics with Mux data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Customizable Error Tracking

```

Notes:

```md
No notes provided
```

## 1. Install the Mux Data SDK

Brightcove's native SDK for Android has support for both the native `MediaPlayer` as well as `ExoPlayer`. In the case that you utilize `ExoPlayer` (via a class such as `BrightcoveExoPlayerVideoView`), monitoring basic video playback is relatively simple.

# Requirements

* Brightcove SDK for Android 6.x
* ExoPlayer-based Brightcove Player (e.g. `BrightcoveExoPlayerVideoView`)

# Integration Instructions

Brightcove's SDK for Android encapsulates an underlying `SimpleExoPlayer` instance. In order to integrate, you need to create an instance of `MuxStats` for each new video loaded into the player. This is best done by listening for the `didSetVideo` event that the `EventEmitter` emits.

Brightcove's current Android SDK (6.2.x) uses ExoPlayer r2.7.x, so you should include the appropriate AAR file from our releases page and in our [Monitor ExoPlayer guide](/docs/guides/monitor-exoplayer).

Note: `didSetVideo` is used in order to get the updated `Video` in the case that a playlist of `Video` objects, so that you can retrieve the updated metadata.

```java
// MainFragment.java (or MainActivity.java, wherever
// you have access to your `BrightcoveExoPlayerVideoView`

import com.mux.stats.sdk.core.model.CustomerPlayerData;
import com.mux.stats.sdk.core.model.CustomerVideoData;
import com.mux.stats.sdk.muxstats.MuxStatsExoPlayer;

public class MainFragment extends BrightcovePlayerFragment implements EventListener {

  public static final String TAG = MainFragment.class.getSimpleName();
  private MuxStatsExoPlayer muxStatsExoPlayer;

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View result = inflater.inflate(R.layout.fragment_main, container, false);
    baseVideoView = (BrightcoveExoPlayerVideoView) result.findViewById(R.id.brightcove_video_view);
    super.onCreateView(inflater, container, savedInstanceState);
    baseVideoView.getEventEmitter().on("didSetVideo", this);

    // Set up your videos for playback here
    Video video = Video.createVideo("https://path/to/video.mp4", DeliveryType.HLS);

    baseVideoView.add(video);
    baseVideoView.start();
    return result;
  }

  @Override
  public void processEvent(Event event) {
    ExoPlayerVideoDisplayComponent videoDisplayComponent = (ExoPlayerVideoDisplayComponent) baseVideoView.getVideoDisplay();
    Video video = baseVideoView.getCurrentVideo();
    ExoPlayer exoPlayer = videoDisplayComponent.getExoPlayer();

    CustomerPlayerData customerPlayerData = new CustomerPlayerData();
    CustomerVideoData customerVideoData = new CustomerVideoData();
    customerVideoData.setVideoTitle(video.getId());
    CustomerData customerData = new CustomerData(customerPlayerData, customerVideoData, null)

    if (muxStatsExoPlayer != null) {
      muxStatsExoPlayer.release();
      muxStatsExoPlayer = null;
    }

    muxStatsExoPlayer = new MuxStatsExoPlayer(this, "YOUR_ENV_KEY_HERE", exoPlayer, baseVideoView, customerData);
  }
}
```


# Monitor CTS PDK
This guide walks through integration with Comcast Technology Solutions Player Development Kit (CTS PDK).
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Custom Dimensions
- Custom Beacon Domain

```

Notes:

```md
Video Quality metrics are not available.
```

## 1. Install \`cts-mux\`

If installing from the MPX Console, load `ctx-mux` from the CDN:

```curl
https://src.litix.io/cts/3/cts-mux.js
```

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

If installing in the player embed, follow the example below

```html
<div class="tpPlayer"
     id="player"
     // ... other configuration options
     tp:muxPlugin = "priority=1|URL=https://src.litix.io/cts/3/cts-mux.js|env_key=ENV_KEY|debug=false">
</div>
<script>
  // Creates the Player object that builds the component.
  const player = new Player("player");
  player.bind("player");
</script>
```

## 2. Make your data actionable

The only required field in the SDK options is `env_key`. Mux will automatically pull some metadata fields like `video_id`, `video_title`, and `video_duration` from the player itself. You can optionally override these values in the plugin parameters. Providing useful metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

Pass in metadata fields separated by `|` with the plugin parameters.

```html
<div class="tpPlayer"
     id="player"
     // ... other configuration options
     tp:muxPlugin = "priority=1|URL=https://src.litix.io/cts/3/cts-mux.js|env_key=ENV_KEY|debug=false|player_name='EXAMPLE_PLAYER_NAME'|player_version=1.0.0">
</div>
<script>
  // Creates the Player object that builds the component.
  const player = new Player("player");
  player.bind("player");
</script>
```

The only required field in the `options` that you pass into the `data` options in the `player.mux` function is `env_key`. But without some metadata the metrics in your dashboard will lack the necessary information to take meaningful actions. Metadata allows you to search and filter on important fields in order to diagnose issues and optimize the playback experience for your end users.

For more information, view [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata).

## 3. Advanced options

### Changing the video

If the underlying source changes of the video within the same player, `cts-mux` will track this change automatically. No extra configuration is needed.

### Disable cookies

By default, `cts-mux` uses a cookie to track playback across subsequent page views. This cookie includes information about the tracking of the viewer, such as an anonymized viewer ID that Mux generates for each user. None of this information is personally-identifiable, but you can disable the use of this cookie if desired. For instance, if your site or application is targeted towards children under 13, you should disable the use of cookies.

This is done by setting `disableCookies=true` in the options passed to the Mux plugin.

```html
<div class="tpPlayer"
     id="player"
     // ... other configuration options
     tp:muxPlugin = "priority=1|URL=https://src.litix.io/cts/3/cts-mux.js|env_key=ENV_KEY|debug=false|player_name='EXAMPLE_PLAYER_NAME'|disableCookies=true>
</div>
<script>
  // Creates the Player object that builds the component.
  const player = new Player("player");
  player.bind("player");
</script>
```

### Over-ride 'do not track' behavior

By default, `cts-mux` does not respect [Do Not Track](https://www.eff.org/issues/do-not-track) when set within browsers. This can be enabled in the options passed to Mux, via a setting named `respectDoNotTrack`. The default for this is `false`. If you would like to change this behavior, pass `respectDoNotTrack=true`.

```html
<div class="tpPlayer"
     id="player"
     // ... other configuration options
     tp:muxPlugin = "priority=1|URL=https://src.litix.io/cts/3/cts-mux.js|env_key=ENV_KEY|debug=false|player_name='EXAMPLE_PLAYER_NAME'|respectDoNotTrack=true>
</div>
<script>
  // Creates the Player object that builds the component.
  const player = new Player("player");
  player.bind("player");
</script>
```

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

There is currently no way to change the default error tracking behavior. If this is something you need in your CTS PDK integration, please reach out.

### Ads tracking with `cts-mux`

Mux has been tested with CTS's VAST plugin for ad support. Configure the VAST plugin as you would with your PDK player normally, and Mux will track ads automatically. No additional configuration is needed.


# Monitor Chromecast
This guide walks through integration with Chromecast to collect video performance metrics with Mux data.
Mux Data is the best way to monitor video streaming performance.

Integration is easy - just initialize the Mux SDK, pass in some metadata, and you're up and running in minutes.

This documents integration instructions for Chromecast. For other players, see the additional Integration Guides.

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Web metrics such as Player Startup Time, Page Load Time, etc
- Average Bitrate metrics and `renditionchange` events
- Request metrics
- Customizable Error Tracking
- Custom Beacon Domain

```

Notes:

```md
Average Bitrate metrics available in v4.2.11 and newer.
```

## 1. Include the Mux Data SDK

Mux supports Chromecast applications that are built on top of the Cast Application Framework [CAF](https://developers.google.com/cast/docs/caf_receiver_overview) Receiver SDK. The CAF Receiver SDK supports the following [streaming protocols](https://developers.google.com/cast/docs/media#delivery-methods-and-adaptive-streaming-protocols).

A Chromecast application contains two main components: a sender and a receiver. The Mux Data SDK is integrated at the receiver side; include the `chromecast-mux.js` JavaScript file within your custom receiver application. You can use the Mux-hosted version of the script to receive automatic updates. (The API will not change within major versions, as in `chromecast/MAJOR_VERSION/chromecast-mux.js`).

```npm
npm install --save @mux/mux-data-chromecast
```

```yarn
yarn add @mux/mux-data-chromecast
```

```cdn
<script src="//src.litix.io/chromecast/4/chromecast-mux.js"></script>
```



## 2. Initialize Mux Data

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

To monitor video playback within your Chromecast application, pass the `PlayerManager` instance to `initChromecastMux` along with SDK options and metadata.

You can initialize within a message interceptor for the `LOAD` event, or immediately on app load as before. This suggestion changed in version 4.0.0 and newer.

```js
import initChromecastMux from '@mux/mux-data-chromecast';

var app = {
  init: function () {
    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();
    let firstPlay = true;
    let playerInitTime = initChromecastMux.utils.now();

    playerManager.setMessageInterceptor(cast.framework.messages.MessageType.LOAD, loadRequestData => {
      if (firstPlay) {
        initChromecastMux(playerManager, {
          debug: false,
          data : {
            env_key: 'ENV_KEY', // required

            // Metadata
            player_name: 'Custom Player', // ex: 'My Main Player'
            player_init_time: playerInitTime,

            // ... additional metadata
          }
        });
      }

      return loadRequestData;
    });

    context.start();
  }
};

$(document).ready(function () {
  app.init();
});
```

After you've finished integration, the quickest way to see that the SDK is loaded is to pass `debug: true` in the options passed to the SDK. With this flag enabled, you can open the debug console, and you should start seeing debug statements from \[mux] when you click play on the video.

After playing a video, a few minutes after you stop watching, you'll see the results in your Mux account. We'll also email you when your first video view has been recorded. Log in to the dashboard and find the environment that corresponds to your env\_key and look for video views.

Note that it may take a few minutes for views to show up in the Mux Data dashboard.

## 3. Make your data actionable

[Detailed Documentation](/docs/guides/make-your-data-actionable-with-metadata)

Options are provided via the `data` object passed in the call to `initChromecastMux`.

All metadata details except for `env_key` are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Set or update metadata after initialization

There are some cases where you may not have the full set of metadata until after the video playback has started. In this case, you should omit the values when you first call `initChromecastMux`. Then, once you have the metadata, you can update the metadata with the `updateData` method.

```js
playerManager.mux.updateData({ video_title: 'My Updated Great Video' });
```

## 5. Changing the video

There are two cases where the underlying tracking of the video view need to be reset:

1. **New source:** When you load a new source URL into an existing player.
2. **New program:** When the program within a singular stream changes (such as a program change within a continuous live stream).

Note: You do not need to change the video info when changing to a different source of the same video content (e.g. different resolution or video format).

### New source

If your application plays multiple videos back-to-back in the same video player, you need to signal when a new video starts to the Mux SDK. Examples of when this is needed are:

* The player advances to the next video in a playlist
* The user selects a different video to play

In order to signal the Mux SDK that a new view is starting, you will need to emit a `videochange` event, along with metadata about the new video. See metadata in [Make your data actionable](/docs/guides/make-your-data-actionable-with-metadata) for the full list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video_`.

It's best to change the video info immediately after telling the player which new source to play.

The source change should be done by intercepting the `cast.framework.messages.MessageType.LOAD` message and doing the following:

```js
playerManager.setMessageInterceptor(cast.framework.messages.MessageType.LOAD, loadRequestData => {
  // It's important to only call this on subsequent videos being loaded, not
  // the first playback (where you call `initChromecastMux`).
  if (!firstVideo) {
    playerManager.mux.emit('videochange', { ... });
  }

  return loadRequestData;
});
```

### New program

In some cases, you may have the program change within a stream, and you may want to track each program as a view on its own. An example of this is a live stream that streams multiple programs back to back, with no interruptions.

In this case, you emit a `programchange` event, including the updated metadata for the new program within the continuous stream. This will remove all previous video data and reset all metrics for the video view, creating a new video view. See [Metadata](/docs/guides/make-your-data-actionable-with-metadata) for the list of video details you can provide. You can include any metadata when changing the video but you should only need to update the values that start with `video`.

Note: The `programchange` event is intended to be used *only* while the player is currently not paused. If you emit this event while the player is paused, the resulting view will not track video startup time correctly, and may also have incorrect watch time. Do not emit this event while the player is paused.

## 6. Advanced options

### Customize error tracking behavior

<Callout type="error" title="Errors are fatal">
  Errors tracked by mux are considered fatal meaning that they are the result of playback failures. If errors are non-fatal they should not be captured.
</Callout>

By default, `@mux/mux-data-chromecast` will track errors emitted from the video element as fatal errors. If a fatal error happens outside of the context of the player, you can emit a custom error to the mux monitor.

```js
playerManager.mux.emit('error', {
  player_error_code: 100,
  player_error_message: 'Description of error',
  player_error_context: 'Additional context for the error'
});
```

When triggering an error event, it is important to provide values for `player_error_code` and `player_error_message`. The `player_error_message` should provide a generalized description of the error as it happened. The `player_error_code` must be an integer, and should provide a category of the error. If the errors match up with the [HTML Media Element Error](https://developer.mozilla.org/en-US/docs/Web/API/MediaError), you can use the same codes as the corresponding HTML errors. However, for custom errors, you should choose a number greater than or equal to `100`.

In general you should not send a distinct code for each possible error message, but rather group similar errors under the same code. For instance, if your library has two different conditions for network errors, both should have the same `player_error_code` but different messages.

The error message and code are combined together and aggregated with all errors that occur in your environment in order to find the most common errors that occur. To make error aggregation as useful as possible, these values should be general enough to provide useful information but not specific to each individual error (such as stack trace).

You can use `player_error_context` to provide instance-specific information derived from the error such as stack trace or segment-ids where an error occurred. This value is not aggregated with other errors and can be used to provide detailed information. *Note: Please do not include any personally identifiable information from the viewer in this data.*

### Error translator

If your player emits error events that are not fatal to playback or the errors are unclear and/or do not have helpful information in the default error message and codes you might find it helpful to use an error translator or disable automatic error tracking all together.

```js
function errorTranslator (error) {
  return {
    player_error_code: translateCode(error.player_error_code),
    player_error_message: translateMessage(error.player_error_message),
    player_error_context: translateContext(error.player_error_context)
  };
}

initChromecastMux(playerManager, {
  debug: false,
  errorTranslator: errorTranslator,
  data : {
    env_key: 'ENV_KEY', // required
    // Metadata
    player_name: 'Custom Player', // ex: 'My Main Player'
    // ... additional metadata
  }
});

```

If you return `false` from your `errorTranslator` function then the error will not be tracked. Do this for non-fatal errors that you want to ignore. If your `errorTranslator` function itself raises an error, then it will be silenced and the player's original error will be used.

### Disable automatic error tracking

In the case that you want full control over what errors are counted as fatal or not, you may want to consider turning off Mux's automatic error tracking completely. This can be done by passing `automaticErrorTracking: false` in the configuration object.

```js
initChromecastMux(playerManager, {
  debug: false,
  automaticErrorTracking: false,
  data : {
    env_key: 'ENV_KEY', // required
    // Metadata
    player_name: 'Custom Player', // ex: 'My Main Player'
    // ... additional metadata
  }
});
```

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
initChromecastMux(playerManager, {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  data: {
    env_key: "ENV_KEY",
    // ...
  }
});
```

## Destroying the Monitor

There are certain use cases where you want to stop monitoring playback within a player (for instance if the player is no longer being used, you are recycling players, or you are shutting down the application). In this case, you should make sure to destroy the monitor. This can be done by simply calling `playerManager.mux.destroy()`.


# Monitor Roku
This guide walks through integration with Roku to collect video performance metrics with Mux data.
Mux's Roku integration supports Roku SceneGraph applications, in conjunction with standard `Video` nodes. Mux runs as a `Task` alongside the `Video` node, and supports instances where the `Video` nodes are reused with additional content as well as when the `Video` nodes are reset between content.

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Custom Dimensions

```

Notes:

```md
Video Quality metrics are not available.
```

## 1. Include the Mux Data SDK

Place the SDK file in your `libs` folder. The latest version of the SDK can be found here:

```sh
https://src.litix.io/roku/2/mux-analytics.brs
```

## 2. Setup a new Mux Task

Create a new `Task` XML named `MuxTask.xml` inside your `components` folder and give it the following interface. This is used to link the `mux-analytics.brs` file into your application.

```html
<component name="MuxTask" extends="Task">
  <interface>
    <field id="video" type="node" alwaysNotify="true"/>
    <field id="config" type="assocarray" alwaysNotify="true"/>
    <field id="rafEvent" type="assocarray" alwaysNotify="true"/>
    <field id="error" type="assocarray" alwaysNotify="true"/>
    <field id="view" type="String" alwaysNotify="true"/>
    <field id="exit" type="Boolean" alwaysNotify="true"/>
    <field id="exitType" type="String" alwaysNotify="true" value="hard"/>
    <field id="useRenderStitchedStream" type="Boolean" alwaysNotify="true" value="false"/>
    <field id="useSSAI" type="Boolean" alwaysNotify="true" value="false"/>
    <field id="disableAutomaticErrorTracking" type="Boolean" alwaysNotify="true" value="false"/>
    <field id="randomMuxViewerId" type="Boolean" value="false"/>
    <field id="cdn" type="String" alwaysNotify="true" />
    <field id="disablePlayheadRebufferTracking" type="Boolean" alwaysNotify="true" value="false" />
    <field id="disableDecoderStats" type="Boolean" alwaysNotify="true" value="false" />
    <field id="rebufferstart" type="Boolean" alwaysNotify="true" />
    <field id="rebufferend" type="Boolean" alwaysNotify="true" />
    <field id="playback_mode" type="assocarray" alwaysNotify="true" />
    <field id="request" type="assocarray" alwaysNotify="true" />
  </interface>
  <script type="text/brightscript" uri="pkg:/libs/mux-analytics.brs"/>
</component>
```

## 3. Setup the task to respond to video events

Within your main application, create the Mux Task node, and pass the `Video` node that you are tracking to it. This should be done before the content is set into the `Video` node so that Mux can track the load process.

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

```js
m.mux = m.top.CreateNode("mux")
m.mux.setField("video", m.video)

muxConfig = {
  env_key: "ENV_KEY",
}

m.mux.setField("config", muxConfig)
m.mux.control = "RUN"

' Load the video into the Video node
```

After you've integrated, start playing a video in the player you've integrated with. A few minutes after you stop watching, you'll see the results in your Mux account. We'll also email you when your first video view has been recorded.

You can also test that Mux is receiving data in the Mux Data dashboard. Login to the dashboard and find the environment that corresponds to your `ENV_KEY` and look for video views.

Note that it may take a few minutes for views to show up in the Mux Data dashboard.

## 4. Debugging

To help you with the integration process and ensure you have successfully incorporated the SDK within your player, we have provided a number of optional manifest attributes. These attributes can help you better understand how the MUX SDK event tracking works as well as show you the actual data being collected. Some of the benefits of using some of the debugging attributes (mentioned below) are that you will be able to see the SDK events and data collected as it occurs.

**NOTE:** The outputs illustrated below are printed on a single line within the terminal to reduce clutter.

<Callout type="info">
  Note that the following settings are configured in your application's `manifest` file, rather than passed into the config object.
</Callout>

### mux\_debug\_events

#### Values

`full`, `partial` or `none`

#### Description

Outputs the event at the time it occurs. Default value is `none`

#### Example output

Property set to `partial`:

```sh
[mux-analytics] EVENT playerready
```

Property set to `full`:

```sh
[mux-analytics] EVENT playing
{
  viewer_application_name:Roku,
  mux_api_version:2.1,
  view_seek_duration:0,
  viewer_application_version:9.20,
  player_name:Reset Player,
  viewer_time:1582317809984,
  view_start:1582317808627,
  player_model_number:4660X,
  video_source_mime_type:mp4,
  event:playing,
  ...
```

***

### mux\_debug\_beacons

#### Values

`full`, `partial` or `none`

#### Description

Outputs the data (full) or event(s) (partial) that is being sent (at the time of sending). Default value is `none`.

#### Example output

Property set to `partial`:

```sh
[mux-analytics] BEACON (2) [  playerready viewstart ]
```

Property set to `full`:

```sh
[mux-analytics] BEACON (2)
[
  {
    viewer_application_name:Roku,
    mux_api_version:2.1,
    view_seek_duration:0,
    viewer_application_version:9.20,
    player_name:Reset Player,
    viewer_time:1582317809984,
    view_start:1582317808627,
    player_model_number:4660X,
    video_source_mime_type:mp4,
    event:playerready,
    ...
  }, {
    viewer_application_name:Roku,
    mux_api_version:2.1,
    view_seek_duration:0,
    viewer_application_version:9.20,
    player_name:Reset Player,
    viewer_time:1582317809984,
    view_start:1582317808627,
    player_model_number:4660X,
    video_source_mime_type:mp4,
    event:viewstart,
    ...
  }
]
```

***

### `mux_base_url`

#### Values

Protocol + domain name. Eg. `https://img.litix.io`

#### Description

Controls to which domain the data should be sent. Useful for environmental builds of your project

## 5. Make your data actionable

The Roku SDK supports adding metadata via two different mechanisms.

The majority of the metadata should be passed inside the `muxConfig` object that is passed to the Mux Task. You can read detailed information about the fields that are supported in [Metadata](/docs/guides/make-your-data-actionable-with-metadata). To update any field, update this within `muxConfig` and then call `m.mux.setField("config", muxConfig)`.

Some other underlying information is mapped from standard [Roku content metadata](https://developer.roku.com/docs/developer-program/getting-started/architecture/content-metadata.md), most of which you probably already set when creating your video. In particular, the metadata fields that you should set (if you do not already) are:

* *ContentType*
* *URL*
* *Live*
* *StreamFormat*
* *Length*

## 6. Advertising configuration

If advertising is to be used, you must send the appropriate events to the Mux Task, as shown below.

```js
function setUpRokuAdFramework
  adIface.SetTrackingCallback(adTrackingCallback, adIface)
end function

function adTrackingCallback(obj = Invalid as Dynamic, eventType = Invalid as Dynamic, ctx = Invalid as Dynamic)
  m.mux = GetGlobalAA().global.findNode("mux")
  adUrl = Invalid
  if obj <> Invalid
    adUrl = obj.getAdUrl()
  end if
  m.mux.setField("rafEvent", {obj: { adurl: adUrl }, eventType:eventType, ctx:ctx})
end function
```

If you would like to pass your own ad parameters, you can do so by setting `ctx.mux` to an associative array with the values you desire. Currently the only value supported is `ad_type`.

```js
function adTrackingCallback(obj = Invalid as Dynamic, eventType = Invalid as Dynamic, ctx = Invalid as Dynamic)
  m.mux = GetGlobalAA().global.findNode("mux")
  adUrl = Invalid
  if obj <> Invalid
    adUrl = obj.getAdUrl()
  end if
  # Add your ad_type if you desire
  ctx.mux = {}
  ctx.mux.ad_type = "preroll"
  m.mux.setField("rafEvent", {obj: { adurl: adUrl }, eventType:eventType, ctx:ctx})
end function
```

If you are utilizing RAF's `renderStitchedStream` method to stitch ads and content together client-side, then you must tell the Mux SDK that this is in use. This is set via `useRenderStitchedStream` on the Mux Task, set to `true`, such as:

```js
mux.setField("useRenderStitchedStream", true)
```

If you are *not* utilizing `renderStitchedStream` but instead controlling ad and content playback directly, then you need to set `useRenderStitchedStream` to `false`.

If you are utilizing server-side ad insertion (SSAI), you should signal that to the SDK by setting `useSSAI` to `true`:

```js
mux.setField("useSSAI", true)
```

## 7. Additional configuration

There are a number of options you can configure on MuxTask, which can be used to customize the SDK:

| Field Name | Type | Description |
|:-|:-|:-|
| `video` | `Node` | The `Video` node that is being tracked. |
| `config` | `assocarray` | Configuration for the Mux task, including env key and additional metadata. |
| `rafEvent` | `assocarray` | Used to forward RAF events from your application into the Mux SDK. See [Advertising Configuration](#6-advertising-configuration) for more information. |
| `view` | `String` | Used to control when views start and end directly. See [Controlling View Start and End Directly](#controlling-view-start-and-end-directly) for more information. |
| `disableAutomaticErrorTracking` | `Boolean` | Used to signal errors manually. See [Manually Tracking Errors](#manually-tracking-errors) for more information. |
| `error` | `assocarray` | Used to signal errors manually. See [Manually Tracking Errors](#manually-tracking-errors) for more information. |
| `exit` | `Boolean` | Used to exit tracking directly. See [Controlling View Start and End Directly](#controlling-view-start-and-end-directly) for more information. |
| `exitType` | `String` | Used to control the mechanism used while exiting tracking. See [Controlling View Start and End Directly](#controlling-view-start-and-end-directly) for more information. |
| `useRenderStitchedStream` | `Boolean` | Used to set whether `renderStitchedStream` is used for advertising in your application. See [Advertising Configuration](#6-advertising-configuration) for more information. |
| `useSSAI` | `Boolean` | Used to set whether Roku's built-in server-side-ad-insertion is used for advertising in your application. See [Advertising Configuration](#6-advertising-configuration) for more information. |
| `randomMuxViewerId` | `Boolean` | Used to instruct Mux to use a random viewer ID instead of an ID based on the device. By default, Mux utilizes the [device RIDA](https://developer.roku.com/docs/references/brightscript/interfaces/ifdeviceinfo.md#getrida-as-string) as the viewer ID. If this flag is enabled, unique viewer counts may be inflated.  |
| `cdn` | `String` | Used to manually signal when the CDN changes. See [CDN Tracking](#cdn-tracking) for more information. |
| `disablePlayheadRebufferTracking` | `Boolean` | Used to control rebuffering directly. See [Rebuffer Controls](#rebuffer-controls) for more information. |
| `rebufferstart` | `Boolean` | Used to control rebuffering directly. See [Rebuffer Controls](#rebuffer-controls) for more information. |
| `rebufferend` | `Boolean` | Used to control rebuffering directly. See [Rebuffer Controls](#rebuffer-controls) for more information. |
| `disableDecoderStats` | `Boolean` | By default, Mux sets `enableDecoderStats` to true on the `Video` node. Set this to `true` not enable decoder stats; dropped frames will no longer be tracked. |
| `playback_mode` | `assocarray` | Used to set and update [Playback Mode](#playback-mode). |
| `request` | `assocarray` | Used to trigger [custom network request events](#network-custom-request-event). |

### Controlling View Start and End Directly

In some situations, it is necessary to directly signal the beginning or ending of a `view` to Mux. This is necessary when the `Video` Node is recycled (i.e. more pieces of content are loaded into the same Node), or when using advertising, as the ads run outside of the lifecycle of the Video.

Note: A `view` is defined as the user watching a single piece of *content*, which includes any advertising.

```js
mux = GetGlobalAA().global.findNode("mux")

' To signal the start of a view:
mux.setField("view", "start")

' To signal the end of a view:
mux.setField("view", "end")
```

The `exitType` setting controls the behavior of the task when a request to exit/terminate the thread is invoked (via `mux.exit=true`). The default value of `exitType` is `hard`.

If the value is set to `hard` then the thread terminates immediately and any data that has not propagated already to the MUX servers is lost.

If the value is set to `soft` then the thread sends all the remaining data to the MUX servers and terminates afterward.

To change value to `soft` call `m.mux.setField("exitType", "soft")`

NOTE: This means that there might be a time difference between you calling `mux.exit=true` and the task thread actually terminating. Please ensure you have a single `MUX Task` running at any given time.

### Manually Tracking Errors

The Mux SDK for Roku tracks error events from the Video node automatically, and reports them as fatal playback errors. If you would like to disable this automatic error tracking, you can set the following in your MuxTask.xml:

```js
<field id="disableAutomaticErrorTracking" type="Boolean" alwaysNotify="true" value="true"/>
```

While it is not advised to control this at runtime, you can also set this by calling

```js
mux.setField("disableAutomaticErrorTracking", true)
```

In order to emit events, you will need to trigger any errors directly, by calling

```js
mux.setField("error", {
  player_error_code: errorCode,
  player_error_message: errorMessage,
  player_error_context: errorContext,
  player_error_severity: errorSeverity,
  player_error_business_exception: isBusinessException
})
```

The error code and message should always be provided, and you can set the other fields if desired. The possible values or `errorSeverity` are `"warning"` or `"fatal"`. Read more about [Error Classification](/docs/guides/error-categorization) for more details.

### CDN Tracking

The Mux SDK for Roku can listen to CDN change events. In order to emit events, you will need to trigger any CDN changes directly, by calling

```js
' The "new_cdn" string should be the new CDN name
mux.setField("cdn", "new_cdn")
```

### Rebuffer Controls

<Callout type="warning">
  Mux does not suggest disabling the automatic rebuffer tracking. The following is for advanced usage only.
</Callout>

The Mux SDK for Roku tracks error events from the Video node automatically. If you would like to disable this automatic rebuffer tracking, you can set the following in your MuxTask.xml:

```js
<field id="disablePlayheadRebufferTracking" type="Boolean" alwaysNotify="true" value="true"/>
```

While it is not advised to control this at runtime, you can also set this by calling

```js
mux.setField("disablePlayheadRebufferTracking", true)
```

Rebuffer start and end events can be emitted by calling the following

```js
mux.setField("rebufferstart", true)
```

```js
mux.setField("rebufferend", true)
```

### Playback Mode

A playback mode event can be emitted by calling the following

```js
mux.setField("playback_mode", {
  player_playback_mode: mode,
  player_playback_mode_data: data
})
```

The `mode` should always be provided, suggested values are: `inline`, `fullscreen`, `mini` and `pip`.
The `data` is optional, if provided it should be a parse-able JSON string.

A `playbackmodechange` event will be emitted containing the following fields:

* `player_playback_mode` (containing the mode set)
* `player_playback_mode_data` (containing the data set)
* `ad_playing_time_ms_cumulative` (containing ad watch time)
* `view_playing_time_ms_cumulative` (containing the total content watch time plus ad watch time)

### Network custom request event

Custom request events can be emitted with custom data for network requests by calling the following

```js
mux.setField("request", manifestRequest)
```

The `manifestRequest` must be a parse-able JSON string.

The following fields can be included in `manifestRequest`. All fields should be numeric values, not strings, except where noted:

* `type` (required, string) - The status of the request: `completed`, `failed`, or `canceled`
* `request_start` (numeric) - Timestamp in milliseconds since the Unix epoch when the request was initiated
* `request_response_start` (numeric) - Timestamp in milliseconds since the Unix epoch when the first byte of the response was received
* `request_response_end` (numeric) - Timestamp in milliseconds since the Unix epoch when the last byte of the response was received
* `request_bytes_loaded` (numeric) - The total number of bytes loaded as part of this request
* `request_hostname` (string) - The hostname portion of the URL that was requested
* `request_type` (string) - The type of content being requested. One of: `manifest`, `video`, `audio`, `video_init`, `audio_init`, `media`, `subtitle`, or `encryption`
* `request_id` (string) - A unique identifier for the request
* `request_url` (string) - The URL that was requested
* `request_labeled_bitrate` (numeric) - Labeled bitrate in bps of the video, audio, or media segment that was downloaded
* `request_response_headers` (object) - A map of response headers and their values
* `request_media_duration` (numeric) - The duration of the media loaded, in seconds. Should not be included for manifest requests
* `request_video_width` (numeric) - For events with `media` or `video` `request_type`, the width of the video included in the segment/fragment
* `request_video_height` (numeric) - For events with `media` or `video` `request_type`, the height of the video included in the segment/fragment
* `request_error` (string) - The name of the error event that occurred (e.g., `FragLoadError`)
* `request_error_code` (numeric) - The response code of the request that spawned the error (e.g., 401, 400, 500)
* `request_error_text` (string) - The message returned with the failed status code

Depending on the `type` value, a corresponding event will be emitted: `requestcompleted` (for `type: "completed"`), `requestfailed` (for `type: "failed"`), or `requestcanceled` (for `type: "canceled"`).

For more information about these fields, see [Network Request Data](/docs/guides/mux-data-playback-events#network-request-data).

#### Latency and Throughput Calculation

If you set `request_start`, `request_response_start`, `request_response_end`, and `request_bytes_loaded`, latency and throughput will be automatically calculated and sent in each event.

* Latency is calculated as the time between `request_start` and `request_response_start`.
* Throughput is calculated as `request_bytes_loaded` divided by the time between `request_response_start` and `request_response_end`.

#### Request Duration Calculation

If the request is completed (`type` is `"completed"`), the `request_type` is `"api"` or `"encryption"`, and both `request_start` and `request_response_end` are present as valid numeric values, the total request duration (`request_duration`) will be calculated as `request_response_end - request_start` and included in the event. Requests of type `"api"` or `"encryption"` are limited to a maximum of 5 per view; if this limit is exceeded, the event is discarded and not sent to Mux.


# Samsung-Tizen
This guide walks through integration with Samsung Tizen to collect video performance metrics with Mux data.
Mux Data is the best way to monitor video streaming performance.

Integration is easy - just initialize the Mux SDK, pass in some metadata, and you're up and running in minutes.

This documents integration instructions for Samsung Tizen TVs. For other players, see the additional Integration Guides.

## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics
- Custom Beacon Domain

```

Notes:

```md
No notes provided
```

## 1. Include the Mux Data SDK

Mux Data supports applications built for Samsung Tizen TVs using JavaScript and Tizen's [AVPlay API](https://developer.samsung.com/tv/develop/api-references/samsung-product-api-references/avplay-api). The Samsung Tizen Smart TV SDK supports C++, JavaScript, and Microsoft .NET; this SDK is only compatible with JavaScript applications using AVPlay.

Include the Mux Data SDK by including the `tizen-mux.js` JavaScript file within your `index.html` file defining your application. You can use the Mux-hosted version of the script to receive automatic updates. (The API will not change within major versions, as in `tizen/MAJOR_VERSION/tizen-mux.js`.)

```html
<!-- place within the <head> of your index.html -->
<script src="//src.litix.io/tizen/2/tizen-mux.js"></script>
```

## 2. Initialize Mux Data

To monitor video playback within your Tizen application, pass the AVPlay player instance to `monitorTizenPlayer` along with SDK options and metadata.

```js
// Place in your application initialization code, around
// where you call `prepare`

var player = $('#my-player').get(0);
player.url = this.url;
var playerInitTime = monitorTizenPlayer.utils.now();
this.prepare();
monitorTizenPlayer(player, {
  debug: true,
  data: {
    env_key: 'ENV_KEY', // required
    // Metadata
    player_name: 'Custom Player', // ex: 'My Main Player'
    player_init_time: playerInitTime,
    // ... additional metadata
  },
  // Optional passthrough listener
  playbackListener: playbackListener
});
```

Tizen's AVPlay API does not allow multiple AVPlayPlaybackCallback listeners to be registered to a player. If you require your own listener to be registered, you must pass this in as `playbackListener` as shown above. Mux's SDK will proxy the calls to your listener. (Note: the location of this changed with v1.0.0)

To stop monitoring your player (e.g. when playback is complete), call `player.mux.stopMonitor()`.

Log in to the Mux dashboard and find the environment that corresponds to your `env_key` and look for video views. It takes about a minute or two from tracking a view for it to show up on the Metrics tab.

**If you aren't seeing data**, check to see if you have an ad blocker, tracking blocker or some kind of network firewall that prevents your player from sending requests to Mux Data servers.

## 3. Make your data actionable

[Detailed Documentation](/docs/guides/make-your-data-actionable-with-metadata)

Options are provided via the data object passed in the call to `monitorTizenPlayer`.

All metadata details except for `env_key` are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

```js
monitorTizenPlayer(player, {
  debug: false,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

## 4. Advanced options

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
monitorTizenPlayer(player, {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', //ex: 'foo.bar.com'
  data: {
    env_key: 'ENV_KEY', // required
    // ,,,
  }
});
```


# Monitor LG
This guide walks through integration with LG Smart TVs to collect video performance metrics with Mux data.
## Features

The following data can be collected by the Mux Data SDK when you use the \{featureDef.name} SDK, as described
&#x20;       below.

```md
- Engagement metrics
- Quality of Experience Metrics

```

Notes:

```md
No notes provided
```

## 1. Integration overview

LG Smart TV applications are built on top of the HTML5 video technology. To support video streaming, these applications can be integrated with player SDKs such as the [HLS.js](https://video-dev.github.io/hls.js/) and [Dash.js](https://github.com/Dash-Industry-Forum/dash.js).

Due to the HTML5 nature of LG Smart TV applications, the Mux Data integration with LG televisions uses one of the HTML5 integrations, such as the ones listed above. When setting up your application, you should check which video player engine that is used, and depending on that, utilize the appropriate integration point within `mux-embed`.

Check these 3 web integration guides for more details:

* [HTML5 video element](/docs/guides/monitor-html5-video-element)
* [HLS.js](/docs/guides/monitor-hls-js)
* [Dash.js](/docs/guides/monitor-dash-js)

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

```js
// main.js
play: function() {
  var data = {
    env_key: 'ENV_KEY', // required
    player_name: 'My Custom Player',
    player_init_time: mux.utils.now(),
    // ... additional metadata
  };

  switch (this.playerEngine) {
    case this.PLAYENGINE_HLSJS:
      if (Hls.isSupported()) {
        const hls = new Hls();
        hls.loadSource('<your source file>');
        hls.attachMedia(this.player);
        hls.on(Hls.Events.MANIFEST_PARSED,function(e,d) {
          app.player.play();
        });
        mux.monitor('#my-player', {
          debug: true,
          hlsjs: hls,
          Hls: Hls,
          data: data
        });
        this.hls = hls;
      }
      break;
    case this.PLAYENGINE_DASHJS:
      const dashjsPlayer = dashjs.MediaPlayer().create();
      dashjsPlayer.getDebug().setLogToBrowserConsole(false);
      mux.monitor('#my-player', {
        debug: true,
        dashjs: dashjsPlayer,
        data: data
      });
      dashjsPlayer.initialize(this.player, 'http://dash.edgesuite.net/envivio/EnvivioDash3/manifest.mpd', true);
      this.dashjsPlayer = dashjsPlayer;
      break;
  }
}
```

After you've finished integration, the quickest way to see that the SDK is loaded is to pass `debug: true` in the options passed to the SDK. With this flag enabled, you can open the debug console, and you should start seeing debug statements from \[mux] when you click play on the video.

After playing a video, a few minutes after you stop watching, you'll see the results in your Mux account. We'll also email you when your first video view has been recorded. Log in to the dashboard and find the environment that corresponds to your env\_key and look for video views.

Note that it may take a few minutes for views to show up in the Mux Data dashboard.

## 2. Make your data actionable

Options are provided via the data object passed in the call to `mux.monitor`.

All metadata details except for `env_key` are optional, however you'll be able to compare and see more interesting results as you include more details. This gives you more metrics and metadata about video streaming, and allows you to search and filter on important fields like the player version, CDN, and video title.

```js
mux.monitor('#my-player', {
  debug: false,
  hlsjs: hls,
  Hls,
  data: {
    env_key: 'ENV_KEY', // required
    // Site Metadata
    viewer_user_id: '', // ex: '12345'
    experiment_name: '', // ex: 'player_test_A'
    sub_property_id: '', // ex: 'cus-1'
    // Player Metadata
    player_name: '', // ex: 'My Main Player'
    player_version: '', // ex: '1.0.0'
    player_init_time: '', // ex: 1451606400000
    // Video Metadata
    video_id: '', // ex: 'abcd123'
    video_title: '', // ex: 'My Great Video'
    video_series: '', // ex: 'Weekly Great Videos'
    video_duration: '', // in milliseconds, ex: 120000
    video_stream_type: '', // 'live' or 'on-demand'
    video_cdn: '' // ex: 'Fastly', 'Akamai'
  }
});
```

For more information, see the [Metadata Guide](/docs/guides/make-your-data-actionable-with-metadata).

## 3. Advanced options

### Customize beacon collection domain

If you have [integrated a custom domain for Data collection](/docs/guides/integrate-a-data-custom-domain), specify your custom domain by setting `beaconCollectionDomain`.

```js
mux.monitor('#my-player', {
  debug: false,
  beaconCollectionDomain: 'CUSTOM_DOMAIN', // ex: 'foo.bar.com'
  hlsjs: hls,
  Hls,
  data: {
    env_key: 'ENV_KEY', // required
    // ... additional metadata
  }
});
```


# Monitor Agnoplay player service
This guide walks through integration with Agnoplay to collect video performance metrics with Mux Data. Because Agnoplay has Mux Data fully pre-integrated there will be no need of any development effort to activate Mux Data.
<Callout type="warning" title="Third-party integration">
  This integration is managed and operated by [Agnoplay](https://agnoplay.com).
  Feedback should be made through your Agnoplay representative [https://agnoplay.com](https://agnoplay.com) or info@agnoplay.com.
</Callout>

# Environment key

Get your `ENV_KEY` from the [Mux environments dashboard](https://dashboard.mux.com/environments).

<Callout type="info" title="Env Key is different than your API token">
  `ENV_KEY` is a client-side key used for Mux Data monitoring. These are not to be confused with API tokens which are created in the admin settings dashboard and meant to access the Mux API from a trusted server.
</Callout>

<Image src="/docs/images/env-key.png" width={2004} height={250} />

# Contact Agnoplay

Contact your Agnoplay representative through [https://agnoplay.com](https://agnoplay.com) or [info@agnoplay.com](mailto:info@agnoplay.com), and provide them with your environment key.

# Wait for the magic

The Agnoplay support team will add your environment key to the configuration of Agnoplay instance, after which your Mux Data environment will be populated with data within minutes. That's all to it.
