The Blog

Youtube video tracking with GTM and UA: a step by step guide

Youtube tracking with GTM and UA

During our GTM+UA webinar I was asked about tracking YouTube videos with the help of Google Tag Manager and Universal Analytics. I quickly demonstrated how we’re doing it in our WASP playground.

Here’s a step by step guide to the macros, tags and rules required to track YouTube video embeds on your website.

A note for Google Analytics users: For sake of demonstration I’m showing Universal Analytics, but you could easily replace the Universal Analytics Event by a regular Google Analytics one and everything will work fine.


We will use the YouTube JavaScript API to expose user interactions with the video. In order for this to work, each of your YouTube embeds will need to include “enablejsapi=1” to the link of the video, for example:

<iframe width="420" height="315" src="//" frameborder="0" allowfullscreen></iframe>

Note: the “Is Youtube present” macro could be modified to automatically add the enablejsapi if it’s not there, but this will result in a quick flash of the Youtube frame.

What you’ll get

Under Behavior/Events/Top Events, you will see an event category named “video”, with event actions named “pause”, “play”, 0%, 25%, 50%, 75% and 100%. The event label will be the unique identifier of the video.

Custom Report for Video Performance

If you want to get details about how individual videos are performing, follow those steps:

  1. Go in yout Behavior/Events/Top Events/video report;
  2. Click on “Customize” in the top left of the report;
  3. Under Dimension Drilldown, remove the “Event Category” dimension and switch “Event Action” with “Event Label”, so it now reads Event Label/Event Action;
  4. Modify the filter so it now reads “Event Category equals video”, so only videos are shown in this new custom report;
  5. Voilà! You now have detailed performance info about each individual video embedded on your website.

Dimension Widening: Video Names

