YouTube Tracking In Google Analytics & Google Tag Manager

By /

May 11, 2015


UPDATE: Now includes percentage viewed tracking.

My colleague Sayf Sharif has long been an advocate of tracking YouTube videos with Google Analytics. Our LunaMetrics YouTube tracking script has been copied, cloned, forked, and borrowed more than a few times. It’s time to bring our script up to date with the latest changes in Google Analytics and Google Tag Manager.

Also, Google recently finished the process of deprecating version two of their data API, which our script has depended on for fetching video titles. If you are using an old version of the script, you’ll see all of your videos titles set to as of a few days ago.

After a little tinkering, we’ve updated the GitHub repo with version 7 of the illustrious LunaMetrics YouTube Google Analytics tracking code. Let’s take a look at what’s inside.

What’s New

This latest version is a plug-and-play tracking solution for tracking user interaction with YouTube videos in Google Analytics. It will detect if Google Tag Manager, Google Analytics (Universal), or Google Analytics (Classic) is installed on the page, in that order, and fire events when users interact with the video.

It includes support for delivering hits directly to Universal or Classic Google Analytics, or for pushing Data Layer events to be used by Google Tag Manager. It also supports percentage viewed tracking. You can find the code on our GitHub repo.


This plugin will play nicely with any other existing plugin that interfaces with the YouTube Iframe API, so long as it is loaded after any existing code. Otherwise, if another function overwrites the window.onYouTubeIframeAPIReady property, it will fail silently.

Universal or Classic Google Analytics Installation:

The plugin is designed to be plug-and-play. By default, the plugin will try and detect if you have Google Tag Manager, Universal Analytics, or Classic Google Analytics, and use the appropriate syntax for the event. If you are not using Google Tag Manager to fire your Google Analytics code, store the plugin on your server and include the lunametrics-youtube-v7.gtm.js script file somewhere on the page. You can host the script on your own server, or you can make use of the freely hosted jsdelivr copy.

Google Tag Manager Installation

Create a new Custom HTML tag and paste in the below:

In the space between the <script> and </script> tags, paste in the contents of the lunametrics-youtube.gtm.js script, found here. You can set the Trigger to All Pages, or you can use a Custom JS Variable to detect if a YouTube video is present and use that instead, like so:


Once everything installed on your own site, this script will fire a Google Analytics event with the following settings:

  1. Event Category: Videos
  2. Event Action: (Action, e.g. Play, Pause)
  3. Event Label: (URL of the video)

Configuring Which Events Fire

If you are not using Google Tag Manager to fire your Google Analytics code, you might want to configure the script to fire or not fire certain events. By default, it will fire:

  • Play events
  • Pause events
  • Watch to End events
  • 10, 25, 50, 75, & 90% View Completion events

To change which events are fired, edit the configuration at the end of the script. For example, if you’d like to fire Play events and not fire Pause events:

The available events are Play, Pause, and Watch To End. These are all enabled by default, which you can see and modify at the bottom of the script file.

Forcing Universal or Classic Analytics

By default, the plugin will try and fire Data Layer events, then fallback to Universal Analytics events, then fallback to Classic Analytics events. If you want to force the script to use a particular syntax for your events, you can set the ‘forceSyntax’ property of the configuration object to an integer:

Setting this value to one of the following numbers:

  • 0 will force the script to use Google Tag Manager events
  • 1 will force it to use Universal Google Analytics events
  • 2 will force it to use Classic Google Analytics events

NEW – Enabling Percentage Viewed Tracking

By default, percentage viewed tracking is enabled. Configure it by adjusting the percentageTracking object’s properties at the end of the script. The object has two properties: each and every. The each property accepts and array of numbers, and will fire an event once that percentage is reached. The every property accepts an integer, and will fire every n%.

NOTE: Google Analytics has a 500 hit per-session limitation, as well as a 20 hit window that replenishes at 2 hits per second. For that reason, it is HIGHLY INADVISABLE to track every 1% of video viewed.

