Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.permutive.com/llms.txt

Use this file to discover all available pages before exploring further.

The MediaTracker API allows you to track video content events with Permutive. Use this for tracking video playback, engagement, and completion metrics.

Basic Usage

Properties

Use Cases

Ad Tracking

Connected TV IntegrationVideo event tracking described below is available once the connected TV integration has been enabled. Please contact your Customer Success Manager (CSM) to enable this feature.

Overview

MediaTracker provides comprehensive video tracking capabilities:
  • Automatic lifecycle tracking - Tracks Videoview and VideoCompletion events
  • Engagement metrics - Measures time spent watching and completion percentage
  • Custom events - Track custom video-related events
  • Rich metadata - Support for extensive video properties

Video Events

MediaTracker automatically tracks two event types:

1. Videoview Event

Tracked when MediaTracker is created:
Event: Videoview
Properties:
  - [your custom properties]
  - [standard video properties]

2. VideoCompletion Event

Tracked when video is stopped:
Event: VideoCompletion
Properties:
  - aggregations.VideoEngagement.engaged_time: Total time spent watching (seconds)
  - aggregations.VideoEngagement.completion: Percentage of video viewed (0.0 - 1.0)
  - [your custom properties]
  - [standard video properties]
📘 Note The aggregations.VideoEngagement.completion property requires a known duration to be set. Pass durationMilliseconds when creating the MediaTracker.

Basic Usage

Creating a MediaTracker

Create a MediaTracker when video playback begins:
import com.permutive.android.MediaTracker
import android.net.Uri

class VideoActivity : AppCompatActivity() {

    private val permutive by lazy {
        (application as MyApplication).permutive
    }

    private lateinit var videoTracker: MediaTracker

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

        videoTracker = permutive.trackVideoView(
            durationMilliseconds = 120000, // 2 minutes
            videoProperties = MediaTracker.VideoProperties(
                title = "Sample Video",
                genre = listOf("Documentary"),
                contentType = listOf("Education"),
                runtime = 120
            )
        )
    }

    override fun onDestroy() {
        super.onDestroy()
        videoTracker.stop()  // Important: Always stop to send VideoCompletion
    }
}

MediaTracker Lifecycle

Expected Usage Flow

  1. Create MediaTracker instance with properties
  2. Call play() when playback begins
  3. Track buffering with pause() / play()
  4. Track scrubbing with play(position)
  5. Call stop() when playback completes
⚠️ Single Instance Limitation Only a single instance of PageTracker or MediaTracker is available at any time. Close existing trackers before creating new ones.

Playback Control Methods

play()

Call when video starts playing:
videoTracker.play()

play(positionMs)

Call when playback position changes (e.g., seeking):
videoTracker.play(positionMs = 30000)  // Seek to 30 seconds

pause()

Call when video is paused or buffering:
videoTracker.pause()

stop()

Call when video playback completes or user exits:
videoTracker.stop()  // Sends VideoCompletion event
⚠️ Important: Always Call stop() Failing to call stop() will prevent VideoCompletion events from being tracked.

Video Properties

Standard Video Properties

The SDK provides standard video properties for consistent tracking:
MediaTracker.VideoProperties(
    title = "Video Title",
    genre = listOf("Action", "Thriller"),
    contentType = listOf("Movie", "Feature"),
    ageRating = "PG-13",
    runtime = 7200,  // Runtime in seconds
    country = "US",
    originalLanguage = "en",
    audioLanguage = "en",
    areSubtitlesEnabled = true,
    subtitlesLanguage = "en",
    seasonNumber = 1,
    episodeNumber = 5,
    consecutiveEpisodes = 3,
    iabCategories = listOf("IAB1", "IAB2")
)

Property Reference

These are the Kotlin SDK parameter names. The SDK maps them to the snake_case event schema and nests them under the video parent automatically.
PropertyTypeSchema NameDescription
titleStringvideo.titleVideo title
genreList<String>video.genreVideo genres (e.g., “Drama”, “Comedy”)
contentTypeList<String>video.content_typeContent types (e.g., “Movie”, “Series”)
ageRatingStringvideo.age_ratingAge rating (e.g., “PG-13”, “TV-MA”)
runtimeIntvideo.runtimeRuntime in seconds
countryStringvideo.countryOrigin country
originalLanguageStringvideo.original_languageOriginal language code
audioLanguageStringvideo.audio_languageAudio language code
areSubtitlesEnabledBooleanvideo.subtitles.enabledWhether subtitles are enabled
subtitlesLanguageStringvideo.subtitles.languageSubtitle language code
seasonNumberIntvideo.season_numberSeason number (for series)
episodeNumberIntvideo.episode_numberEpisode number (for series)
consecutiveEpisodesIntvideo.consecutive_episodesConsecutive episodes watched
iabCategoriesList<String>video.iab_categoriesIAB content taxonomy categories
💡 Best Practice Track as many properties as possible to enable richer cohort creation and insights.

