Easily Track YouTube Videos with Google Analytics

By /

October 22, 2012

May 2015: We’ve updated our YouTube tracking script to work with Google Tag Manager and Universal Analytics (and fixed a few other issues!) Click to see the latest blog post.



Note: This blog post was last updated on January 23rd, 2014 with version 6.

Recently I was tasked with tracking YouTube videos on a website using Events in Google Analytics, and I was not particularly thrilled with the options. Either old blog posts from even our site, or posts that didn’t lay out any specifics on how to do it, or posts that listed basically how the YouTube player API instructs people to track videos. Most from a year or even two ago. Which was all well and good, until I realized that I was dealing with possibly hundreds of pages, with a variable amount of videos on them.

The basic YouTube IFrame Player API shows an example of one video. And if you add a second? Well you need to add more javascript, as well as modify your HTML. If you had 10 videos on a page you would have to modify the javascript for the page to create 10 different objects, and you’d need to replace or edit the embed code to div tags. Not exactly easy, particularly for someone to go back to a site already in existence.

What I wanted was basically, maybe, a javascript file you could include on your page and then just BAM presto chango, all the basic embedded YouTube videos would be tracked, no muss no fuss, no additional JavaScript. Write a new blog post, add a new YouTube video, and have the tracking just automatically happen. I couldn’t find that.

So I wrote it.

See that video? I embedded it with standard Youtube embed code. Copy and Paste into the blog. No additional javascript. Go ahead and view the source. I’m tracking when it buffers, plays, cues, pauses, or if someone watches it to the end. All I did was copy and paste the embed code straight from YouTube on the page.

This one too. Copy. Paste. Tracked with Events in Google Analytics. Easy as pie. A monkey could do it. Well… a trained monkey.

And this one too…Don’t believe me? Use your favorite tool, and check out the source. Just iframes. Check out the Network and see the UTM gif’s flying with Event’s being Tracked for being Rick Rolled straight to our Google Analytics account.

It’s ok. You can go ahead and slow clap.



Here’s what you do. No complicated coding. Just download this file from our github, and include it in the head of your html. Just use one of them. We’ve updated this code a few times, so be sure to go here for the latest version.

You’ll also need Jquery so be sure to include that before the script. So you’ll have something like this

<script src=”//code.jquery.com/jquery-1.7.2.js”></script>

<script type=”text/javascript” src=”http://www.yourwebsitehere.com/js/lunametrics-youtube-v5.js”></script>

And then… That’s it.

UPDATE: NOPE... YouTube has updated their scripts so that you are now REQUIRED to have enablejsapi=1 attached to each video to be tracked. So you should probably manually add these.  You can also add this automatically with the reloadFrames variable included in the script, which you can change to be 1 instead of 0, but this will cause screen “flicker” but if you have 100s of pages and videos to update it could be a better short term fix. You can also instead manually add enablejsapi=1 to ever source of the videos as a parameter. END UPDATE.

The script will use jquery to scan through your page and look for iframes. Any iframe that has a standard youtube value in it’s source parameter like http://www.youtube.com/embed/ or https://www.youtube.com/embed/ will get acknowledged as a YouTube video. (if it has the -nocookie listing that is an option in Youtube we don’t track it, as it wouldn’t track anyway). Then we dynamically create the objects based on the YouTube ID’s based on their IFrame Player API and voila. All the iframes embedded on the page with the standard default YouTube embed code, as well as their https secure version, get tracked with Events in Google Analytics.



1) It requires jquery as noted above. If you don’t have jquery on the page as well as our youtube code, it won’t work.

2) It assumes that the video is embedded only once on the page. You can have 100 videos on the page and it’ll track them all, but if you embed the same video twice it’ll actually error out because I’m using the YouTube video ID as the id for the player itself, so it’ll just overwrite itself, and the second video with the same YouTube video ID won’t get tracked.

3) I mentioned it before, but if you choose the option for “enhanced privacy mode” which sets a no cookie field in the URL, we can’t track those.

4) We track Play, Pause, Cue, Buffer, and Watch till End, but you’re free to add additional stuff to our code for your own use.

5) We originally stripped the YouTube ID out from the URL and that’s what got placed into the Event for identification, not the full URL. The new code uses a separate api to grab the title of the video and has the event read “Title of the Video | ASdfj0oi2_34vh” etc where the garbage is the YouTube ID. This hopefully makes it easier to read. You can change this setting in a variable early in the code to display just the title, or just the id. It defaults to concatenated.

6) This works with the embed code YouTube provides. If you copy the URL and gum up the url in the iframe with all sorts of other parameters that aren’t standard, it probably won’t work either. It’ll work with URL’s like http://www.youtube.com/embed/e90s3v_G4PU?rel=0 or http://www.youtube.com/embed/e90s3v_G4PU or https://www.youtube.com/embed/e90s3v_G4PU?rel=0 or http://www.youtube.com/embed/e90s3v_G4PU which are the basic forms that YouTube provides as the SRC value in the iframe. It’ll also work without the http at all.

7) This does NOT work with the old object code embeds, only the iFrame embeds.

8) If you don’t have Google Analytics and the Tracking Code already on your site, this won’t work without it. It works WITH jquery and the GATC, but doesn’t include either.

9) We’re not currently tracking how long the video played. We had some errors with the API and wanted to make the value of the event the duration of watching the video on both the pause, and watched till end, but have left them off for now.

10) Sometimes there are problems and it doesn’t work for some people. We added some extra help, with a reloadFrames variable. It defaults to 0, but set it to 1, and it’ll rewrite the iframes with enablejsapi=1 and an origin of your current window.location.hostname, and then reload the iframes. If it’s not working on your site, try setting this to 1. It’ll cause the embeds to load twice, but they may track after that, if they didn’t before. For most people it should work without this setting.


Hopefully this makes some people’s lives easier. Tracking videos embedded on your site from YouTube is now a fire and forget solution. I know I was excited to get this to work, so I have to assume there are other people out there that will find this just as easy and useful.

Questions or comments? Post em below! If someone finds a problem with the code, let me know and you can help perfect it!