Google Tag Manager Configuration

Once you’ve added the script to your container (see Google Tag Manager Installation), Data Layer events will occur for all of the following:

  • Play
  • Pause
  • Watch to End

Create the following Variables:

  • Variable Name: videoUrl
    • Variable Type: Data Layer Variable
    • Data Layer Variable Name: attributes.videoUrl
    • This is the URL of the video on YouTube
  • Variable Name: videoAction
    • Variable Type: Data Layer Variable
    • Data Layer Variable Name: attributes.videoAction
    • This will be the action the user has taken, e.g. Play, Pause, or Watch to End


Create the following Trigger:

  • Trigger Name: YouTube Video Event
    • Trigger Type: Custom Event
    • Event Name: youTubeTrack


Create your Google Analytics Event tag

  • Tag Type: Google Analytics
    • Choose a Tag Type: Universal Analytics (or Classic Analytics, if you are still using that)
    • Tracking ID: <Enter in your Google Analytics tracking ID>
    • Track Type: Event
    • Category: Videos
    • Action: {{videoAction}}
    • Label: {{videoUrl}}
    • Fire On: More
      • Choose from existing Triggers: YouTube Video Event


Getting Video Titles

Because of the deprecated YouTube API, this script no longer provides the titles of the videos. We chose to go with the most consistent method, which means that instead of the human-readable titles you would have gotten as your Event Label before, you’ll now see the URL of the video itself, e.g.

Once you have the video URL, you can use something like Excel or Google Spreadsheets to help convert those into readable titles. Another option would be to use a Google Tag Manager Lookup Table to translate the URLs into titles before sending the information to Google Analytics. We have a spreadsheet to help convert URLs to Titles, as well as blog about quickly creating lookup tables.

Coming Soon

We have added percentage completion tracking to the script, and are looking for suggestions on how we could improve the script with further functionality. Let us know on the GitHub repo or in the comments below.

