JWPlayer video tracking using Google Tag Manager

JWPlayer is one the most known video players (if not the most one) and today we’re going to learn how to track it using GTM (Google Tag Manager). This time we’re going to use an agnostic dataLayer pushes instead of the ones that we usually use for Google Analytics. 

We’ll be using one tag, one trigger and one variable, and in the next list we’re resuming all the events that our code will be able to track:

  • Video Plays
  • Video Pauses
  • Video Completions
  • Video Progress (Percentages to be tracked can be easily defined in the first line of the code)
  • Video Mute and UnMute
  • Video FullScreen On and FullScreen Off
  • Video Errors

As we said before we’re going to use a tool agnostic dataLayer pushes instead of focusing in the almost standard event tracking model from Google Analytics. The following object will be our video tracking data model:

    "event": "video",
    "player_id": {{VIDEO_ID}},
    "interaction": {{VIDEO_ACTION}},
    "video_url": {{VIDEO_URL}},
    "duration": {{VIDEO_DURATION}},
    "width": {{PLAYER_WIDTH}},
    "height": {{PLAYER_HEIGHT}},
    "position": {{VIDEO_CURRENT_POSITION}},
    "resolutions": {{AVAILABLE_VIDEO_QUALITIES}}, // an array
    "volume": {{PLAYER_VOLUME}},
    "player_type": {{PLAYER_TYPE}} // html5 or flash

Most important data is the event, the interacction and the video_url (as used of the most video tracking scripts), but this time we’ll be adding some extra to the dataLayer pushes to be able to track more details info if we want to.

Let’s start creating our needed configuration on Google Tag Manager. First thing that we’re going to need is to have a variable that is going to tell us if there’s any jwplayer available in the current page. We don’t want our tracking code to be injected in the page if we don’t have any video on it, do we?.



Now it’s time to configure the trigger that is going to fire our tracking tag, so we’ll be using the previously created variable, and a second condition to trigger the tracking tag after the DOMReady event:



Let’s configure the tracking tag, after the screenshoot you’ll find the full code so you can copy & paste it:


Tag Code

Now all the video interactions info will be pushes to the dataLayer so you’ll have all that info available to send your events to Google Analytics or any other tool you like.
Any suggestion, new tracking idea, feedback will be welcome, just leave a comment.

Author: David Vallejo

Google Analytics Consultant and implementer. I have some experience with Google Tag Manager Follow me: @thyng

