Skip to Content
Tracking YouTube Engagement

Tracking Youtube video engagement with usermaven

Track how users interact with embedded YouTube videos on your site, including plays, progress milestones, and completions. This guide provides a JavaScript solution using the YouTube Iframe Player API.

Goal

To send events to Usermaven when a user:

  • Starts playing a YouTube video.
  • Reaches specific progress milestones (e.g., 25%, 50%, 75% viewed).
  • Watches the entire video (100%).

Prerequisites

  1. Usermaven JavaScript SDK: Ensure the Usermaven SDK is installed and initialized on your website.
  2. YouTube Iframe API: You’ll need to include the YouTube Iframe API script on your page.

Implementation steps

1. HTML setup

Add a <div> element to your HTML where the YouTube player will be embedded. Give it a unique ID (e.g., player).

<!-- 1. The <iframe> (and video player) will replace this <div> tag. --> <div id="player"></div> <!-- 2. Include the YouTube Iframe API script --> <!-- This should ideally be placed before your custom script or at the end of the body --> <script src="https://www.youtube.com/iframe_api"></script>

2. Javascript tracking code

Add the following JavaScript code to your page. It’s best placed in a <script> tag after the YouTube API script include, or in your main JavaScript file.

// --- Configuration --- let player; let videoInterval; let videoEventName = "sample-video"; // Customize this for different videos const videoId = "M7lc1UVf-VE"; // REPLACE with your YouTube Video ID const breakpoints = [0.25, 0.5, 0.75]; // Progress milestones to track (25%, 50%, 75%) // --- State Variables --- let passedBreakpoint = 0; // Tracks the last breakpoint successfully reported let hasTrackedInitialPlay = false; // Ensures "clicked" event fires only once per play session // 1. This function creates an <iframe> (and YouTube player) // after the API code downloads. function onYouTubeIframeAPIReady() { player = new YT.Player("player", { // 'player' is the ID of your div height: "360", width: "640", videoId: videoId, playerVars: { // Add any playerVars you need, e.g.: // 'autoplay': 0, // 0 for no autoplay, 1 for autoplay // 'controls': 1, // 0 for no controls, 1 for controls // 'modestbranding': 1, // Hide YouTube logo // 'rel': 0 // Do not show related videos at the end }, events: { onReady: onPlayerReady, onStateChange: onPlayerStateChange, }, }); } // 2. The API will call this function when the video player is ready. function onPlayerReady(event) { // You can do initial setup here if needed, e.g., mute the player // event.target.mute(); console.log("YouTube Player ready for video:", videoId); } // 3. The API calls this function when the player's state changes. function onPlayerStateChange(event) { if (event.data === YT.PlayerState.PLAYING) { // Video is playing if (!hasTrackedInitialPlay) { // This is the first play event for this "session" usermaven("track", `clicked-${videoEventName}`); hasTrackedInitialPlay = true; passedBreakpoint = 0; // Reset breakpoints for this new viewing session } // Start checking progress if not already doing so if (!videoInterval) { videoInterval = setInterval(checkVideoState, 1000); // Check every second } } else if ( event.data === YT.PlayerState.PAUSED || event.data === YT.PlayerState.BUFFERING ) { // Video paused or buffering, stop checking progress clearInterval(videoInterval); videoInterval = null; } else if (event.data === YT.PlayerState.ENDED) { // Video ended checkVideoState(); // Run one last time to catch any final breakpoint usermaven("track", `watched-${videoEventName}-100%`); clearInterval(videoInterval); videoInterval = null; hasTrackedInitialPlay = false; // Reset for a potential replay // passedBreakpoint will be reset on the next PLAYING event } else if (event.data === YT.PlayerState.UNSTARTED || event.data === YT.PlayerState.CUED) { // Video is reset (e.g. new video loaded) or cued. clearInterval(videoInterval); videoInterval = null; hasTrackedInitialPlay = false; passedBreakpoint = 0; } } // 4. Function to check video progress and track breakpoints function checkVideoState() { if (!player || typeof player.getDuration !== 'function' || typeof player.getCurrentTime !== 'function') { return; // Player not ready or methods unavailable } const duration = player.getDuration(); if (duration === 0) { return; // Duration not available yet } const currentTime = player.getCurrentTime(); const viewedPercentage = currentTime / duration; breakpoints.forEach((breakpoint) => { if (passedBreakpoint < breakpoint && viewedPercentage >= breakpoint) { passedBreakpoint = breakpoint; // Mark this breakpoint as passed usermaven("track", `watched-${videoEventName}-${breakpoint * 100}%`); } }); }