Sayf Sharif is a Senior Analytics Supervisor working with Google Analytics and specializing in Usability and Conversion. He has helped hundreds of businesses design, develop, and improve conversion on their websites since 1997. Things you didn’t know about Sayf: he’s biked from Pittsburgh to Cleveland in 32 hours, studied Archaeology in Graduate School focusing on human tool use, and feels the Oxford comma is more important than Jim apparently does.

  • Tyler

    That was the most entertaining script I’ve read…I guess ever.

  • Sayf Sharif

    I’ll admit I was commenting it on Saturday from my couch and taking way too much pleasure in doing so. Glad you enjoyed it.

  • Nick

    Due to various backend issue we chose to implement all our event tracking in a similar way; including recognising and categoriesing different groups of links on given pages. There are issues as you mention, but it’s worth considering as a viable option.

  • Sayf Sharif

    Absolutely Nick. Adding in abilities so recognize groups and categories is a great addition to this type of code.

    My main concern writing this was essentially thinking of a generic site with a generic blog, one where there were a myraid of videos embedded throughout the static pages, and then regular embedded videos posted on the blog, and how much a nightmare it would be to track them, particularly if the organization had a very tight IT funnel.

    with code like this you could essentially add it through Google Tag Manager, if you had that working, and then without even bothering your IT department be suddenly and effectively tracking all your standard YouTube video embeds, with no other effort.

  • Ignatius Hsu

    Sayf, nice code! This will save me so much time! I like the midieval-ish comments, too.

    The way that the code captures the youtube id possibly needs to be broader that an exact string ?rel=0. See the available YT parameters https://developers.google.com/youtube/player_parameters#relstring .

    What could be done is to use a regex in the js that pattern matches all characters after embed up until it finds a question mark. Something like: [^?]+ would do the trick.

    String matching is significantly more efficient than regex, but also more limited in use. So broadening from an exact strong match to a regex pattern would cause a small performance hit on the efficiency of your js. Something to consider to make this more awesome.

  • Sayf Sharif

    It’s interesting you bring up the Regex because that’s what I first did to match the strings to grab the ID. I agree what I have is definitely limiting, and I think probably needs to be expanded in that direction, but when i first did the regex I was a little concerned that I was leaving things off, or getting an incorrect result. I don’t recall what it was, but I decided to just go explicit for the moment. Definitely a 2.0 version of this code I think should use a decent pattern match to grab more id’s.

    I think I was worried about the order of the paramters in some cases? I think I need a bigger list of possible sources for the iframe with various parameters to make sure that we don’t lose anything.

    But I think you’re absolutely right, adding the regex is a definite next step to take this a notch up.

  • http://www.cardinalpath.com Eduardo Carvalho

    Thanks for sharing that Sayif.

    The code is quite entertaining. I have written the same thing in the past. You may want to take a look at mine, even though it’s not so well commented.


    I’m quite intrigued how you don’t need to use the enablejsapi=1 query parameter in the video url. The docs say it’s required. And in my previous tests it wouldn’t work otherwise. Maybe I need to re-run some tests as I have written this plugin quite a while back and had to rewrite some parts a couple months ago when the youtube api left beta status and did some breaking changes.

    It probably needs some cleanup anyway.

  • Sayf Sharif

    Eduardo, I originally didn’t add it and it worked. It looks like it throws a few security warnings in the Chrome console, but no errors, and it works, so I didn’t add it in.

    I was curious as well that it was working, but if I could get it to work in my browsers without forcing a user to do anything but copy and paste their iframe embed code into their blog, I decided to try and get away with it. I’d be curious to hear how your tests go and whether it works with your code now as well.

  • http://www.cardinalpath.com Eduardo Carvalho

    Just tried it out and it works even without the enablejsapi=1. The errors in the console you mention happen regardless if you use it or not.

    With enablejsapi: http://jsbin.com/ilutut/1/quiet
    Without enablejsapi: http://jsbin.com/ilutut/2/quiet

  • http://www.cardinalpath.com Eduardo Carvalho

    You should take a look at mine because even though I use the enablejsapi I don’t require the user to add that. I change the iframe href on the fly. It seems hackish at first but it actually works very reliably. I even change object/embeds to iframes in order to track them with the api. So the user also doesn’t need to do anything special besides triggering my code at some point.

  • http://sanderheilbron.nl Sander Heilbron

    Thanks for sharing.

    Recently I was working on some projects which also required tracking YouTube and Vimeo player events with Google Analytics. Because I couldn’t find any scripts or examples that met my requirements I wrote some scripts myself. You can find both scripts and documentation on GitHub:


  • Sayf Sharif

    Thanks for sharing your code Sander,

    The main difference is that it looks like your code still requires some Javascript work, entering in YouTube ID’s manually, unless I’m reading it wrong. That seemed pretty standard across most of the code I found that worked. My issue was that I wanted to be able to instantly apply the code I had to the head of a website so that I could immediately start tracking possibly thousands of videos across thousands of pages with an upload of 2 lines of code rather than having to go page by page by page editing page specific scripts. (as long as the videos were embedded with the standard youtube iframe).

    I was thinking of say someone who had a WordPress blog and wanted to be able to just embed a video on their blog (like our LunaTV’s!) where a Social Media person, or Marketing person with no knowledge and skill with javascript could just embed the copy/paste code on their site, and have it automatically tracked.

  • http://CircleMarketing.com Circle Marketing

    This is great! I’m going to use this on our site and all of our clients’ sites! More writing from Sayf would be great. I love that his writing style is the perfect mix of entertaining, intelligent, professional, and accessible.


  • http://www.analyticsforjoomla.com Martijn van Vreeden

    Very useful script! Just gave it a testdrive and found two issues:
    1. When using the scrollbar to skip parts of the video, it triggers many events for YT.PlayerState.PAUSED;
    2. When videos are set to loop, the script will not trigger the event YT.PlayerState.ENDED, event when the video is watch till the end.

    Hopefully this feedback can be incorpated into the current code.

  • Sayf Sharif

    Martijn thanks for the feedback! I’ll look into both of those.

  • zxon

    Nice script! Is there any way the title of the video could be used for the GA Event tracking label, instead of the video ID?

  • Sayf Sharif

    Well unless I read the API wrong you can’t grab the title from YouTube.


    You can get the URL, the embed code, and the duration. It’s not optimal. We talked about it internally here at LunaMetrics about what would be preferable. Just the YouTube ID? The URL stripped of parameter garbage? Ultimately we are using different things and modifying the code for different clients. One thing you find is that with all the parameters you can have the same video track as different ones, so you want to combine those as much as possible.

    Optimally we could capture both the link as well as the title, I agree, but the only way we could see to easily get the title, was to have the user enter the title manually in the iframe included on the page, or in a separate html element named and included near it. That was not my intention for this, in that I wanted something people could track their videos on a fire and forget basis by simply embedding a youtube video on their blog and have it immediately be tracked.

    But if we can come up with a better and easier way to grab that title and stick it into the event, I’m all ears!

  • yarvit0

    im trying to use the libs for my web but i get always a js error, at line 57 of lunametric-youtube.js: “Uncaught TypeError: Cannot call method ‘substr’ of undefined” any ideas?” it´s tracking anything T_T

  • Sayf Sharif

    Yarvit, I’m seeing that actually here on the LunaMetrics website, but I’m NOT seeing it on my test server where i’m running a stripped down HTML page. I’m wondering if it’s some sort of conflict with other code on the page? I’m looking into it.

  • yarvit0

    im debuging and at line 50 of the libs:
    var src = video.attr(‘src’);
    it returns src as undefined;

  • Sayf Sharif

    Yeah, i’ve tried changing how the jQuery is loaded, no conflicts, jQuery(‘iframe’) rather than $. Changed the variable to vidSrc rather than src. Added a basic check to only run those substrings if vidSrc has a value…

    Still comes up as an Uncaught TypeError: Cannot call method ‘substr’ of undefined.

  • Sayf Sharif

    It does bother me that i can’t reproduce the error on my test page though, there has to be some sort of conflict.

  • http://www.buzzwordstobusiness.com ThompsonPaul

    Am just checking out the script, but in the course of looking at this page’s source I noticed an error indo9cating your caching plugin isn’t working correctly:

    Just wanted to let ya know in case you hadn’t spotted it yet.


  • Sayf Sharif

    Thanks Paul, but the weirdness there is that we don’t use WP Super Cache, it must be a relic comment from somewhere.

  • yarvit0

    i couldnt solve it, anyone have the same prob?

  • Diego


    Thanks for your script, we have adopted it and made some modifications to report as we do with another script.

    One note, it would be nice that you checked that vidSrc exists in your script, considering the page can have some other iframes in it that do not have a src attribute (like in our case).

    Like this:
    if(vidSrc && vidSrc.length>29){

    Thanks again!

  • yarvit0

    I have fix it
    if (video[i] == undefined) {
    var src = video.attr(‘src’);
    } else {
    var src = video[i].src;

    its temporal, i think maybe its a problem with other iframes of the page (facebook and twitter logins)

  • Nicole

    Thanks for this post – it came at exactly the right time when I needed it. Like some others, I made a few modifications which may or may not be helpful to others. To prevent conflict with other videos on a page (which may be tracked in a different way), I added a unique id attribute to each I wanted tracked – i.e. “track123456″ – and checked that “track” was there. Like others here, I wanted a bit friendlier title passed in the label parameter of the tracking so that it would be easier to recognize the video on the GA side. So, I added functionality which takes the title from the iframe and passes it as the label. (Less hands off than your approach, but most videos on my site are added to content dynamically based on a content structure with this metadata, so it works for me. And if it’s not, then this approach is friendly enough for content editors to be trained to do.) I also changed the URL matching to this regex, which works well (though I’m sure there are regex experts who could tell me a whole bunch of things wrong with it), saves some code duplication, and doesn’t care which URL parameters exist.

    var regex = /https?://www.youtube.com/embed/([w-]{11})(?:?.*)?/;
    var matches = vidSrc.match(regex);

    If it’s a proper YouTube embed URL, then matches[1] should hold the youtubeid.

  • Sayf Sharif

    I’m going to apply these fixes and upload new code when i’ve tested it.

    Does anyone have any thoughts on how best to solve the issue of it firing a slew of pause events when someone drags the player time scroll bar?

  • http://riaancornelius.com Riaan

    I’m testing this on a wordpress site using the slidedeck plugin, and some of my slides are not showing after adding this script (Only ‘smart’ slidedecks are affected).

    The strange thing is that the slides are defined using definition lists, no iframes anywhere.. I had a quick look and the source doesn’t seem to be any different… I can’t see anything in the script that could cause this, but my Javascript skills is rather rusty. I’ll do some more testing and see if I can figure out what’s happening.

  • http://BasicBlogTips.com Ileane

    I’m using Viewbix to embed YouTube videos (works with Vimeo too) and the stats are great. I can also add an optin form for my email list. The videos get way more attention then the “vanilla” YouTube embeds.

  • Sayf Sharif

    I haven’t seen any specific data on levels of engagement with Viewbix videos, but there are other free ways to add interactive links to videos. In general though I’m not a fan of splitting analytics. I want to see in one spot, in this case Google Analytics, what is happening on the site, and how that relates to conversions. Do video viewers convert more on my site? I want to see that inside Google Analytics, etc.

  • Sayf Sharif

    Riann, I’ve seen general problems with smart slidedecks and youtube videos in general. Which slidedeck are you using? My immediate though is that the jquery is messing things up with how the jquery for the slidedeck is setup, and how the code in this is.

  • http://riaancornelius.com Riaan

    I’m using one called slidedeck (slidedeck.com). You can see the site on coretalk.co. For now, I’ve disabled your script, but the problem is with the slides in the sidebar (Yeah, I know – Slides in a sidebar!? – Shareholders will be shareholders though)

  • Sayf Sharif

    Yeah, obviously slidedeck uses jquery and some complicated javascript to function, and it doesn’t like something in this one. My money is still on some sort of jquery conflict.

  • Chris Green

    For the paused event… Wouldn’t this work?
    For your review…

    var _pauseFlag = false;


    function onPlayerStateChange(event) {
    //it tries to trick us with a number one greater than
    //that of our arrays. But we outsmart it.
    //with math.

    videoarraynum = event.target.id – 1;
    //Should the video rear it’s head
    if (event.data ==YT.PlayerState.PLAYING){
    _gaq.push([‘_trackEvent’, ‘Videos’, ‘Play’, videoArray[videoarraynum] ]);
    _pauseFlag = false;
    //should the video tire out and cease
    if (event.data ==YT.PlayerState.ENDED){
    _gaq.push([‘_trackEvent’, ‘Videos’, ‘Watch to End’, videoArray[videoarraynum] ]);
    //and should we tell it to halt, cease, heal.
    if (event.data ==YT.PlayerState.PAUSED && _pauseFlag == false;){
    _gaq.push([‘_trackEvent’, ‘Videos’, ‘Pause’, videoArray[videoarraynum] ]);
    _pauseFlag = true;
    //and should the monster think, before it doth play
    //after we command it to move
    if (event.data ==YT.PlayerState.BUFFERING){
    _gaq.push([‘_trackEvent’, ‘Videos’, ‘Buffering’, videoArray[videoarraynum] ]);
    //and should it cue
    //for why not track this as well.
    if (event.data ==YT.PlayerState.CUED){
    _gaq.push([‘_trackEvent’, ‘Videos’, ‘Cueing’, videoArray[videoarraynum] ]);

  • http://pawnmaster.com Ken

    This is exactly what I’ve been looking for but it’s not working. No errors, just doesn’t work.

  • http://pawnmaster.com Ken

    I’m not sure but it’s possible YouTube changed something on their end. The onYouTubeIframeAPIReady function is fired before your trackYouTube function, causing the videoArray.length to be 0, therefore nothing happens.

  • Trevor

    This is definitely not working, and I’ve spent hours checking and double-checking my process. Definitely a bummer, I should have read the last two comments before devoting so much time to troubleshooting!

    Google Analytics reads “4 of your visits sent events” but there is zero information regarding those events.

  • Sayf Sharif

    Ken and Trevor,

    I’m not sure exactly which issues you’re having. The code as described above is working on this very site, and on our test site. Are there no other errors getting kicked up? Are the embedded videos flagged as secure or to not be tracked? Were the embedded straight from the YoutTube site? If you read this, can you email me at sharif@www.lunametrics.com with an example page that doesn’t work for you, including the code implementation, and the embedded iframe? I’d like to take a look to see if i can reproduce and fix the problem.

  • http://fitzage.com Matt Fitzsimmons

    I had a little issue that some others may run into, and the fix is easy. I was getting an undefined error related to mySrc, and tracked it down to the fact that Olark generates an iframe without a src attribute which kills the rest of the loop, apparently.

    I fixed it by changing this:


    to this:

    if(vidSrc && vidSrc.length>29){

    So basically now it checks to make sure vidSrc actually exists and then looks at the length. The length check wasn’t enough because it would throw the undefined error on the length check if vidSrc was undefined.

  • AJ

    Hi Sayf,

    Great giveaway, it solves a big problem for a lot of people.

    I have a question, does this code work only with asynchronous GA tracking code or it also works with the traditional GA code?

  • http://www.rkd.ca Al

    Awesome. We always ran into issues getting accurate tracking of embedded videos on client sites. Uploaded your JS and bam! instantly tracking correctly.


  • Sayf Sharif


    My guess is that it might not work with the traditional code, but I haven’t tested it.

  • http://ea.com Robert

    Hi Sayf,

    This is a recommended approach for evaluating youtube urls and the youtube video id with regex:

    if(url.match(‘http://(www.)?youtube|youtu.be’)) { do.something() }

    var youtubeId = url.split(/v/|v=|youtu.be//)[1].split(/[?&]/)[0];

  • Viktor

    Thanks for the code! It is very useful for embedded video tracking. The install takes only 2 minutes and it works!
    Awesome idea! :)

  • AJ

    Thanks Sayf, too bad it doesn’t work with the traditional code. I have to do the OLD School setup again for a site, how come there is no simpler way for Traditional code.

  • jim

    FYI, I think you need to add the http: before the link in your code above:

  • Sam

    Great script but do you know why it doesn’t seem to work in IE? I am seeing almost no plays, pauses etc from IE users despite them making up around 30% of visits. Also I am testing a bit in IE8 and can only get events to fire intermittently. Anyone else having problems in IE?

  • Mihnea

    Hi Sayf!

    It seems a pretty simple tutorial. However, I didn’t manage to track the events in GA. I have added the scripts as you said. Also I have added the Youtube video with the recommended iframe code.

    I got nothing. I use Asynchronous code for GA tracking. Does anyone encounter this problem with the code above?


  • http://zmenmediagroup.com Art


    I have the same issue. I insert the code right after my GATC and before the , with no results.

    I’m a marketer by trade, know very little about coding and don’t have budget to hire anyone. That said, any suggestions for getting this tracking code to work via my Tumblr blog would be greatly appreciated

  • jim

    This code did not work for me either. Nothing appears in GA.

  • Sayf Sharif

    I’ve updated the code to version 2, with some of the above suggestions. It now uses regex to match the iframes, so should match more odd youtube iframe embeds better. In addition I added the pause script suggestion to prevent the rapid fire pause events that would occur on dragging the slide bar. I’ve tested the code and it’s working.

    If you are having problems getting the code to fire, confirm that your jquery and youtube code is placed on the page after the main Google Analytics Tracking Code script, and that you’re linking to them correctly. Download the javascript, and host it on your own system, rather than linking to the code on lunametrics.

    However the script does seem to have some Internet Explorer cross browser compatibility issues, and does not fire consistently on IE. Will look at that for the next version of the code.

  • Micah

    Awesome! Although I didn’t use it as just an include, since I had to integrate it into a custom analytics tracking module. But I used all the ideas in it. Life saver! Thanks 😀

  • Tathiana

    Great script, except I can’t get it to work on my site. In the Chrome console an error is shown: Uncaught TypeError: Cannot call method ‘match’ of undefined. Any ideas, or anyone else having the same problem?

  • Sayf Sharif


    Thanks! While it worked on my test site, I was able to reproduce your error. I added in some slightly better logic to catch that occurrance, and if you download the script again and use the new script included, there is additional logic on line 65 to catch that error, and it should now work.

  • David Hughes

    Thanks for the script. We were having some issues with it not reporting on IE and I found a fix that seems to work.

    I added two new booleans, documentReady and youtubeAPIReady which are set to true when those respective methods are called.

    Then, I added a new method which is called by an interval:
    function initialisePlayers() {
    if (youtubeAPIReady && documentReady) {

    I’m not sure how good of a practice this is, so any advice would be great & I hope this helps someone :)

  • Sayf Sharif

    Interesting, I’ll have to take a look at that.

  • Chris

    Thanks for this! I am not familiar with javascript, so I am dependent upon great work such as this. I am, however, having some trouble. I am hoping someone can help me.

    I am running a blogger site. Each post is a video. The main page shows the 5 most recent posts, and therefore contains 5 videos. Videos are placed on the page using the standard embed method.

    In the header of the site template, I have added the following lines:

    So here is what I get:

    1. First video on the page does generate alerts.
    2. Other videos on the page do not generate any alerts
    3. Only two alerts are reporting: PLAY and PAUSE

    What am I missing here? Thanks for the help!

  • http://cpoheli.com Chris

    Sorry… the comment engine must have stripped the script code. It’s essentially the two lines that are posted in the blog entry here after the words: ” So you’ll have something like this…”

    I have one line for jquery and one line for lunametrics-youtube.js.

  • Sayf Sharif

    Ok I see it now on your site. This isn’t the first time I’ve seen this error with the code, but i can’t reproduce it on my test server, which makes me wonder exactly what is causing it.

    It often seems to revolve around the matching aspect and your site is kicking up the error:

    Uncaught TypeError: Cannot call method ‘match’ of undefined

    Maybe that’s not being handled right in the code. I’ll see what I can do to change it, unless anyone else listening in on this thread has any suggestions.

  • http://cpoheli.com Chris

    Thanks! I did see your visit, and it looks like the first video on each of the two build pages registered the play/pause events.

    I appreciate you looking into this. Your script was exactly what I needed. I’ve tried the former methods, and they don’t work with multiple videos on the same page. I was very excited to find this. Now if we can figure out what the deal is, maybe it will help others too.

    For everyone else…My site is a Blogger site, so it may be unique to their formatting?? Not sure. I know only enough to get into trouble. : )

  • http://cpoheli.com Chris

    I’m way out of my comfort zone here, but I did try copy/paste the actual code into the page, rather than using your externally host js. It didn’t work either, but maybe there is some intel that will make sense to you. When I tried to use the code direct, It wouldn’t accept some of the formatting.

    I had to change && references to &amp:& and I had to change < to $lt;

    This could just be a product of the Blogger html editor (since it checks for malformed tags or code issues before letting me save) and may not really have any impact to the actual code processing in real-time, but I figured I would bring it up in case it was of some value to you as you try and troubleshoot.

  • http://cpoheli.com Chris

    Sorry….It should read:

    I had to change && references to && and I had to change < to <

    (I can't edit the comment)

  • Sayf Sharif

    One thing that you could do would be to try hard coding the video. It goes against my goal of this code which was to just have a script to have on all your pages to automatically track all videos across a site without hand coding anything….

    However this has worked in the past when for whatever reason the client server has a problem with the match method. To change the trackYouTube function in the above code to the following, and then just have if/else statements to match the actual src value for each video on the page, and bypass a regular expression match entirely. It’s definitely a kludge, but if you only have a few videos, it could work and solve the problem.

    Look at the iframe on the page, and then take the value of the src which would be something like “http://www.youtube.com/embed/YOUTUBEIDHERE” where YOUTUBEIDHERE is the YouTubeId like.. PtHET657o and copy that whole value into the line below with it, and then just the youtube id into the two spots for it there. Then even just copy and paste that entire if statement again and do it for a second video.

    Essentially you’d be manually building the array of videos on the site rather than comparing them via a regex match. This wouldn’t even really be the best way to do this staticlly, because you could do it without even running through every iframe on the page to check, you could just set them, but this seemed like it might be easier to understand for a non developer.

    let’s hope my code pastes below…

    function trackYouTube()
    var i = 0;
    $(‘iframe’).each(function() {
    var video = $(this);
    var vidSrc = “”;
    vidSrc = video.attr(‘src’);
    if (vidSrc == “http://www.youtube.com/embed/YOUTUBEIDHERE”){
    videoArray[i] = “YOUTUBEIDHERE”;
    $(this).attr(‘id’, “YOUTUBEIDHERE”);

  • http://cpoheli.com Chris

    I appreciate the time Sayf. This option does not work in my situation, since I cannot predict which videos will be displayed at any given time They are dynamically presented based on recency, search results, etc.

    Would it be possible to remove the trackYouTube function all together and just hard code adding the video ID into the array down in the page where the video actually is? I don’t know if this is possible, but I was thinking of something like this (pseudocode):

    Add the code that can be loaded up front that doesn’t require the array to be in place yet.

    Have the various videos iframes and an associated javascript code that simply adds the video ID to the array. No regex, no if/then, just a statement that loads with the video pages.

    At the very end, after all of the array statements have been made, can I then load up the rest of the script that is dependent upon the array being complete. I imagine this is the meat of the code, loading at the end rather than up front. I realize their is some risk of activity before the script fully loads, but I see it as minimal.

    Does any of this make sense, and is it possible to reconfigure in that fashion? I realize it takes away from the fire-and-forget intention of the script, but it doesn’t seem like that is going to work in my situation. I’d rather not go manually add javascript code to my 50ish videos, but will do it if that’s the way to get it to work. Future videos are not a problem, since I can just make it a part of the template for new posts.


  • http://cpoheli.com Chris

    Dang…looks like my “free support” expired. : ) LOL. Just kidding. I may have to look at plan B…I just can’t get this to work. Unfortunately, all of the articles and blogs that start to address the situation eventually point to this blog. Kudos for solving most everyone’s needs! Stinks, tho, that there are a few of us that this doesn’t work for. I even tried looking for conflicting javascript, but didn’t find it. I’ll continue to check back from time to time, just to see if anyone comes up with anything. Thanks!

  • Sayf Sharif

    Chris, et al,

    i’ve just updated it to 2.1. I’ve added the following code.

    var vidSrc = “”;
    var vidSrc = video.attr(‘src’);

    Before I wasn’t checking for something being undefined and it would error out on the match portion later, but only on some servers. I don’t know WHY it only happened on some servers and not others, but there it is. This check though seems to fix that Type match problem, and might solve some of the problems for people where the code would not fire.

  • Chris


    Thank you, thank you, thank you!

    This seems to be working great now on my site. I really appreciate it, and glad you were able to figure out the issue. I am glad I decided to check back today!

  • Sayf Sharif

    Chris, Glad that fix worked for you!

  • http://twitter.com/aschottmuller Angie Schottmuller (@aschottmuller)

    Thanks for posting this, Sayf! I was about to code the same thing, so you saved me the time. Much appreciated! I wanted to include the video time at the time of the events, so I’m glad you mentioned getting some errors in the API.

    The comments in the code are amusing. =) Do you have a clean, minified version of the code available for download?

  • Sayf Sharif

    I don’t have a clean version available (though I’ve made one in the past by just hand deleting the comments). I should really just get my act together and put a version in github or something to make it easier for people to play with.

    good idea for the video time in the events. I just did that with my jplayer tracker, and it’s really useful for analysis.

  • Luca

    This just doesn’t work for me and I don’t understand why. On the JavaScript console on Google Chrome, I get this:
    Uncaught SyntaxError: Unexpected end of input js_lunametrics_youtube2:184
    Unsafe JavaScript attempt to access frame with URL http://www.mysite.com/ from frame with URL http://www.youtube.com/embed/___________. Domains, protocols and ports must match.

  • Sayf Sharif

    Luca, the unsafe javascript attempt is normal, that’s not the problem. The Uncaught SyntaxError is. I’m not sure what’s cuasing that, it looks like maybe you renamed the file? Or edited it? It’s hard to say without looking directly at the page with the error. Something looks like it wasn’t properly implemented though.

  • http://www.vidanalytic.com/ James Wann

    Hi there,

    Just wanted to mention a product that already does embed analytic measurement with depth tracking:


    We also do Dailymotion and Vimeo for multi-source curators.

    (P.S. I work for vidanalytic – so this is a shameless plug 😛 )

  • Sayf Sharif

    James, I’ll allow the plug. :) However, I have to say that while your service appears to give good information on video usage, it is completely disconnected from the remainder of your site tracking.

    My goal with the various video tracking scripts I’ve posted is to bring in that video data to Google Analytics, where you can see where a user came from (say a campaign tagged email marketing blast) and what they did on the site (like watched a couple of videos, viewed a few product pages), and then ultimately whether they converted on your KPI (they purchased a product, they filled out a contact form, etc).

    Bringing that data into Google Analytics let’s us compare how the videos perform in relation to where the visitors came from, what they also looked at on the site, and how they ultimately converted. If there are 20 videos on a website, just knowing that all 20 were viewed 10 times each doesn’t help increase our conversion by itself. Knowing however that viewing Video A led to 50% of the viewers to purchase a product, versus Video B which led to 0 purchases can let the company say “hey maybe we should use more of Video A” etc.

  • http://www.vidanalytic.com/ James Wann

    Sayf, that feature is definitely on our roadmap (and accelerated based on your feedback!) – we’ve seen some adoption over the past few months from folks hosting A/B test pages – and something like that will definitely take it to another level. :-)

  • Leone

    Hello Sayf,
    I love your script! Yesterday I succeded in getting it working, I left the office got back and it wasn’t working anymore! that sound weird I know.
    Looking at the console I get:
    chrome.windows is not available: You do not have permission to access this API. Ensure that the required permission or manifest property is included in your manifest.json. binding:202
    Uncaught TypeError: Cannot call method ‘getCurrent’ of undefined popup.js:17

    Not sure this could cause it.
    here you find my attempt:

  • Leone

    I even tried to create a new blank page (which is correctly tracked by realtime on Analytics) with your code I found on the source of this page and this video:

    NOthing: I see someone is browsing that page but no events is showing in realtime–>events
    The weird thing is that it was working yesterday evening!

  • Viktor

    I can’t seem to get your script to work if the videos have been embedded using the javascript method (where the iframe is created dynamically), instead of writing iframe tags into the actual html source.

    That is, using this method: https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player

    I can successfully attach events for onReady and onStateChange like in the example, but I would like to use your script (or a similar one) in order to not have to specify events manually for each video I embed.

    When I include your script as-is, it stops the video frame from loading completely. I suspect it could be due to it creating new YT.player objects that replace the original one.

  • http://www.delphiglass.com Chris S


    For the most part this seems great, and I’m really excited about this, but it seems that there is a strange anomaly happening with the reporting. The code has been running for two days, and over the past two days google Analytics is reporting that 18 of our 99 videos that have been viewed thus far have 1 transaction associated with them, with the Revenue being $277.83 exactly. I looked into our order management system and there has only been one order equaling $277.83. So could there be an issue here, or is it possible that an individual watched 18 different videos before making a purchase and each video is being tied to that purchase?


  • Jo

    Hey, I tried your method & downloaded the file & followed the direction.
    But still not firing off. My website is a wordpress, I get this message when I was debugging it via chrome.

    Blocked a frame with origin “http://www.youtube.com” from accessing a frame with origin “http://mywebsite.com”. Protocols, domains, and ports must match.

    Have you seen this before?

  • Sayf Sharif

    Leone, I’m not sure. Maybe the latest version of jQuery has an issue with something? i just checked here on LunaMetrics and it’s still working. Try putting an id on each iframe, and also moving the code up higher on the page above the GATC and see if that fixes it.

  • Sayf Sharif

    Viktor, yes this isn’t compatible with dynamically generating them. You’d have to modify the script so that our video script wouldn’t actually run until after the videos are all loaded onto the page, and then it probably would work.

  • Sayf Sharif

    Chris you should be able to tell how many people watched the videos. One way you might want to look at is to segment video viewing sessions from sessions that didn’t view videos. Create an Advanced Segment which includes video event category, and another segment which excludes them. Then you can compare visits where people viewed videos and those that didn’t.

    however if you’re seeing 18 videos viewed, and they all have that same transaction amount, and no other videos do, my feeling is that it’s one person who watched them all and purchased.

    Also keep in mind, I think it says this somewhere, that this still is iffy or doesn’t work at all on IE, so if you have a large volume of IE traffic, it’s not going to capture everything.

  • Sayf Sharif

    Jo that error message is normal with the script, and shouldn’t stop it from working. There must be some other problem with how you implemented the code. If you want, you could create a test page and put the URL in here as the website URL on your comment and I’ll take a quick look.

  • http://www.delphiglass.com Chris S

    Thanks Sayf!

  • Jo

    here’s the test page that you can look at.

  • Sayf Sharif


    Not sure if that’s the right page. There was no youtube video on that page, and the youtube script itself looks like it wasn’t loaded/pointed to on the page properly.

  • Jo

    I had to take it down for the wkend.
    please look it the page now.

  • Sayf Sharif

    Is this the script to include our code?

    <script type=”text/javascript” src=”http://westernshootingjournal.com/wp-content/themes/atahualpa/js/utube.js”>

    If so, then the quotes are ‘curly quotes’ and need to be changed to regular quotes like “. In addition that file doesn’t appear to exist on the server. It looks like the filename was cut off. so it’s definitely not loading our script correctly that I can see.

  • Jo

    yes that is the script.
    double checking the file it does show up on my browser, I did rename the file to utube.js

  • Sayf Sharif

    It’s definitely not loading for me in Chrome. Watching the Console while the page loads I get this error:

    Failed to load resource: the server responded with a status of 404 (Not Found) http://westernshootingjournal.com/about/test/%E2%80%9Dhttp:/westernshootingjournal.com/wp-content/themes/atahualpa/js/utube.js%E2%80%9D

  • Jo

    Yes, when I run the debug in chrome, I do see this. I double checked the server, and the file is there. so I’m confuse at the moment.

  • Mark

    I am getting a console error when any event is trying be fired, such as pressing play:

    “Uncaught ReferenceError: _gaq is not defined”

  • Mark

    If it makes any difference, the tracking code GA gave me today doesnt look like the codes I’ve used in the past (details hidden):

    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),

    ga(‘create’, ‘UA-########-1′, ‘domain.co.uk’);
    ga(‘send’, ‘pageview’);

  • Shahar

    Like it says in the notes, you need to be using the older ga.js code for this to work, you can find it here:

  • Sayf Sharif

    Mark and Shahar,
    Yes this works with the asynchronous tracking, not the new universal tracking which is still in beta.

  • Matt

    Thanks for sharing this. Does the script account for HTML5 YouTube videos? HTML5 is typically used by YouTube when a user does not have flash installed (iPads).

  • Matt

    By the way, it may be helpful to add the part about it not working with universal analytics to the notes part at the bottom of this post. I would not have realized it if I didn’t notice it in the comments section. Thanks again.

  • Oleg

    Hi Sayf,
    thank you for the amazing script. You saved a lot of my time.
    I have a little question. Are there some restrictions on the jQuery version?

  • Oleg

    Also during the test of Your remarkable script I found that it doesn’t track events when I use Opera browser.
    It shouldn’t work in opera or it’s my own problems?

  • Igor

    Thank you very much for sharing script. I am trying to implement the script but do not appear on the Analytics events…

    The web page is http://www.palaciodeesquileo.es/bodas-segovia.html

    What I am doing wrong??? Thank you in advanced an than for sharing

  • Sayf Sharif

    Matt, yes it tracks on both iphone and ipad.

  • Sayf Sharif

    Oleg, I never tested it on Opera so I’m not sure. It does have problems sometimes with IE versions prior to 10, but IE 10 it does work. So it’s possible Opera had the same issues.

  • Sayf Sharif

    Igor, Sorry that page won’t load for me at all. If it’s not working, remember to have the jquery and youtube script in the head of the document, rather than in the body, and be sure that the files are actually being pointed to correctly and loading onto the page. Those seem to be the most common problems people have.

  • Oleg

    Sayf, thank You for the answer about Opera.
    Please, answer to my question about jquery version. Is there any limits for jquery version?

  • Sayf Sharif

    It works with the version I listed above, but I haven’t tested it for earlier versions.

  • gal

    Hallo sayf,

    I have a qusestion about the code position,
    I have 1 page Website which were made in wordpress,
    my question is where I need to put the code in wordpress case, where I can’t specify a page?
    should I put it in the header.php?
    (I am using the “page builder” widget to push video to my page).
    Thank you very much for your time and Patience!

  • João Victor

    Hi Sayf,
    Thank you very much! Your script saved my life!
    But I would like to know how can I get the elapsed time of video that user already watched. Is it possible? How can I achieve that?
    One more time, thank you!

  • Sayf Sharif

    gal, yes put it in the header.php file in that case and it will be included on every page, which in your case is just that one.

  • Sayf Sharif

    João Victor, you’re welcome. Other players have a bit of an easier time with elapsed time, see my jplayer or video.js posts. Those it’s easy to do some sort of TimeWatched trigger. Youtube however does not send that information with the api (at least it didn’t last time I checked, but I’d love to be wrong and corrected on that).

    So that leaves you with doing something like manually tagging the videos with a length in some way, and then setting an interval on the page in javascript and occasionally at certain points sending that time elapsed data, tied into the play event occuring, but no stop or pause event, etc. Keep in mind that you’d still be limited to 500 events per session, so you won’t want to be sending that every second, etc.

    In general if you want more accurate second by second tracking, you might want to examine using another player.

  • gal

    Hi Sayf,
    first of all thank you very much for the quick respond.

    unfortunately it doesn’t work )=
    I added to your code YourCode,(otherwise I just see it on the Website) in the header.php(between the tag),
    my youtube tag look like this:

    I am sure that I’m doing something real stupid and I hope you could track it out (=.

    Again, thank you very much!!

  • gal

    …”I added to your code” script “YourCode” /script tags…

  • gal

    SORRY! I am not use to write in forums XD.
    “my youtube tag/code look like this:”

    iframe class=”alignnone” width=”100%” height=”450px” src=”http://www.youtube.com/embed…” frameborder=”0″ allowfullscreen /iframe

  • Sayf Sharif

    gal, do you have a link to the page that I can see? If you include the 2 lines of code to be sure to include jquery, and the video code within the head section of the html, and are using asynchronous ga, not the universal analytics code, and have the iframe on the page, it should work. Maybe one of the files isn’t pointing correctly and not loading?

  • gal

    Again thank you very much for your respond.

    I’m working on a project from the company, thats why I preffer not to post it here.

    if i understand correctly (please correct me if I’m wrong),
    when user get into my Website, click on the youtube video (of course the video is in the landing page), and immediately get out, the GA recognize this user as bounce, and that’s exactly what I’m trying to prevent.
    That’s why your code is perfect for me, your code track every single click on the video and does not count the user in as bouncerate.

    1)I put the code in the header.php – in the head tag between “script” tags,
    2)in “TEXT AREA” widget (from “pagebuilder”)I put the iframe with the youtube video in it.
    3)Under the iframe write the 2 jquery codes from above.

    And still, when I test the connection, by entering the site, click “play” and leave it’s still count me as a bouncer.

    Maby I am 100% wrong with the purpose of the code.

    Again TY very much for your Patience (if left any XD).

  • Sayf Sharif

    Well the lines of code need to be in the head section of the page, but you don’t need to add extra script tags around them so:

    <script src=”//code.jquery.com/jquery-1.7.2.js”></script>

    <script type=”text/javascript” src=”http://www.lunametrics.com/js/lunametrics-youtube.js”></script>


    You could copy those scripts into that location just like that. Make sure you’re not copying in jquery twice, see if it’s on the page already (it probably already is there on the page).

    Then include that iframe so it shows up on the page in the body content somewhere. I don’t know what the text area widget is, but if it puts that code in an actual HTML Text Area, then that won’t work. If your’e seeing the video on the page, and can play it though, I’m assuming it’s just the wordpress text widget, and that should work fine. However you don’t need to include jquery after the iframe. just put those scripts into the head section within the header.php file, then icnlude your iframe, and it should work.

  • Sayf Sharif

    Also watch for curly quotes in the script lines if you copy them, sometimes they seem to get added by wordpress and it’ll break the code and it won’t actually get included.

  • http://ceriusinterim.com/webinar_revenue_0613.html tlock

    Your code works great. Thank you for sharing. I’m wondering how I can be more specific with the naming of each video. With multiple pages and videos the analytics starts to get difficult to decipher with the conventional YouTube naming structure. It would be great if I could assign more specific names to each.
    I appreciate any assistance you can offer.

  • http://www.publiclikes.com/youtube_like.php gopal

    yes put it in the header.php file in that case and it will be included on every page, which in your case is just that one.for more:http://www.publiclikes.com/youtube_like.php

  • gal

    Hi Sayf,
    Happy fourth of july!
    I did my homework and I managed to implement your code in to my Website,
    I must say it works PERFECT!
    The problem was, I used a GA traditional code and not Asynchronous.
    I would like to thank you very much for your support and patience!
    again thank you and wish you all the best!

  • Sayf Sharif

    tlock, you can use the YouTube API and retrieve the title of the video I believe. When the first implemented this we were using the title of the video but for some reason we changed it to the YouTube ID I don’t recall why but something tells me there was some reason why the title might change where is the ID did not. However I agree it is unwieldy at times and hard to recognize buy eye.

  • Sayf Sharif

    gal, glad it worked for you!

  • gal

    Sayf one more question (=
    is there any way that I could see in the GA
    content> event> overview > label event, the name of the video and not the ID?


  • Sayf Sharif

    gal, here is a link to some people that built off this code in a way that Incorporated the title of the video as opposed to the ID: http://www.isitedesign.com/labs/2013/01/21/how-to-track-youtube-video-playback-with-jquery-and-google-analytics-events/

    check it out it might answer your question.

  • gal


    thank you very much!

  • http://www.rendermouse.com Andy

    This script is very useful. THANK YOU.

    You can get individual video progress by using setInterval to call a function every 1/2 second or so that loops through the playerArray and uses playerArray[i].getDuration() and playerArray[i].getCurrentTime() to calculate the amount of video that has been watched. Once that crosses 25% (50, 75%), fire a Google tracking call.

  • Matt

    Thanks again for this script and responding to so many comments. Looking at the JavaScript, it looks like modifying this to work with Universal Analytics would only require changing all of the lines with _gaq.push to the new analytics.js events format. Is that a correct assumption or am I overlooking something?

  • Sayf Sharif

    No that would be all you would need to do I think.

  • Jim


    This is an awesome script. Nice code commenting too!

    Is there a version of this that would work with the Universal analytics.js? We are already using analytics.js to track other events across our site.

    I tried to modify the script a bit to work with Universal Analytics per this post http://stackoverflow.com/questions/16015364/how-to-set-up-ajax-call-tracking-in-google-analytics to no avail.

  • Sayf Sharif

    I’ve added a second version above that should work with Universal Analytics.

  • http://toinfinity.co.uk Kirsty

    Laughed heartily at the commentary throughout the code. A ray of light in my work day!

  • Sayf Sharif

    Glad you enjoyed it Kirsty.

  • Todd

    This is great. Do you happen to know how to adjust the script to work with embedded vimeo content?

  • vinot

    I tried to implement your code.. but its not working for me… Plz have a look at it and help me.

    Thanks in advance..!

  • Sayf Sharif

    Todd, try the code at http://sanderheilbron.github.io/vimeo.ga.js/ he beat me to a good vimeo implementation.

  • Sayf Sharif

    vinot, your youtube embed needs an http: at the start of the source address, noit just a //

  • Vinoth

    Thanks a lot sayf. Its working now.

    Tried to use the same code in GTM. Its not working.
    Whether I need to change anything in the code for Implementing Youtube video tracking using GTM?

  • Sayf Sharif

    I haven’t done it through GTM, but I guess it could mess it up depending on the order it loaded in, though.

  • http://njoin.co.uk/grains/5203669e6decf93f1e000032 James

    Hi, the script doesn’t work with the current youtube embed code as the regex doesn’t match //www.youtube.com... when missing the http.

    I’ve fixed it in my own version by using (https?:)? and using the third capture group maches[2] instead of matches[1].

    You can see my changes and updated script at https://gist.github.com/Jamedjo/6184913

  • Lauren

    This is exactly what I have been looking for. Thanks so much!

    My question is where on the page does this script get placed so it can be used? And if the script doesn’t go on the page that I have the video embedded in where does it need to get put?t doesn’t go on a script where do I need to put it

  • Roie

    Works perfectly, though cannot seem to find a solution for wmode transparent, any suggestions?

  • Sayf Sharif

    James, thanks youre right. I wonder when they changed that. Very annoying.

  • Sayf Sharif

    Lauren, in the head section of the HTML preferably. It needs to be included on the page delivered in some manner for it to work. In theory I think you could probably put it anywhere on the page.

  • Sayf Sharif

    Roie, I haven’t looked at that at all, sorry. Maybe another reader has a solution?

  • George

    I was very excited to find this solution, only to find that it doesn’t work for me.
    I tried on different domains, with the new universal analytics code (ga) and the classical one (_gaq). Neither worked!
    Could you please take a look at zeebeauty.net and tell me if you see anything wrong on missing?

  • Sayf Sharif

    George your double quotes in the script got turned into curly quotes.

    Edit the jquery line and the youtube code line and replace the curly quotes with plain double quotes. You can do this easily by converting it to plain text as well in a text editor.

  • George

    Thanks for that, but replacing the curly quotes with plain double quotes didn’t fix the issue.

  • George

    Hi Sayf,

    I have even tried with the classic (gaq) GA code and your corresponding js.. but unfortunately the result is the same – NO events recorded in Google Analytics.
    So, at this point, zeebeauty.net contains the new code and zeebeauty.com contains the old code. Neither works.
    Do you have any solution or any other suggestions?
    Thanks in advance!

  • Sayf Sharif


    the code is loading correctly now, but the problem is that Youtube very recently changed the default source for it’s embeds. try going to the iframe embed code and before the //www.youtube.com add the http: line so that the source of the iframe starts http:// instead of just // and it should work. I need to update these scripts to compensate for their change.

  • George

    unfortunately the adding of “http:” didn’t fix the problem. Events are still not recorded.
    Any other possibilities?

  • Lope Titi

    HI Sayf,

    I was able to get this working but the event fires at random (It fires on some youtube videos and not other).

    Has anyone experience this?

    Could it be that the YouTube IFrame Player API loads before document.ready, which fires the YouTubeIframeAPIReady, while the videoArray is still empty.

    Any idea to resolve this will be highly appreciated.



  • Tiffany

    We added the “http:” in iframe for youtube URL and we are now able to see some tracking, but like Lope, we not seeing tracking for all 12 videos on the page.

    We also continue to see the following error:
    Blocked a frame with origin “http://www.youtube.com” from accessing a frame with origin “http://www.website.com”. Protocols, domains, and ports must match.

    Any help is appreciated!

  • Lope Titi

    Further to the message i sent above, I think the problem is with jquery not aware of the page object when the object changes via Ajax with the page is not reloading. I have my Youtube videos in a carrousel and i noticed that the event tracking is fired only for the first video and not for the others on the page.

    @ Tiffany — is this the same situation as yours and have got any work around on this.


  • Tiffany

    We originally had 12 videos on one page, but just recently updated one page per video. Tracking is still not working.

    Please take a look at this page and offer any suggestions. meditab.com/client/client-voice/allergy-ehr-improves-practice-efficiency/

    We really need to get this tracking issue resolved. Thanks in advance!

  • George

    Automagically, one of my websites onto which I installed the lunametrics js started recording events – it uses the classic GA code (gaq_).
    Another website with the new universal analytics still won’t record events.

  • Sayf Sharif

    I’ve updated the code. It should work with the current newer form of YouTube embeds as well as older ones. try updating to the code now included above as the download code (marked version 5) and it should track right out of the box.

  • Sayf Sharif

    Per some of the above questions. The code runs when jquery is loaded, and ready to go. It then scans the page for youtube iframes, and runs it’s code accordingly when it finds youtube events.

    If you dynamically add the embed code later through ajax, it will not get tracked straight out of the box, because the code isn’t seeing that iframe when the page loads. To do so you would need to turn our code into a function that both runs on load, as well as again separately when you dynamically load additional video embeds.

  • avejidah

    Thanks for the example. *Small gripe a bit about the comments.*

    Looks like Lope pointed this out already, but there seems to be a race condition there. If onYouTubeIframeAPIReady fires before document.ready, the videoArray will be empty. It works _most_ of the time, which seems worse than not working since it’s hard to tell that it’s not working!

    This is an easy fix with a $.Deferred. When the API is ready, queue the YT.player creation against the $.Deferred. Then resolve the deferred when trackYoutube() completes. Three-line fix!

    Anyway, thanks again for the snippet. /me goes and brushes up on ye ol’ C.

  • Sayf Sharif

    That’s an interesting idea, I will look at adding that in the next version.

  • Dave

    I seem to be having a problem with ‘Total Events’ and ‘Unique Events’.

    For example I have 1 video on a page. In google analytics that page got 10 unique views. However in the events analytics for that page it says it got 120 total events and 8 unique events. Why is the total events so much higher? There is no way that out of 8 unique people that they paused/play or it went from buffering to play. Could anyone shed light on these numbers. Or the accuracy.

    Any insight or explanation on why these numbers would be off/accuracy would be great!


  • Sayf Sharif

    It would be hard to say based on that data, and without looking at the page. However let’s say that the 8 people watched the video all the way through. You’d be looking at 3 events each so 24 total events. It’s possible one person played and paused alot and it skewed all the totals. Very possible with 10 total visitors to the page.

    Or maybe there is something going wrong with the tracking. That could be the case as well and you have multiple events firing for some reason.

    If one of those users was you, and you were testing the tracking though, it might be you who was inflating the overall numbers.

  • Peter

    Hi. I’d like to track plays on a YouTube playlist. Will your script work with the additional playlist value appended after the video id.


    There were additional attributes (like fullscreen, frameborder, etc) but I’ve removed them to the basic needed to play the video playlist.


  • Sayf Sharif


    It should match that and work out of the box.

  • Sayf Sharif

    The core part to have is this:


    whether it starts with nothing, http https, and whatever comes after it.

  • Leonardo

    Hi Sayf, Is it possible to use this way with Google Tag manager? Ia am testing pasting the code int HTML Custom (GTM).

  • Dave

    It seems on Saturday the events went down to under 15 a day. Where before we were over 500 events a day. Did youtube change their embed? Is other peoples analytics counting the video views correctly since saturday?


  • http://www.basketballworkouttips.com Jesse

    Hi Sayf,
    I trying to include this script in my wordpress site but it’s making the website crash.

    I took the 2 script lines and put them at the bottom of the header.php file.
    the last lines of the header.php looked like this:


  • http://www.basketballworkouttips.com Jesse

    Oh, I see I can’t post html here so I’ll just post a link to a text file of my header.php.

  • http://magnet360.com Mike

    Sayf — I’ve been using this for a few months now, so thank you for that. However, it suddenly stopped working recently. Was there a change at Google? It doesn’t seem to be working on this page right now either…

  • Sayf Sharif

    Jesse, move the scripts. They won’t work when they are in the php portion of the code. copy them away from there and further up near the middle of the coe put them between an earlier close php and the end of the head tag.

    <—-put them here

  • Sayf Sharif

    MIke, try the newest code we link above. Google changed how they embed the vidoes a little bit and the newer code may solve your problem.

  • Alvin

    I used your code and it works fine on localhost but not when the code is live. Do you have any idea how I can make it work live?

  • Sayf Sharif

    Alvin I can’t be sure what you are doing wrong. Could be that you are pointing to a local file in the script, but that is breaking when you make the code live.

  • Sayf Sharif

    Leonardo, yes you can use this with GTM.

  • http://www.craftbeer.com Nate

    Hi Sayf-

    I have a dynamic page that loads videos into the page without reloading the entire page via ajax.

    I try to re-initalize the trackYouTube() function via JS when a new video is loaded, but I continually get ‘function not defined’ errors.

    I have tried loading the script in different places (header, body, footer) to no avail. Do you have any insight on how to re-initialize the script when a new video is embedded/loaded?

    Thank you kindly.


  • http://www.basketballworkouttips.com/ Jesse

    Hi Sayf, I moved the lines upwards like you said but the code is not working, I don’t see any events on analytics. Am I missing something?

  • Sayf Sharif

    Jesse you have some extra double quotes showing up in your code so it’s broken both for jquery and the video script. Have only one set of plain double quotes where you have two.

  • Sayf Sharif


    Your best bet would be to write up some code that had a function called when the new video was dynamically written and then have that video added to the already existing array.

    Or if you are only doing the dynamic load once, you could change our code to fire as a function when you call it rather than on document.ready which would be before the videos are loaded.

  • Graeme Mac

    Thanks for the code. Do you know if anyone has added to the tracker to get view range into Google Analytics?

  • Ian L

    Would be great if someone could expand on tracking YouTube videos using GTM! I’ve tried but failed to implement the above solution (it’s throwing errors)..

  • Sayf Sharif

    We’ve actually implemented it through GTM as have others, and it should work right out of the box just include the code and go.

    Make sure you have the right copy of the code (universal or classic) and then host that file on your own server, and include the script include code in a GTM tag.

    If you are getting errors you are probably either not hosting the right code locally, or there is an error in how you are including the script via javascript, or your youtube embeds are being done through a different method where the iframes don’t exist when the tracking code runs through jquery.

  • Ian L

    Thanks Sayf, I’ll give it another crack. 2 quick questions:
    1) Is there a way to get this functioning without jquery if a site doesn’t have it? For instance, if all videos are in a particular subfolder? Or is the jquery doing more than just finding the iframes?
    2) What specifically needs to be done in GTM to tie it all together?

    Thanks again!

  • Sayf Sharif


    This code specifically requires jquery. The basic idea was that you could add this to a site, and if a content editor embeded a youtube video it would automatically be tracked just by embedding it in a blog post. If you KNOW all your videos you can use the youtube tracking api I link to above and just hardcode them all without using any jquery.

    All that needs to be done in GTM is to add the script to a tag, and include it on any page you want your embeds to be tracked. that assumes you are already including jquery somewhere, otherwise you’d need to include that in a GTM tag as well.

  • http://www.amd-promotion.de/bf4/ Christian

    Hi Sayf,

    first of all thanks for your effort. I tried keeping track of the 3 embeded Youtube Videos on this site:

    For some unknown reason it doesn’t work. Iam about to give up because i dont see it. Maybe you can help?

    thanks in advance!

  • Sayf Sharif

    Christian, it looks to me like it’s working. What browser are you using?

  • Christian

    Hi Sayf,

    iam using Chrome.
    All of a sudden without any changes it works now… WOOHOO ^^
    Thanks alot for sharing that script!

  • Artur Barseghyan

    Hey Sayf. I’m testing your code with official google analytics tool and I don’t seem to get any tracking when clicking youtube videos. All scripts are placed in the head. Also, on this page it doesn’t work either, since at the moment your CDN is down. Did you try it very recently?

  • Artur Barseghyan

    More about this. Likely, in my case, the YouTube video is covered by some transparent element which prevents the tracking. I didn’t find the solution yet. At the moment when I remove all the CSS declarations, the script starts working. I did try to set z-index of the iframe to 999999 and the wmode to opaque or transparent. None of those tricks worked. Do you have any tips? Thanks!

  • Christian

    I end up with a couple errors in chrome that prevent the API events from firing. Any suggestions

    Uncaught SecurityError: Blocked a frame with origin “http://www.youtube.com” from accessing a frame with origin “http://www.domain.com”. Protocols, domains, and ports must match.

    Uncaught TypeError: Cannot read property ‘classList’ of null

  • http://stripes.com Hao

    Hi Sayf,
    Thank you for your script! I put your script in head of our velocity template file, then play the youtube video in this url http://www.stripes.com/forging-honor-how-the-military-medals-are-made-1.225411, then I check in Google analytics. I could not see the event in Top Events, could you tell me on this?

  • Sayf Sharif

    hey guys and gals,

    Something appears to have changed again and it’s not working as intended. I am looking into it.

  • ksampath

    Hi Sayf,
    I added this to the blog using Google Tag Manager. The script is firing as it should but when i see the network section in google developer’s tools it shows a 404 error to fetch the JS. What is happening is, say for eg it is hosted in example.com/js/lunametrics-youtube-v5.js(i tested the url and it is returning a 200.). But when the browser loads it adds the page of that url and then this script url. Say i was browsing on example.com/foo.html then it the browser tries to find the script on example.com/foo.html/example.com/js/lunametrics-youtube-v5.js(obviously there is no suck url like this and hence it returns a 404). Any idea why?

  • http://www.ifactorconsulting.com jake

    Hi Sayf,

    Thanks for the code. I put it in my wordpress site’s header.php file a few days ago, but I’m not seeing new events appear in my Google Analytics dashboard. Was I supposed to do anything in GA, or did I miss a step?

    Thanks again

  • Sayf Sharif

    Hey, as I mentioned there is something currently going on and the code might not be working. I am investigating. If anyone else finds a solution please post it here.

  • Mick

    Thanks for your script. Each time i try to track something with an event, I have the following warning : ReferenceError: ga is not defined
    Thanks for help

  • Sayf Sharif

    Mick you might be using the wrong tracker? if you are using asynchronous tracking you need the async include, not the universal one.

  • Steve Austin

    Hi Sayf,

    I have 2 issues with this.

    1) Up until today, it works (albeit inconsistently) across different browsers.
    To summarise: Google Chrome – works fine for direct youtube in-page embeds and when embedded into rotating panels, Firefox – works fine direct page embed but not always when embedded within rotating panels, IE – intermittent and unpredictable

    2) The second issue brought to attention only today is that the tracking was reported to not be working at all now. After debugging in Firefox I noticed that the onYouTubeIframeAPIReady() method is very rarely being invoked, therefore the tracking results are also rarely triggered.

    Any suggestions would be greatly appreciated.

    The code I am using is below (apologies for the commented out lines of code):

    YouTube Analytics
    Code adapted from:
    Code adapted by Alex Mueller for ISITE Design http://isitedesign.com

    // enable cross-domain scripting in IE -1) {
    // …remove the extra characters
    videoID = videoID.substr(0, videoID.indexOf(‘?’));

    // put an object in our array with the videoID…
    videoArray[i] = {};
    videoArray[i].id = videoID;

    // …and the video title (pulled from the YouTube data API)
    dataType: ‘JSON’,
    type: ‘GET’,
    url: url
    .done(function(data) {
    videoArray[i].title = data.entry.title.$t;

    // put the videoID on the iframe as its id
    $iframe.attr(‘id’, videoID);

    $(function() {
    // initiate tracking on document ready

    //may not be needed – check everything reloaded when MSP including video is clicked
    // $(‘a[href^=”http://#$$”]’).click(function () {
    // var listItem = $(this).parent();
    // //alert(listItem[0].nodeName.toLowerCase());
    // var idx = $(‘ul.tabs li’).index(listItem);
    // var slctdTab = $(‘.tabbed-box .tabbed-content:eq(‘+idx+’)’);
    // if ((slctdTab).find(‘iframe[src*=”youtube”]’).length) {
    // alert(‘youtube vid found’);
    // trackYouTube();
    // }
    // });


    // when the YouTube iframe API has loaded
    function onYouTubeIframeAPIReady() {
    // insert YouTube Player objects into our playerArray
    for (var i = 0; i < videoArray.length; i++) {
    playerArray[i] = new YT.Player(videoArray[i].id, {
    events: {
    //'onReady': onPlayerReady,
    'onStateChange': onPlayerStateChange

    // when the player changes states
    function onPlayerStateChange(event) {
    var videoIndex = event.target.id – 1;

    // if the video begins playing, send the event
    if (event.data == YT.PlayerState.PLAYING) {
    _gaq.push(['_trackEvent', 'Videos', 'Play', videoArray[videoIndex].title]);
    videoPlaybackInProgress = true;
    // if the video paused, send the event
    if (event.data == YT.PlayerState.PAUSED) {
    //_gaq.push(['_trackEvent', 'Videos', 'Paused', videoArray[videoIndex].title]);
    //alert('video paused');
    // if the video ends, send the event
    if (event.data == YT.PlayerState.ENDED) {
    _gaq.push(['_trackEvent', 'Videos', 'Ended', videoArray[videoIndex].title]);

    function onPlayerReady(event) {

  • Sayf Sharif


    Something changed in the process, and now the script isn’t working, or isn’t working consistently. We are investigating a fix, but as of right now this code is definitely not working. If you figure something out please come back and post it here and we can incorporate it!

  • giovanni

    @Sayf Sharif did you find a solution?

    What happens in my case is:
    the ‘onPlayerReady’ callback of the object YT.player is executed (on the video’s event ‘onReadh’) but the callback ‘onPlayerStateChange’ (that should be executed on the event ‘onStateChange’ when a user plays the video) is never executed

    It may be a chane in youtube player api. I”m investigating.

  • Sayf Sharif

    No solution yet. I do think the youtube api changed though.

  • Sayf Sharif

    I’ve updated the code to version 6, available at https://github.com/lunametrics/youtube-google-analytics

    We’ve been closing comments on older blog posts for anti-spam reasons, but if you have any questions or comments, or problems, please email me at sharif@www.lunametrics.com

  • Sabrina

    Would it matter that I’m implementing the GitHub code through WordPress? Added the min.js code to my Custom JS space in my template with the extra jquery lines with my website domain replacing “yourwebsitehere.com”, leaving everything else the same….and I dont think its working. Do I need to be adding something like onclick = “_gaq.push… in my GA? Help!

    • Sayf Sharif

      Sabrina, Sorry I”m just seeing this now, we upgraded to disqus and I missed several comments. If you are still having problems please email me at sharif@lunametrics.com and I’ll see if I can help you.

  • Jonathan Davis

    Are you going to add back in the duration events anytime soon?

Contact Us.


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

Follow Us




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