Dan Wilkerson is an Analytics Engineer at LunaMetrics. He is passionate about web technology, measurement, and analysis. Dan is the winner of the 1999 Forge Road Elementary School Science Fair for his groundbreaking report on how magnets work. (ICP, take note.) Dan has worked at LunaMetrics in social media, as our marketing manager, and now in our analytics department.

  • Frédéric Gaye

    Hi Dan,
    Very nice solution but it seem have a “little” bug with GTM. We have a “flash” on youtube video (when page loading video disappears briefly then reappears). Except this point all is fine.
    PS : Yes, add percentage completion tracking will be a nice idea.

    • Dan Wilkerson

      Hi Frédéric,

      This is expected behavior – if your video embed doesn’t have the proper parameters (?enablejsapi=1& or is an older style object, the tracking won’t work. The script detects these issues and reloads the video. If you don’t want that to happen, you can add those parameters to the src attribute of the video you’ve embedded.


    • Dan Wilkerson

      Hey Frédéric,

      Just wanted to let you know that we’ve added percentage tracking to the script. Check it out in the repo and leave me some feedback.


  • Katya De Palma

    HI Dan, thanks for ur guidelines. Just a info: you suppose to do it with Version 2, but I can manage the same with the version 1 of gtm?
    I mean I fixed all the event /tag /macro in V1 but doesn’t work.
    many thanks for ur help.

    • Dan Wilkerson

      Hi Katya,

      Sure can, but they’re migrating everyone to v2 on June 1st.


  • Sarah Peduzzi

    What voodoo magic is this? Much learning. So excite.

    • Dan Wilkerson

    • Dan Wilkerson

      Aw yiss.

  • Amanda Dominy

    I don’t seem to be able to get this to work at all. I have a WordPress site, with a Bootstrap theme that already uses JQuery. I have enqueued the script lunametrics-youtube-v7.gtm.js in the header, after jquery. I’m using Universal Analytics, and I’m happy with the events you have by default, so I have not configured anything else. I’m using the standard iframe embed code (eg: ). Here is a link with an example video on our site:

    I don’t know what else is going wrong?

    (PS: I added a space to the iframe code because I couldn’t figure out how to [pre] code here…

    • Dan Wilkerson

      Hi Amanda,

      The newest version removes the jQuery dependency.

      When I look at the video on the page, it’s being served via, not a standard YouTube Iframe. Are you using a plugin of some kind to deliver this video? That’s why it’s not working, as far as I can tell.


      • Amanda Dominy

        Hi there, yes, I installed a plugin from in the mean time to track the views. I will disable it now for a couple of days – would you mind taking another look?

        • Dan Wilkerson

          Hi Amanda,

          You’ve got another file loaded in after the YouTube tracking script that is overwriting the window.onYouTubeIframeAPIReady endpoint with it’s own function. This happens before the Iframe API is loaded in and can call the LunaMetrics script, so you don’t see an error or anything it’s simply lost. If you want to have both scripts, you’ll need to add logic to them both to detect if there is already a function registered at that endpoint and to concatenate their execution, Check this file for more.


          • Amanda Dominy

            Ah! Thanks so much – I’ll see if I can do without the slideshow plugin, or better yet, do it natively in Bootstrap.

          • Amanda Dominy

            Ok, I’ve removed that plugin (replacing my slideshow with a native bootstrap carousel). I can see now that the enablejsapi bit is properly added to my videos, and it’s being served from youtube, but I’m still not seeing any events triggering in my analytics account (looking at the Real Time events, last 30 min). Could it be a caching problem? Thanks so much for the help and feedback, in advance.

          • Dan Wilkerson

            Hi Amanda,

            Sorry, missed this comment. It looks like your Yoast Google Analytics plugin is renaming the default Universal Analytics function to __gaTracker. This is something I can fix in the code, but for now, you’ll just want to find and replace:


            And that should fix it.


          • Amanda Dominy

            Aha! Success! Thank you so much!!

  • Tiaan Van Zyl

    Hi Dan,

    I have a noob question – should the custom HTML tag fire on all page of the website?

    Oh yes, this is pretty cool!


    • Dan Wilkerson

      Hey Tiaan,

      It can, but you’re adding extra code execution that you don’t really need. You might instead create a custom JS variable that checks for any YouTube videos on the page and returns ‘true’ if it sees one, then use that as a firing Trigger.


      • Tiaan Van Zyl

        Hey Dan,

        Thanks for the feedback. I actually did a quick search within Google and found the following javascript code to detect if there is a youtube video present. I will create a trigger when this code snippet fires, then the trigger should fire on any pageview (type) of the custom html tag? –

        function () {

        for (var e = document.getElementsByTagName(‘iframe’), x = e.length; x–;)

        if (/[x].src)) return true;

        return false;



      • PeaceInEurope

        Hi Dan Wilkerson,

        I don’t how to create it. I went to “Variables”. Then i went to user-defined variables. Then i clicked on “New”. Then i chose the type “custom JavaScript”
        What do i type in to find any YouTube Video on my website?

        • Dan Wilkerson

          You could use Tiaan’s code from above, but if you want to a little more thorough, you could use this:

  • Zorin Radovancevic

    Hi Dan,

    tested the script and it works nicely – thanks!

    One question though with UA simple implementation GA debug reported ‘Unrecognized Positional Argument: false’. I have changed your js and instead of false used {nonInteraction: 1|0} and no more warnings were present.

    Kind regards,

    • Dan Wilkerson

      Hi Zorin,

      Good catch! Pushed a fix to the repo. Much appreciated.


  • Lucas

    Hi Dan, great video! It was exactly what I needed to start tracking videos on the company site. I was researching on Google Tag Manager and it stated that we can also add the GA tracking code to our Tag Manager container. In this case, can I remove the older GA script?

    • Dan Wilkerson

      Hi Lucas, I’d suggest doing some additional research on migrating to GTM. It’s often not as simple as just removing the old code; we recommend running a test property in parallel with identical configuration to your on page code for awhile, then switching the UA numbers when you’re good to go.

      • Lucas

        Got it. thanks!

  • Christian Orellana

    Thank you very much! This was easy to set up and works nicely, specially with embedded playlists. It would be great to add % completion tracking!

    • Dan Wilkerson

      Hi Christian, we just added this feature a few days ago. Take a look in the repo and send me some feedback!

      • Christian Orellana

        Hey Dan, thanks so much for the heads-up! I just tested the new version and seems to work great. Easy to set up on Google Tag Manager, too. The only thing that I expected but did not work out of the box, was that it would also track % viewed for videos played after the first video, like in related videos. This is important to me because I like to see what *other* videos my users are watching on my page, so I can include those videos later too.

        Right now, I get % tracked for the first video. If the video ends and I click a new related video, I just get the Play and Watch to End events pushed to the DataLayer, but no % played. Is this expected?


        • Dan Wilkerson

          Hi Christian,

          Good catch. I can make a fix; I’d appreciate if you could open an issue in the repo, if you’ve got a minute. I’ll post here when I get it fixed – probably in the next two weeks.


          • Christian Orellana

            Done! Thank you very much!

          • Dan Wilkerson

            @borghal:disqus This should be fixed with our latest version

          • Christian Orellana

            Looks like it’s working. Thank you, @disqus_ZlOkX51Bk6:disqus!

  • Bellatrice

    Hello Dan!
    Thank you for this script
    Unfortunately I can’t use it because of following error shown in ga debugger. Can you advice me anything for getting rid of it? Many thanks of advance.

    Failed to execute ‘postMessage’ on ‘DOMWindow':
    The target origin provided (‘’) does not match
    the recipient window’s origin (‘’).

    • Dan Wilkerson

      Hi Bellatrice,

      The script tries to set the origin parameter based on the hostname of the document that contains it, but only if the video already does not have an origin set. Can you share a link with me so I can take a look?


      • Bellatrice

        We are trying to run the script in our test environment, beafore adding it to the working webpage available for external users. I would be really glad to show it, but there is no way I can:(

      • Bellatrice

        I’ve attached some screenshots, mb they and following information can help:

        1. There are no other scripts that fire Youtube API at the page

        2. Youtube iframes don’t have origin of jsapi parameter set

        3. The name of script was changed to video.js but we havent changed anything inside

        4. More information about the error from the code line

        f.J=function(a){;var b=[];Ba(new Aa,a,b);a=b.join(“”);var b=this.f,c,d=Ha(this.c.src);c=d[1];var e=d[2],g=d[3],d=d[4],k=””;c&&(k+=c+”:”);g&&(k+=”//”,e&&(k+=e+”@”),k+=g,d&&(k+=”:”+d));c=k;b=0==c.indexOf(“https:”)?[c]:b.c?[c.replace(“http:”,”https:”)]:b.h?[c]:[c,c.replace(“http:”,”https:”)];for(c=0;c=a.length)throw T;if(b in a)return a[b++];b++}};return c}throw Error(“Not implemented”);}

        Thank you!

  • Alex Hadimulya

    I want to do the same tracking for youtube videos that are loaded via fancybox. For example, click on a link and the video opens up. What modifications do i need to make to take into account the delayed trigger for the fancybox?

    • Dan Wilkerson

      Hi Alex,

      You can try firing the script when the user clicks on something that opens the Fancybox.


  • Craig Hodgkins

    I thought we had everything good but we keep getting the following error:

    Uncaught TypeError: player.getVideoUrl is not a functiononStateChangeHandler @ (index) @ (index):421f.P @ www-widgetapi.js:13f.A @ www-widgetapi.js:23f.R @ www-widgetapi.js:31W.l @ www-widgetapi.js:30g @ www-widgetapi.js:19

    • Dan Wilkerson

      Hi Craig,

      It’s difficult to say why you’re seeing this without a firsthand look; can you share a link I can take a look at?


  • Kimberly

    I can’t seem to get the GTM Github link to the js script code to work, the link is:

    And shows “not found” when I click. Hoping to get that script so I can set up YouTube tracking on my site!

  • Neil Odiaz

    Hi, Unfortunately, I can’t get this to work. Here is my sample page: Anyone can help me on this? Thanks in advance.

    • Dan Wilkerson

      Hey Neil,

      There was a two-day window where there was a bug which would stop the script from pushing to the dataLayer. We pushed a fix, so if you try the latest version you should be good:


      • Neil Odiaz

        Already updated the js file but still doesn’t work. I followed your steps above but no luck.

        • Dan Wilkerson

          Hi Neil,

          I took another look and it appears like that fixed it (see attached).

          Have you configured a Google Analytics Event tag in your GTM account to fire on the youTubeTrack event?


  • Tom

    Hello Dan,

    Sorry if this is a stupid question. But where can I see all the results in Google Analytics? (how many people paused the video, etc.) I can only find the real time data. But is there a page where you can see the history of the results? Or do I have to take another step in Google Analytics?

    Thanks in advance,


    • Dan Wilkerson

      Hi Tom,

      If you see events firing in the Real Time reports, you can view the data in the Behavior -> Events -> Top Events report. There you’ll see the Event Category ‘Video’, which you can click on to drill into more detailed data.


  • Varis

    For some reason, functions for fetching player data didnt work, for example, player.getVideoUrl(); returned a javascript error of undefined function in Chrome. I had to replace it with “player.B.videoUrl”

    • Dan Wilkerson

      Hello Varis,

      If you fire this script twice or in conjunction with another tracking script, that issue will occur. Your current fix is brittle; ‘B’ is the annotated minified reference for an internal method in the YouTube Iframe API, and will change if they add, remove, or adjust the variables in the script before minification.

      If you do come up with a full solution, please pull it to the Repo!


  • Abiodun

    Hello Dan,

    Great post!

    Under “Configuring Which Events Fire” Seems you missed on what Trigger the YouTube tag to fire if using GTM. See attached image.

    • Dan Wilkerson

      Hi Abiodun,

      Good idea, I’ll add a note about that. Typically you can fire it on every page, or you can add a Variable that detects if a YouTube video is present and then fires it.


  • Marcos Alonso

    Hi Dan,

    You´ve done a really nice job here. Congrats!

    I tried to implement it on my website, but my Event Action or Label are comming as Undefined, although I configured the variables videoAction and videoUrl as shown in your post. Do you have any idea on what am i doing wrong?

    • Marcos Alonso

      After a little analysis, I found that the event “undifined” of the category “videos” where sent in some pages without any video.
      So i created another Google Analytics Tag which is configured to be fired in All Pages. But now I don´t have any event.

      The age with the video is:

      below you can find some prints n(they´re in portugueese, but i think you can understand them 😉

  • FacelessMan

    For others that are going to use this script, make sure that if you are using a URL that doesn’t read exactly “” or “” that you add in the following potentialYouTubeVideoSrc.indexOf( ‘’ ) > -1 || with the other two if constraints in the function checkifyoutubevideo.

    All in all a pretty sweet little plugin.

    • Dan Wilkerson

      Could you share an example of a specific domain this might apply to? I’m happy to add some logic for common non-traditional syntaxes, or a configuration option. I’m also happy to look at anything you’d like to pull in to the repo.


  • Caleb

    Do you think it would be possible to track multiple YouTube videos that exist on the same page?

    • Dan Wilkerson

      Hi Caleb,

      By default, this script will track multiple videos on the page.


      • Caleb

        Thanks for the quick reply. I appreciate it!

Contact Us.


24 S. 18th Street, Suite 100,
Pittsburgh, PA 15203

Follow Us



We'll get back to you
in ONE business day.