This is a placeholder. Your actual Usermaven SDK setup will provide the usermaven() function.

// function usermaven(type, eventName, properties) { // console.log(`Usermaven Event: ${type} - ${eventName}`, properties || ""); // }

3. Customization

videoEventName:
Change sample-video to a unique, descriptive name for your video (e.g., product-demo-video, homepage-banner-video). This helps segment your analytics in Usermaven.

videoId:
Replace "M7lc1UVf-VE" with the actual YouTube Video ID you want to embed and track. The Video ID is the string of characters after v= in a YouTube URL (e.g., for https://www.youtube.com/watch?v=dQw4w9WgXcQ, the ID is dQw4w9WgXcQ).

breakpoints:
Adjust the [0.25, 0.5, 0.75] array if you want to track different progress milestones (e.g., [0.1, 0.5, 0.9] for 10%, 50%, 90%).

Player dimensions & playerVars:
Modify height, width, and the playerVars object within onYouTubeIframeAPIReady to customize the player’s appearance and behavior. See YouTube Player Parameters.

How it works

onYouTubeIframeAPIReady():
This function is automatically called by the YouTube API once it’s loaded. It initializes the YouTube player (YT.Player) targeting your <div id="player">.

onPlayerStateChange(event):
This function listens to player state changes:

  • PLAYING: When the video starts playing (or resumes), it tracks a clicked-{videoEventName} event (only once per “play session” thanks to hasTrackedInitialPlay). It also starts an interval (videoInterval) to periodically check progress. passedBreakpoint is reset here to allow tracking for replays.
  • PAUSED / BUFFERING: Clears the progress-checking interval to save resources.
  • ENDED: Tracks a watched-{videoEventName}-100% event and clears the interval. It also resets hasTrackedInitialPlay so if the user replays, the “clicked” event fires again.
  • UNSTARTED / CUED: Resets tracking state if a new video is cued or the player is reset.

checkVideoState():
Called every second while the video is playing.

  • It calculates the current viewedPercentage.
  • It iterates through your defined breakpoints. If the viewedPercentage has passed a new breakpoint (and that breakpoint hasn’t been reported yet, managed by passedBreakpoint), it sends a watched-{videoEventName}-{percentage}% event to Usermaven.

Example usermaven events

Assuming videoEventName is "product-tour":

  • User clicks play:
    usermaven("track", "clicked-product-tour")
  • User watches 25% of the video:
    usermaven("track", "watched-product-tour-25%")
  • User watches 50% of the video:
    usermaven("track", "watched-product-tour-50%")
  • User watches 75% of the video:
    usermaven("track", "watched-product-tour-75%")
  • User watches the entire video:
    usermaven("track", "watched-product-tour-100%")

Important considerations

Single Page Applications (SPAs):
If your site is an SPA and you dynamically load/unload YouTube players without a full page refresh, ensure this script is re-initialized or that player instances are correctly managed (destroyed and recreated) to avoid issues with stale player objects or event listeners. The UNSTARTED / CUED state handling helps here.

Multiple videos on one page:
If you have multiple YouTube players on a single page, you’ll need to adapt this script. Each player would need its own YT.Player instance, and you’d likely need to manage state variables (like passedBreakpoint, videoInterval) distinctly for each player, perhaps by associating them with the player’s ID or an object.

Error handling:
For production, you might want to add more robust error handling (e.g., try...catch blocks) around API calls.

Last updated on