Page Properties (Optional)

If the video is displayed within a page context (e.g., embedded in article), include page properties:
videoTracker = permutive.trackVideoView(
    durationMilliseconds = 120000,
    videoProperties = MediaTracker.VideoProperties(
        title = "Tutorial Video"
    ),
    pageProperties = MediaTracker.PageProperties(
        title = "How to Use Android SDK",
        url = Uri.parse("https://example.com/tutorial"),
        referrer = Uri.parse("https://example.com/docs")
    )
)

PageProperties Reference

PropertyTypeDescription
titleStringPage title
urlUriPage URL
referrerUriReferring page URL

Custom Properties

Add custom properties specific to your event schema:
import com.permutive.android.EventProperties

videoTracker = permutive.trackVideoView(
    durationMilliseconds = 120000,
    videoProperties = videoProps,
    pageProperties = null,
    customEventProperties = EventProperties.from(
        "video_id" to "vid_12345",
        "playlist_id" to "playlist_abc",
        "is_premium_content" to true,
        "content_partner" to "PartnerXYZ"
    )
)

Complete Example

import com.permutive.android.MediaTracker
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity

class VideoPlayerFragment : Fragment() {

    private val permutive by lazy {
        (requireActivity().application as MyApplication).permutive
    }

    private lateinit var videoTracker: MediaTracker
    private lateinit var exoPlayer: ExoPlayer

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Initialize video tracker
        videoTracker = permutive.trackVideoView(
            durationMilliseconds = 180000, // 3 minutes
            videoProperties = MediaTracker.VideoProperties(
                title = "Introduction to Android",
                genre = listOf("Educational", "Technology"),
                contentType = listOf("Tutorial"),
                ageRating = "G",
                runtime = 180,
                country = "US",
                originalLanguage = "en",
                audioLanguage = "en",
                areSubtitlesEnabled = false,
                iabCategories = listOf("IAB19")
            ),
            pageProperties = MediaTracker.PageProperties(
                title = "Android Tutorial Page",
                url = Uri.parse("https://example.com/tutorials/android"),
                referrer = Uri.parse("https://example.com/home")
            ),
            customEventProperties = EventProperties.from(
                "video_id" to "vid_tutorial_001",
                "is_premium" to false
            )
        )

        // Set up ExoPlayer with tracking
        setupVideoPlayer()

        return inflater.inflate(R.layout.fragment_video, container, false)
    }

    private fun setupVideoPlayer() {
        exoPlayer = ExoPlayer.Builder(requireContext()).build()

        exoPlayer.addListener(object : Player.Listener {
            override fun onPlaybackStateChanged(state: Int) {
                when (state) {
                    Player.STATE_READY -> {
                        // Video ready to play
                        if (exoPlayer.isPlaying) {
                            videoTracker.play()
                        }
                    }
                    Player.STATE_BUFFERING -> {
                        videoTracker.pause()
                    }
                }
            }

            override fun onIsPlayingChanged(isPlaying: Boolean) {
                if (isPlaying) {
                    videoTracker.play()
                } else {
                    videoTracker.pause()
                }
            }
        })

        // Track position updates
        exoPlayer.addAnalyticsListener(object : AnalyticsListener {
            override fun onPositionDiscontinuity(
                eventTime: AnalyticsListener.EventTime,
                reason: Int
            ) {
                if (reason == Player.DISCONTINUITY_REASON_SEEK) {
                    videoTracker.play(exoPlayer.currentPosition)
                }
            }
        })
    }

    override fun onPause() {
        super.onPause()
        videoTracker.pause()
        exoPlayer.pause()
    }

    override fun onResume() {
        super.onResume()
        if (exoPlayer.isPlaying) {
            videoTracker.play()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        videoTracker.stop()  // Send VideoCompletion event
        exoPlayer.release()
    }
}

Tracking Custom Events

Track custom video-related events using the track() method:
// User shares video
videoTracker.track(
    "VideoShared",
    EventProperties.from(
        "share_method" to "twitter",
        "video_position_seconds" to 45
    )
)