30 thoughts on “JWPlayer video tracking using Google Tag Manager”

  1. Hello David,

    We just started with GTM and we are trying alot of new things. This is definitly tricky to implement but we are going to give a try.

    Did you personalize the javascript code yourself?

    We will let you know later how it went. Thanks for this 🙂

  2. in the screenshot for the variable you show “jwplayer” but in the screenshot for the trigger you show “isJWPlayerAvailable”. Is this a typo?

    1. it’s not. You need to create a variable in GTM ( named in my example as IsJWPlayerAvailable, you can name it however you want ) that read the global javascript variable named “jwplayer”.

  3. David,
    Thank you for your quick reply. I’ve completed this setup and everything is working ok except that the .onPlay action is adding a new event every time the visitor click on the play icon (which is supposed to do). However, this is inflating the real number of views a video has. Is it possible to add in the logic to only count the first time the onPlay is called?

    Example: For one video, if I click play, pause, play, pause, play pause; the results show 3 plays for the video. The more accurate number should be only one for that visitor.

    Please let me know if you can provide some insights here.

    Thanks in advance for your help.

  4. I just added a filter on the trigger to only send ‘play’ when the currentPosition was less than 3 seconds. Basically, only the first time ‘play’ is hit.

    Thanks for this coding. It helped me a lot to understand more GTM and the extra options it has to implement.

  5. Hey,

    Thanks for the guide, it was really useful.

    One question: how can i send all that info to Google Analytics as an event?

    Thanks in advance,

  6. This is lovely, David, thank you.

    One question for you – it’s more valuable for us to pull in the video’s title instead of its URL.

    getplaylistItem().file works just fine, but if I use getplaylistItem().title instead it always returns undefined.

    If I leave .title or .file off, it will pull everything available and dump it into the data layer… and even here I see things like description, title, mediaid all as “undefined”. Whereas everything else (duration, position, this.id, interaction, file) all display data just fine, as you’ve identified above.

    I’m totally at a loss and JWPlayer support is pretty much nonexistent. Do you have any light you might be able to shed on this issue?

    Much thanks!

    1. Without seeing the pages where the player is I can’t say much. To bring some idea, if you’re directly loading a video file there won’t a title for it as it won’t be defined anywhere.

      Can you please mail me with the player URL so I can take a quick look to it?

      1. Wow, that was a fast reply. I’m emailing you now – the site hasn’t launched yet (goes up tomorrow or Monday) so I can’t put it out here publicly.

  7. David,
    Are you using the datalayer because JWplayer does not support Google Tag Manager. So far, I’ve tested JW7 and have not seen any events. I was on the verge of experimenting with JW7 and Google Analytics. But I prefer to continue using GTM.

    1. I’m using a dataLayer to have an agnostic way to track the player, all info is pushed into the dataLayer, so you can fire any tool within Google Tag Manager.

      Please check if dataLayer pushes are being sent typing “dataLayer” into the browser console, if they’re there, you’re missing to setup your tags and triggers.

  8. One other question David. To validate that the event is fired, does Real-Time Events work? So far, it has not for us.


    1. If you configured GTM for sending events based of the current values sent to the datalayer it should. If you’re following the post example you should have some event tag that is fired on the event “video” . Take in mind that category and action are needed values on a event type tag.

  9. Hi David,

    I tried your instructions but it’s not working for me. When I click on my JWPlayer video, the event trigger doesn’t fire to get the information on my click. Any idea?


  10. Hi David,

    I tried a lot to your instructions but it isn’t working for me also. However when I click on JWPlayer video present on my website, the event trigger fired to get the information. But still Google Analytics is still unable to track the videos. Suggest me please what I need to do.

    If you wish I can show you each and every step (via screencast) that, has been done to track the same.

    Thanks in Advance

  11. Hi David,

    Problem: only some browsers sending data to dataLayers. I’ve tried personally – no dataLayer push, but I see that other users are pushing dataLayers, also events rules calling GA tags.
    JWP – 6.12 with ads

  12. This may be a silly question but would I replace the properties of this function? …haystack, key, needle

    function findObjectIndexById(haystack, key, needle)

    1. well, why would you need to change them? it’s a function I use to find an index name inside an object, but feel free to change them as long as you change their references inside the function.

  13. I’ve followed the steps and the plays and buttons are all tracking correctly. But it is not tracking the percentage played. Am I supposed to configure the section below to get the percentage played to be tracked?

    var i = 0;
    // Define at which percentages you want to fire an event
    var markers = [1,2,3,4,5,10,25,50,70,75,90];
    var playersMarkers = [];

  14. Hi David,

    thanks for that! I have a somewhat strange problem; I followed your instructions quite scrupulously.

    When I use the GTM debugger, I see the JWPlayer Tracking Tool firing only when there is a jwplayer (following your trigger where the variable “jwplayer” is not undefined).

    However, nothing is added to the data layer when I interact with the player, and no error message shows in the console.

    When I manually copy paste your exact code into the Javascript console, then the events are added to the data layer.

    So your script works fine when it’s pasted directly, but not when it’s obtained via the GTM – even if it is executed only when the player is present, which makes me think the trigger is working as expected.

    I use JWP 7 and the latest GTM.

    Any ideas will be welcome, I’m at a loss. Thanks!


  15. Hi David,

    thanks for this really helpful guide. It works fine for our site. But i also would like to track an embedded youtube player in the same manner. Therefore I added the variable and the Trigger for Youtube and just changed the name of the player in the skript to YT.Player so it looks like this:
    while (true) {
    var player = YT.Player(i);
    if (!player.id)
    But that doesn’t work. Do i have to make more changes? Is it possible to track an embedded YouTube Player with this skript?

    Thanks a lot!

  16. This is great and I can see the items being pushed to the dataLayer… only thing I am missing is how you push the values in the dataLayer into Google Analytics as an event using GTM?

    Maybe I missed something? Any links or articles that would help me with this would be great.

  17. Hi David,

    I’m having the same issue as Yannick – I can see JWPlayer Tracking Tool firing – but nothing is added to the datalayer. It would be great to get this working – as we use GTM and JWplayer but aren’t seeing any events at the moment. If anyone has any ideas/suggestions on getting it working recently, please let me know.


Leave a Reply

Your email address will not be published. Required fields are marked *