The Youtube JS API doesn’t provide any means of retrieving a friendly video title. Only the unique id is available (as in // To work around this, you could use use Universal Analytics Data Import to upload a table containing video id, video title. To do this, you will need to modify the code provided bellow and use two new custom dimensions and make a few other tweaks – since this is more advanced and would make the article too complex, please contact us if you need help in setting it up.


Is Youtube present?

You have two options here, either use this macro to automatically detect when a video is embedded on a page, or use a rule to include the Youtube Listener tag only on pages where you know there’s a video.

Macro Name: Youtube is present
Macro Type: Custom JavaScript
Custom JavaScript:
// Return "true" if there is at least one Youtube video on the page
function () {
    for (var e = document.getElementsByTagName('iframe'), x = e.length; x--;)
        if (/\/embed/.test(e[x].src)) return true;
    return false;


Macro Name: event
Macro Type: Custom Event

dataLayer action

Macro Name: dataLayer action
Macro Type: Data Layer Variable
Data Layer Variable Name: action

dataLayer label

Macro Name: dataLayer label
Macro Type: Data Layer Variable
Data Layer Variable Name: label


Listen for Youtube activity

Tag Name: Youtube Listener
Tag Type: Custom HTML Tag
Firing Rule: Youtube present
<script type="text/javascript">
// attach our YT listener once the API is loaded
function onYouTubeIframeAPIReady() {
    for (var e = document.getElementsByTagName("iframe"), x = e.length; x--;) {
        if (/\/embed/.test(e[x].src)) {
            new YT.Player(e[x], {
                events: {
                    onStateChange: onPlayerStateChange,
                    onError: onPlayerError
            YT.gtmLastAction = "p";

// listen for play/pause, other states such as rewind and end could also be added
// also report % played every second
function onPlayerStateChange(e) {
    e["data"] == YT.PlayerState.PLAYING && setTimeout(onPlayerPercent, 1000, e["target"]);
    if (e["data"] == YT.PlayerState.PLAYING && YT.gtmLastAction == "p") {
            event: "youtube",
            action: "play",
        YT.gtmLastAction = "";
    if (e["data"] == YT.PlayerState.PAUSED) {
            event: "youtube",
            action: "pause",
        YT.gtmLastAction = "p";

// catch all to report errors through the GTM data layer
// once the error is exposed to GTM, it can be tracked in UA as an event!
function onPlayerError(e) {
        event: "error",
        action: "GTM",
        label: "youtube:" + e["target"]["src"] + "-" + e["data"]

// report the % played if it matches 0%, 25%, 50%, 75% or completed
function onPlayerPercent(e) {
    if (e["getPlayerState"]() == YT.PlayerState.PLAYING) {
        var t = e["getDuration"]() - e["getCurrentTime"]() <= 1.5 ? 1 : (Math.floor(e["getCurrentTime"]() / e["getDuration"]() * 4) / 4).toFixed(2);         if (!e["lastP"] || t > e["lastP"]) {
            e["lastP"] = t;
                event: "youtube",
                action: t * 100 + "%",
                label: e["getVideoUrl"]().match(/v=([^&]+)/)[1]
        e["lastP"] != 1 && setTimeout(onPlayerPercent, 1000, e);

// load the Youtube JS api and get going
var j = document.createElement("script"),
    f = document.getElementsByTagName("script")[0];
j.src = "//";
j.async = true;
f.parentNode.insertBefore(j, f);

UA Youtube event

If you are using Google Analytics instead of Universal Analytics, simply change the Tag Type to Google Analytics and everything will work fine.

Tag Name: Youtube Event
Tag Type: Universal Analytics
Tracking ID: UA-XXXXXX-Y
Track Type: Event
Event Tracking Parameters:
Category: {{event}}
Action: {{dataLayer action}}
Label: {{dataLayer label}}
Firing rule: Youtube event


Youtube embed found on a page

Rule Name: Youtube present
Conditions: {{event}} equals gtm.dom AND {{youtube is present}} equals true

Youtube is telling us something

Rule Name: Youtube event
Conditions: {{event}} equals youtube

Putting it all together

That’s it! Now you can track Youtube video embeds on your own website thanks to Google Tag Manager and Universal Analytics.

Don’t forget to use Google Tag Manager “debug & preview” with WASP to make sure everything works fine before you publish.

I will cover this topic and many more tricks in our upcoming hands-on workshop at eMetrics San-Francisco. Please check the Cardinal Path training calendar for more locations.

This entry was posted in Technology, Cardinal Path, Google Analytics, Web Analytics and tagged , , , . Bookmark the permalink.
  • kinaze

    This is great Stephane. Thanks for sharing. I like the use of {{event}} equals gtm.dom.

  • Sam Briesemeister

    Stephane, very nice approach you have here. On first glance it looks like your code (starting in onYouTubeIframeAPIReady) may be using some global variables (e and x) that could cause serious interference with other parts of a poorly-coded site. It looks like you may just need to declare them with “var” in that for(…) loop header. Thanks for sharing!

    • Stephane Hamel

      Excellent point Sam – and a general best practice!
      I have updated the article accordingly.

  • Elena

    Thank you for sharing. How would I set up this event in my Google Analytics account so I could see the results of tracking in the report?

    • Stephane Hamel

      You can look under Behavior/Events/Top Events and you will see an event category called “video”. If you drill-down in this entry, you will find play, pause, 0%, 25%, 50%, 75% and 100%. This will give you an appreciation of the number of videos that were looked at until the end. If you wanted to have details about a specific video, you could customize the default view and simply put the “event label” dimension before the “event action”. (I will updated the article with more info about this)

  • Harm te Molder

    Hi Stephane,

    Just implemented this and it works great. Had to fix the Custom HTML Tag though. You are missing three “)”s after the match-functions. Or was that a copy-paste error of mine?

    • Stephane Hamel

      You are right – looks like the copy/paste on my end scrambled just those – fixed now. Thanks!

  • menachem rosenbaum

    Thanks for this great post I need to go implement this like now!

  • AlexMorask

    Hey Stephane,

    This is awesome. Thank you for posting. I just have one quick question. Do you have any ideas as to why the event label (the video ID) wouldn’t be coming through in GA? I’ve gotten the event to fire and I see category and actions coming through, but the labels are not populating. I know this is somewhat vague, but I figured I’d ask to see if you’ve ran into this trouble before. Thank you!

    • Stephane Hamel

      @harmtemolder:disqus noticed a little glitch and that’s what might have been causing this problem. The post is updated now. Basically, where you see the label assigned through the getVideoUrl() call, make sure there’s a closing parenthesis before [1] (somehow got mangled when I pasted the code)

      • AlexMorask


        Made the change. Works perfectly now. Thanks so much for posting, this is really awesome.

  • Aziz Qaisar Shaikh

    Simple steps which solved my query, I was searching for the steps yesterday and today i got it. That awesome and wonderful for me

  • lfaber

    Nice stuff Stephan! I had been struggling with this for weeks. Now to get tracking working when videos play within a Lightbox (yes that’s a challenge). ;-)

  • lfaber

    Small typo in the “What You’ll Get” section. The event category should be “youtube” not “video”. ;-)

  • ryandigital

    Hi Stephane,

    Thank you so much for this post! It works on my end. Good thing that I found your article. It solved my problem! Thank you! But I still have one more to solve..

    How can I apply this to other media players like Vimeo? I do have an embedded Vimeo video in my site and I am not sure how your scripts can be converted to track the video plays.

  • Audrey

    Hi Stéphane,
    Thanks so much for this article, extremely helpful!

    Could you maybe elaborate on how we can modify the “Is YouTube present” macro to automatically add the enablejsapi if it’s not there?

  • Cameron

    love the post Stephane… how would I modify the tracking if I only wanted to capture plays? At present Google Analytics is creating a new event every time someone clicks on the video (even to pause or skip).

Cardinal Path Training

Copyright © 2014, All Rights Reserved. Privacy and Copyright Policies.