While Google Analytics 4 offers built-in 'Enhanced Measurement' for videos, it only natively tracks embedded YouTube videos. For self-hosted HTML5 videos (<video> tags) or other custom players, your data will be blank unless you have a custom setup like the one detailed below.
Google Analytics 4 does not track HTML5 video interactions by default. To capture events such as video_start, video_progress, and video_complete, you need to add JavaScript and configure Google Tag Manager. This guide outlines the steps required to granularly track custom HTML5 video elements, provided you can deploy a Google Tag Manager container.
Tracking video interactions helps you assess the performance of your video content.
This approach can answer questions such as:
What’s the percentage of all videos that are watched till the end?

The answer: 15 / 43 * 100 = 35%
What’s that number for easy specific video
Note: to run this test I created two test videos and named them Bunny Rabbit and The Earth, and asked good folks at Slicedbread to play one of the two videos.

-
Bunny Rabbit: 5 / 26 * 100 = 19%
-
The Earth: 10 / 17 * 100 = 59%
Clearly, The Earth video is the one that was watched till the end more often. It is because it is the shortest of the two.
What’s the most watched video of the two?

The answer: Bunny Rabbit
How many users watched different portions of the video?
You can use this information to assess the effectiveness of your video content, such as whether the video's length or content is engaging enough to retain viewers' attention.
Which traffic channels generate the most videos?

If you treat a video playback as a micro goal on the way to a purchase, then knowing which traffic channel drives the largest number of video_start events could serve as an indicator of traffic source quality. According to the above chart, the Referral traffic did pretty well and might deserve an advertising budget increase.
The insights above represent only the surface of what is possible with HTML5 video tracking in GA4. If you are ready to enhance your video performance analysis, here is how to begin the implementation.
How do I know that my video is an HTML5 video?
Your video is an HTML5 video if it uses <video></video> tags, such as those shown in the below HTML snippet:
<div class="video_container">
<video id="myVideo" width="320" height="240" controls>
<source src="./assets/video.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
If that’s what you have on your page, then this guide can be of help. You can learn more about the HTML5 video at this w3schools.com guide.
What are CSS selectors?
To use the JavaScript code provided below, you will need to be able to update it with a CSS selector. For example, the correct CSS selector for the video element of the above HTML code is #myVideo. To learn more about CSS selectors, check out this guide:
https://www.w3schools.com/css/css_selectors.asp
Alternatively, make sure that your video tag is updated with an ID attribute, like so:
<video id="myVideo"></video>
Should I use the Autoplay attribute?
The HTML5 video can be added an autoplay attribute, which will make the video play automatically, as soon as a user comes to the page and the video is ready to play. This is accomplished by adding an autoplay attribute, like so:
<video autoplay id="myVideo"></video>
Sites that automatically play a video with an audio track can be an unpleasant experience for users, so it should be avoided when possible. As such, if you have that attribute, it is best to remove it.
How do I add a JavaScript file to my site?
Almost every HTML page consists of the following elements:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
...
More code goes here
...
<script src="/track-videos.js"></script>
</body>
</html>
If you were to save the JavaScipt code listed below in a file track-videos.js located at the root level, you would need to link to it by placing a <script> tag immediately before the closing </body> tag, as shown above.
If the above still does not make sense, consider reaching out to someone who knows a bit more about front-end web development.
The actual JavaScript code
The following code will work as is if your <video> tag has an ID attribute of myVideo, like so:
<video id="myVideo"></video>
If you cannot make sure the video tag has that specific ID attribute value, you will need to find and replace each instance of #myVideo with whatever ID attribute value your video has. For example, if your ID attribute is:
<video id="something_else"></video>
You will need to find and replace every instance of #myVideo with #something_else. There are only two places in the below code where that replacement needs to be made. Hopefully, that makes sense. Also, notice that closer to the end of the code there is a line of code that reads My Tracked Video. You can replace that value with something more specific to what your video is about. Just make sure it is below 100 characters, as that’s the maximum parameter value length in Google Analytics 4.
For example, if the video you want to track is about a bunny rabbit, just use those two words in place of the My Tracked Video. With all bases covered, here comes the JavaScript code you will need to customize slightly (as described above) and save in a file such as track-videos.js:
(function(){
'use strict';
class HTML5Video {
constructor(videoElemSelector, videoTitle){
this.videoElem = document.querySelector(videoElemSelector);
this.videoTitle = videoTitle;
this.secondsPlayed = 0;
this.percentagePlayed = 0;
}
initialize(){
this.videoLengthInSeconds = Math.round(this.videoElem.duration);
//enable progress tracking only where it makes sense: where video is long enough
if (this.videoLengthInSeconds > 119){
this.trackVideoProgressEvent = true;
this.reportProgressAt = [10, 25, 50, 75];
this.alreadyReported = [];
}
this.videoElem.addEventListener('play', () => {
//'play' event is fired both when video is played and resumed
//we want it to fire only once when the 'play' event fired the first time
if (!this.videoPlayed){
this.updateDataLayer('video_start');
this.videoPlayed = true;
}
});
this.videoElem.addEventListener('timeupdate', (e) => {
//tracks video progress event for videos 2 mins and over
if (this.trackVideoProgressEvent){
this.trackPlaybackProgress(e);
}
});
this.videoElem.addEventListener('ended', () => {
this.updateDataLayer('video_complete');
//if video playback is started from scratch, make ...
//...'video_start' event possible again
delete this.videoPlayed;
if (this.trackPlaybackProgress){
this.alreadyReported = [];
}
});
}
trackPlaybackProgress(e){
this.secondsPlayed = Math.round(e.target.currentTime);
//calculate percentage progress every new seconds
this.percentagePlayed = Math.round((this.secondsPlayed / this.videoLengthInSeconds) * 100);
//ensure we report on each threshold only once for each percent listed in this.reportProgressAt
if (this.reportProgressAt.includes(this.percentagePlayed) && !this.alreadyReported.includes(this.percentagePlayed)){
//notify analytics
this.alreadyReported.push(this.percentagePlayed);
this.updateDataLayer('video_progress');
}
}
updateDataLayer(event_type){
//grab dataLayer array, or initialize one
window.dataLayer = window.dataLayer || [];
const dataLayerObject = {
'event': event_type,
'video_title': this.videoTitle
};
if (event_type === 'video_progress'){
dataLayerObject.video_percent = this.percentagePlayed;
}
dataLayer.push(dataLayerObject);
}
}
document.addEventListener('DOMContentLoaded', () => {
//ensure instance is created only on pages where video with provided selector is found
const myVideo = document.querySelector('#myVideo');
if (myVideo && myVideo.nodeName === 'VIDEO'){
const clip = new HTML5Video('#myVideo', 'My Tracked Video');
clip.videoElem.addEventListener('loadedmetadata', () => {
clip.initialize();
});
}
});
})();
The code pushes event data along with parameters to the dataLayer, which will be used by Google Tag Manager to log events in Google Analytics 4.
Videos that are shorter than two minutes in length (119 seconds and below) will fire only video_start and video_complete events. Videos two minutes and longer (120 seconds and above) will additionally send a video_progress event, along with the video_percent parameter. The video_progress will fire at 10, 25, 50, and 75 percent. That being said, you could easily customize it to other thresholds by adding this bit of code [10, 25, 50, 75]. If you wanted to track the playback progress at 20 and 40 percent intervals, you could replace the value in square brackets with [20, 40].
How to make sure the code works:
Hopefully, you know your way around in Google Tag Manager. If you don’t, check out this guide.
Copy the URL of your site containing the HTML5 video you want to track and paste it into the Preview video. For example, my test HTML5 videos were added to Slicedbread’s homepage at https://www.slicedbread.agency/ (chances are, the videos are no longer there if you decide to find them). That’s the URL I will preview in Google Tag Manager:


With the URL containing HTML5 videos pasted, hit the Connect button and play the test video. With the video still playing, head back to Google Tag Manager. The left sidebar section (event timeline) will get populated with multiple Video Engagement events, as shown below:

If you don’t see that, chances are you did not add the correct CSS selector.
Set up the GTM variables, triggers, and tags
The above JavaScript code merely updates the dataLayer object of a page. The actual video interaction events are not yet logged in Google Analytics 4. To make that happen, we will need to create the following.
GTM Variables
We need to create two data layer variables:


GTM Triggers
We will also need three GTM triggers:


GTM Tags
Last but not least, we will need three GTM tags:



With all those GTM variables, triggers, and tags in place and published, open the same page with videos in the Preview again, and let the video play. You might want to switch to see GA4 tas specifically by selecting the G- tag:

Longer pages will track these events:
-
video_start
-
video_progress (10%)
-
video_progress (25%)
-
video_progress (50%)
-
video_progress (75%)
-
video_complete
Here is what I see in the GTM having played a longer (two minutes plus) video:

All six events fired as expected.
Videos shorter than 2 minutes will have just two events:
-
video_start
-
video_finish
It does not really make sense to track the intermediary points for pretty short videos:

Understanding Video Engagement and Enhanced Measurement
Since its release, Google Analytics 4 has introduced "Enhanced Measurement," which natively supports video engagement tracking for many platforms. This feature significantly simplifies the process by automatically collecting data for embedded videos that support the YouTube JavaScript API. When Enhanced Measurement is enabled, GA4 automatically tracks events such as video_start, video_progress, and video_complete without requiring additional custom dimensions or code.

With that event, I would send two parameters for the author name and blog post category:
With those two parameters registered as custom dimensions, we could easily learn about the most-read blog author at Slicedbread:

For custom implementations like the one described in this article, you generally only need to register custom dimensions if you are using non-standard parameters. Because video_start, video_progress, and video_complete are now recognized as standard events within the GA4 schema, parameters like video_title and video_percent should theoretically be available in your reports automatically.
However, depending on your specific property configuration or the complexity of your custom HTML5 setup, you may still find that certain dimensions do not appear by default. For instance, while video_title is often captured, the video_percent dimension may occasionally require manual registration as a custom dimension to ensure it is available for Exploration reports.

Google Analytics 4 does not include a default dimension for Video Percent, so I registered it as a custom dimension.
Tracking HTML5 video events in Google Analytics 4 offers valuable insights into user engagement with your video content. By using the provided code examples, you can monitor video views, play rate, and video progress, and then use this data to optimize engagement and the user experience. Testing your tracking setup also ensures the data collected is accurate and actionable.
Remember that tracking video events is just one piece of the puzzle when it comes to measuring the effectiveness of your video content. By combining video tracking data with other metrics such as bounce rate, time on site, and conversion rate, you can gain a more comprehensive understanding of how your video content is performing and make data-driven decisions to improve it.
We hope this article has helped you get started with tracking HTML5 video events in Google Analytics 4. For further information on Google Analytics and digital marketing data tracking, please consult the Google Analytics documentation and other online resources.