// User adds to favorites
videoTracker.track("VideoAddedToFavorites")

// Quality changed
videoTracker.track(
    "VideoQualityChanged",
    EventProperties.from(
        "from_quality" to "720p",
        "to_quality" to "1080p"
    )
)

Video Ad Tracking

If you need to track video ads within video content, use the AdTracker API:
// Create ad tracker from video tracker
val adTracker = videoTracker.trackAdView(
    durationMs = 15000,  // 15 second ad
    adProperties = AdTracker.AdProperties(
        title = "Product Ad",
        durationInSeconds = 15,
        isMuted = false,
        campaignId = "campaign_123",
        creativeId = "creative_456"
    )
)

// Track ad playback
adTracker.play()
// ... ad plays ...
adTracker.completion()
See Video Ad Tracking for complete documentation.

Use Cases

videoTracker = permutive.trackVideoView(
    durationMilliseconds = movieDurationMs,
    videoProperties = MediaTracker.VideoProperties(
        title = movie.title,
        genre = movie.genres,
        contentType = listOf("Movie", "Feature"),
        ageRating = movie.rating,
        runtime = movie.runtimeSeconds,
        country = movie.country,
        originalLanguage = movie.language,
        iabCategories = movie.iabCategories
    )
)
videoTracker = permutive.trackVideoView(
    durationMilliseconds = tutorialDurationMs,
    videoProperties = MediaTracker.VideoProperties(
        title = tutorial.title,
        genre = listOf("Educational"),
        contentType = listOf("Tutorial"),
        runtime = tutorial.runtimeSeconds
    ),
    customEventProperties = EventProperties.from(
        "course_id" to tutorial.courseId,
        "module_id" to tutorial.moduleId,
        "difficulty_level" to tutorial.difficulty
    )
)
videoTracker = permutive.trackVideoView(
    durationMilliseconds = episodeDurationMs,
    videoProperties = MediaTracker.VideoProperties(
        title = episode.title,
        genre = series.genres,
        contentType = listOf("Series", "Episode"),
        seasonNumber = episode.season,
        episodeNumber = episode.number,
        consecutiveEpisodes = userWatchData.consecutiveCount,
        runtime = episode.runtimeSeconds
    )
)

Troubleshooting

Problem: VideoCompletion events not appearing.Cause: stop() not called.Solution: Always call stop() in onDestroy():
override fun onDestroy() {
    super.onDestroy()
    videoTracker.stop()  // REQUIRED
}
Problem: Engaged time is inaccurate.Causes:
  1. Not calling play() when video plays
  2. Not calling pause() when video pauses/buffers
Solution: Track all play/pause events:
exoPlayer.addListener(object : Player.Listener {
    override fun onIsPlayingChanged(isPlaying: Boolean) {
        if (isPlaying) {
            videoTracker.play()
        } else {
            videoTracker.pause()
        }
    }
})
Problem: completion property is missing or null.Cause: Duration not provided when creating MediaTracker.Solution: Always provide durationMilliseconds:
videoTracker = permutive.trackVideoView(
    durationMilliseconds = videoDurationMs  // REQUIRED for completion
)
Problem: Error about multiple trackers.Cause: Creating new PageTracker or MediaTracker without closing existing one.Solution: Close existing tracker first:
// Close old tracker
videoTracker.stop()

// Now create new tracker
videoTracker = permutive.trackVideoView(...)
See Common Errors for more troubleshooting.

Best Practices

  • Always call stop() when video finishes
  • Provide duration for completion tracking
  • Track play/pause events accurately
  • Include as many video properties as possible
  • Close tracker before creating a new one
  • Track buffering with pause/play

Video Ad Tracking

Track video advertisements

Page Tracking

Track non-video content

Event Properties

Custom properties

Issues

Solve common issues

API Reference

For complete API documentation, see the Javadocs.

MediaTracker Interface

  • play() - Start/resume video playback
  • play(positionMs: Long) - Start at specific position
  • pause() - Pause video playback
  • stop() - Complete video tracking (sends VideoCompletion)
  • setDuration(durationMs: Long) - Update video duration
  • track(eventName: String) - Track custom event
  • track(eventName: String, properties: EventProperties) - Track custom event with properties
  • trackAdView(...) - Create AdTracker for video ad

Creating MediaTracker

  • Permutive.trackVideoView(durationMilliseconds, videoProperties, pageProperties, customEventProperties) - Create MediaTracker