Skip to Content
Mux Docs: Home

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 SDK in order to integrate your video app with Mux Data. Our SDK consists of a set of open-source libraries 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


The following data can be collected by the Mux Data SDK when you use the AndroidX Media3 SDK, as described below.

Supported Features:

  • 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

Request Latency is not available.

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.

1Install 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.

// in a repositories {} block
maven {
url = uri("")

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.

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]

// 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.3.x
  • 1.2.x
  • 1.1.x
  • 1.0.x

2Integrate this SDK with Media 3 in your app

Get your ENV_KEY from the Mux environments dashboard.

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.

To monitor a Player, you need to create your player and monitor it before setting playWhenReady or calling prepare(). You must initialize your Mux Data integration with a valid Environment Key.

val myCustomerData = CustomerData()
val muxStats = exoPlayer.monitorWithMuxData(
context = context,
customerData = myCustomerData,
playerView = playerView
// Do these after creating the monitor
player.playWhenReady = true
// ... When you are done with your Player

3Add 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.

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.

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.

4Advanced 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 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 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 Views, 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.

override fun onCreate(savedInstanceState: Bundle?) {
// If you are using SimplePlayerView, StyledPlayerView, etc
playerView = findViewById(
playerView.setFullscreenButtonClickListener { isFullScreen ->
// Set presentation based on which mode is requested
if(isFullScreen) {
} else {
// 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:

// 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:
// 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)

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:


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.

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.

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.

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

// in your app's dependencies

Then, use the extension to monitor your IMA integration.

val newPlayer = ExoPlayer.Builder(this)
.setLocalAdInsertionComponents({ adsLoader }, view.playerView))
// ... rest of builder calls
muxStats = monitorPlayer(newPlayer)
adsLoader = ImaAdsLoader.Builder(this)
// ... rest of builder calls
muxStats = muxStats!!,
customerAdErrorListener = { /*Optional parameter, your custom logic*/ },
customerAdEventListener = { /*Optional parameter, your custom logic*/ },

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.

Release notes

Current Release



  • Expose parameter to control logging level when initializing monitoring

Previous Releases


  • fix: incorrect screen resolution reported in some cases
  • Update to Mux Android Core 1.2.2
  • Update to Mux Java Core 8.0.2



  • update: Add support for media3 1.3.0


  • fix: reported app hang due to event handling during beacon dispatch
  • fix: crash when exoplayer HLS module not used


  • Update Android Core to v1.2.1
  • Update Java Core to v8.0.1



  • MuxErrorException now allows you to report non-fatal and business-related errors


  • update: Updated MuxCore to version 8.0.0
  • update: Updated Android Core to version 1.2.0


  • fix: renditionchange sent in situations where rendition was only reset
  • fix: Capture IMA CSAI media failures with LOG events
  • fix: rebuffering percentage inflated if client ads fail to load



  • fix: populate ad data even for non-preroll ads
  • fix: seeking time included in time-to-first frame if user seeks before play starts


  • remove extraneous androidx deps from the exoplayer lib (they are still required if using IMA)



  • add support for media3 v1.2.x



  • add support for media3 v1.2.x



  • Expose IDevice and INetworkRequest for injection, as with the other player sdks



  • update: Update compileSdkVersion and targetSdkVersion to 34.



  • fix: SSAI Ad events not properly reported



  • fix: setting playWhenReady to true while READY sends play but not playing


  • Update to Core 1.0.1 - Fixes handling of leaving ads by seeking out of them



  • Update this SDK to v1.0.0 (🎉)


  • fix: Custom Domain implementation POSTs to wrong URL
  • fix: viewstart may not be sent if monitor attached while idle && playWhenReady == true



  • feat: Detect Title, Source URL, and Poster Art

Was this page helpful?