• Courses
    • Courses
    • Course bundles
  • Blog
  • Services
  • Resources
    • Youtube channel
    • E-books and Guides
    • GTM Recipes
    • View All Resources
    • GTM Community
    • GA4 community
  • About
    • About
    • Contact
  • Login
  • Courses
    • Courses
    • Course bundles
  • Blog
  • Services
  • Resources
    • Youtube channel
    • E-books and Guides
    • GTM Recipes
    • View All Resources
    • GTM Community
    • GA4 community
  • About
    • About
    • Contact
  • Login

September 3, 2020

How to Track HTML5 Audio Player with Google Tag Manager and GA

Updated: November 15th. I guess that the majority of the GTM community is familiar with a custom event listener that probably already has the status of legendary. Even this Twitter (that I saw today in my feed) confirmed this:

Yes, I’m talking about David Vallejo’s HTML5 video listener that is used to track almost any other video player that is not Youtube or Vimeo (or anything else in the iFrame). You can also find a GTM recipe here.

But today’s blog post is not about the video.

Note: this blog post teaches how to track events with Universal Analytics. If you want to get familiar with event tracking in Google Analytics 4, you can also refer to this blog post.

 

Table of Contents

  • Media events
  • HTML5 audio listener for GTM (a.k.a. one word can make a difference)
  • Requirements for this solution to work
  • So how do we actually track HTML5 audio player with GTM?
    • #1. Custom HTML tag
      • #1.1. Create a Custom JavaScript variable
      • #1.2. Create a trigger that activates the listener only when the audio player is present
    • #2. Custom Event Trigger and Data Layer Variables
    • #3. Google Analytics event tag
    • #4. Let’s test
  • Google Tag Manager Recipe
  • How to track HTML5 audio player with Google Tag Manager: Final words

 

Video tutorial

If you prefer video tutorials instead, you can watch a video here. However, to fully understand the concept of audio tracking, I recommend doing both: reading this article and watching the tutorial.

 

Media events

Some time ago, I discovered a thing called Media events (I’m still in the very beginning of my JavaScript journey, so pardon my ignorance). It turned out that there is a bunch of interactions that can be tracked (e.g. play, pause, etc.) on video players (and audios as well). David’s listener catches those very exact events and pushes them to the Data Layer.

But his listener does that only for HTML5 video players. Audio is not supported.

Unless… you change one word in his code. Literally, one word.

P.S. In the final result, there will be more words changed (but it was done just to match the proper naming convention). But in order to just start listening to audio events, it’s enough to change one word in David’s code.

Subscribe and Get the Ebook - Real Book Img - GTM for Beginners

HTML5 audio listener for GTM (a.k.a. one word can make a difference)

Let’s take a quick look at David’s listener code. Since there are no numbers of code lines, you should be looking somewhere at 60% mark of his code.

Spot this line:

var videos = document.getElementsByTagName('video');

It means that the code is looking for elements that are using the HTML tag <video> and will start listening to their events. If we go back to the MDN’s documentation about media events, you’ll see that those interactions are supported by <video> and <audio> elements.

So that one word that we need to change is video.

That is the minimum you need to do in order to adapt the listener to HTML5 audio. But to keep things tidy and to have the proper naming convention, I changed more words (for example, I’ve replaced all other “video” words in the code and changed it to “audio”).

So, the final result of the HTML5 audio listener for Google Tag Manager is this:

<script>
// This listener is based on David Vallejo's HTML5 video listener, thyngster.com/tracking-html5-videos-gtm/
// Edited by Julius Fedorovicius, analyticsmania.com

  // Let's wrap everything inside a function so variables are not defined as globals 
(function() {
    // This is gonna our percent buckets ( 10%-90% ) 
    var divisor = 10;
    // We're going to save our players status on this object. 
    var audios_status = {};
    // This is the funcion that is gonna handle the event sent by the player listeners 
    function eventHandler(e) {
        switch (e.type) {
            // This event type is sent everytime the player updated it's current time, 
            // We're using for the % of the audio played. 
        case 'timeupdate':
            // Let's set the save the current player's audio time in our status object 
            audios_status[e.target.id].current = Math.round(e.target.currentTime);
            // We just want to send the percent events once 
            var pct = Math.floor(100 * audios_status[e.target.id].current / e.target.duration);
            for (var j in audios_status[e.target.id]._progress_markers) {
                if (pct >= j && j > audios_status[e.target.id].greatest_marker) {
                    audios_status[e.target.id].greatest_marker = j;
                }
            }
            // current bucket hasn't been already sent to GA?, let's push it to GTM
            if (audios_status[e.target.id].greatest_marker && !audios_status[e.target.id]._progress_markers[audios_status[e.target.id].greatest_marker]) {
                audios_status[e.target.id]._progress_markers[audios_status[e.target.id].greatest_marker] = true;
                dataLayer.push({
                    'event': 'audio',
                    'audioPlayerAction': 'Progress %' + audios_status[e.target.id].greatest_marker,
                    // We are using sanitizing the current audio src string, and getting just the audio name part
                    'audioTitle': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1])
                });
            }
            break;
            // This event is fired when user's click on the play button
        case 'play':
            dataLayer.push({
                'event': 'audio',
                'audioPlayerAction': 'play',
                'audioTitle': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1])
            });
            break;
            // This event is fied when user's click on the pause button
        case 'pause':
            dataLayer.push({
                'event': 'audio',
                'audioPlayerAction': 'pause',
                'audioTitle': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1]),
                'audioValue': audios_status[e.target.id].current
            });
            break;
            // If the user ends playing the audio, an Finish audio will be pushed ( This equals to % played = 100 )  
        case 'ended':
            dataLayer.push({
                'event': 'audio',
                'audioPlayerAction': 'finished',
                'audioTitle': decodeURIComponent(e.target.currentSrc.split('/')[e.target.currentSrc.split('/').length - 1])
            });
            break;
        default:
            break;
        }
    }
    // We need to configure the listeners
    // Let's grab all the the "audio" objects on the current page     
    var audios = document.getElementsByTagName('audio');
    for (var i = 0; i < audios.length; i++) {
        // In order to have some id to reference in our status object, we are adding an id to the audio objects
        // that don't have an id attribute. 
        var audioTagId;
        if (!audios[i].getAttribute('id')) {
            // Generate a random alphanumeric string to use is as the id
            audioTagId = 'html5_audio_' + Math.random().toString(36).slice(2);
            audios[i].setAttribute('id', audioTagId);
        }// Current audio has alredy a id attribute, then let's use it ?
        else {
            audioTagId = audios[i].getAttribute('id');
        }
        // audio Status Object declaration  
        audios_status[audioTagId] = {};
        // We'll save the highest percent mark played by the user in the current audio.
        audios_status[audioTagId].greatest_marker = 0;
        // Let's set the progress markers, so we can know afterwards which ones have been already sent.
        audios_status[audioTagId]._progress_markers = {};
        for (j = 0; j < 100; j++) {
            audios_status[audioTagId].progress_point = divisor * Math.floor(j / divisor);
            audios_status[audioTagId]._progress_markers[audios_status[audioTagId].progress_point] = false;
        }
        // On page DOM, all players currentTime is 0 
        audios_status[audioTagId].current = 0;
        // Now we're setting the event listeners. 
        audios[i].addEventListener("play", eventHandler, false);
        audios[i].addEventListener("pause", eventHandler, false);
        audios[i].addEventListener("ended", eventHandler, false);
        audios[i].addEventListener("timeupdate", eventHandler, false);
    }
})();
</script>

 

Requirements for this solution to work

This listener supports only those audio players embedded on a page that:

  • Are not in the iFrame
  • Use the <audio> HTML tag

Both of these conditions must be met. If the listener is indeed not working (and you don’t see the audio events in GTM’s preview and debug mode, inspect the player and most likely you will see that there is no <audio> tag on a page or that you’re dealing with an iframe.

As for the audio player, just open your browser’s developer tools, go to the “Elements” tab (a.k.a. “DOM Inspector”) and do a quick search (e.g. CTRL + F). In the search field, enter “<audio” (without quotation marks, and I intentionally skipped the > sign). If it returns 0 results, you’re out of luck.

In fact, for some reason, it is quite common for audio players to be built by not using the <audio> tag. At least, that’s what I’ve noticed. So if your website utilizes some way-too-fancy audio player, well, this guide is not for you, sorry.

As for the iFrame, you should inspect the audio player, climb the element tree (DOM tree) and see if there isn’t an <iframe> somewhere along the way.

 

So how do we actually track HTML5 audio player with GTM?

Compared to HTML5 video tracking, the process of tracking the audio player is quite the same:

  1. Implement the HTML5 audio player listener (with a Custom HTML tag)
  2. Create Custom Event Trigger and Data Layer Variables
  3. Create a Google Analytics tag that will send the audio player data to GA
  4. Test

 

#1. Custom HTML tag

First, we need to activate the HTML5 audio player listener on a page. Since this is a custom solution, this must be done with a Custom HTML tag. So go to GTM > Tags > New > Custom HTML and paste the aforementioned code.

When should you activate this listener? There are two possible answers:

  • If you have A LOT of pages with audio players, you can set that Custom HTML tag to simply fire on DOM Ready trigger (you’ll need to create that by yourself).
  • If you have a listener just on certain pages, we can follow the usual practice, activate the Listener only on those pages where audio players actually exist (a.k.a. HTML element <audio> is present).
Subscribe and Get the Ebook - Real Book Img - GTM for Beginners

#1.1. Create a Custom JavaScript variable

It will return true if <audio> element is present on a page. If not, then you’ll get false. This variable will be used in a trigger that decides whether to activate the Custom HTML tag (listener) or not.

In GTM, go to Variables > Scroll down to User-defined Variables > Custom JavaScript and paste the following code:

function() {
  return (document.getElementsByTagName('audio').length > 0) ? true : false;
}

We can name the variable cjs – audio player is on a page

 

#1.2. Create a trigger that activates the listener only when the audio player is present

In Google Tag Manager, go to Triggers > New > DOM Ready. We want it to fire not on all DOM Ready events but just on those, when previously created cjs – audio player is on a page variable returns true.

In other words, if the HTML5 audio player is actually on a page, only then the Custom HTML tag will be activated.

Assign this trigger to the Custom HTML tag.

 

#2. Custom Event Trigger and Data Layer Variables

After you create the HTML tag (with the listener code) and add a trigger to it, save everything, enable the Preview and Debug mode and go to the website you’re working on (I mean where the audio player is present).

Refresh that page (the Preview and Debug mode should appear).

Click the DOM Ready event on the left side and check whether the Custom HTML tag has fired. If yes, that’s good. This is exactly what you should expect. If the Custom HTML tag has fired, this means that the audio player is present. Once you start interacting with the player, some new events will start appearing in the Preview and Debug panel.

Those events are possible because the listener is doing its job, it listens to player interactions and then sends them to the Data Layer so that GTM could be informed.

Anyway, once the Custom HTML tag has fired, click Play in the audio player, you should see a new audio event in the Preview and Debug mode, then click Pause.

If you let the player play and you’ll see even more events (e.g. every 10% of the audio length, a new event will be pushed. Also, pause, play, finished events are supported).

Click any of the audio events and go to the Data Layer tab. You’ll see some useful data related to that audio player, like audioPlayerAction and audioTitle.

Even though this data is visible in the Preview mode, you cannot use them as triggers or variables, unless you specifically instruct GTM to do so. This can be done by creating the Custom Event trigger and several Data Layer Variables. So let’s do that.

Go to Triggers > New > Custom event and enter the following settings:

Then let’s create two Data Layer Variables. Remember, those settings are case-sensitive.

  

I didn’t create the audioValue variable because I don’t use it (but you can). It returns the threshold (in seconds) of where the video was paused (at least, I think so).

 

#3. Google Analytics event tag

Next step, let’s send the audio player event data to Google Analytics. In GTM, go to Tags > New > Universal Analytics and enter the following settings:

If you have given different names to Data Layer Variables, then enter those exact names in the GA event tag’s settings.

In triggering section of the tag, click anywhere and add the Custom Event trigger we’ve created in the previous chapter of this blog post.

 

#4. Let’s test

So here’s what was done so far:

  • A Custom HTML tag was created that contains the HTML5 audio player listener. I will fire either on all pages or only on those pages where the audio player is present (thanks for the Custom JS variable). It’s up to you which option to choose.
  • Custom Event Trigger and Data Layer Variables were created in order to catch everything that the audio player is listener is pushing to the Data Layer.
  • GA Event tag was created and it will be fired every time an event called audio is dispatched by the audio player listener. That event tag will transfer the values of audioPlayerAction and audioTitle.

Enable the GTM Preview and Debug mode, refresh the page with the audio player.

Start interacting with the player, e.g. click the Play button. The expected result:

  • audio event will appear on the left side of the Preview and Debug mode
  • Click it and you should see the GA Event tag being fired

If everything is good, go to your GA Real-time reports > Events. Check whether those events are also visible there. If not, read this guide for some ideas on how to troubleshoot.

That’s it! You’re good to go with this solution. Just remember, if you don’t see audio events in the Preview and Debug mode, most likely, your player is not built with the <audio> HTML element or is in the iFrame. Then this guide will not help you.

However, if your player is not in the iFrame and uses the <audio> tag, then you could try changing the Listener’s trigger from DOM Ready to Window Loaded.

 

Google Tag Manager Recipe

To save you some time, here is a ready-made GTM recipe. Click this link, download the file, follow the instructions and start tracking.

 

How to track HTML5 audio player with Google Tag Manager: Final words

So there you have it. With a small tweak in the already existing solution, we managed to start tracking a different set of interactions on a page, HTML5 audio player. This wouldn’t have been possible without the brilliant David Vallejo’s HTML5 video listener code.

Here is the list of items that needed to be done in order to manually configure this:

  • HTML5 audio player listener is implemented via Custom HTML tag
  • Custom Event Trigger was created that catches the audio events
  • Data Layer Variables were created that fetch the audioPlayerAction and audioTitle values from the Data Layer. Those values appear there because the listener does so
  • Finally, Google Analytics tag was created that fires every time an audio event happens in the Data Layer. The tag also sends the values of audioPlayerAction and audioTitle.
Google Tag Manager Ebook Bundle
Julius Fedorovicius
In Google Tag Manager Recipes Google Tag Manager Tips
15 COMMENTS
Ralph Keser
  • Oct 14 2019
  • Reply

Hi Julius,

thanks for the great article. I was looking for a solution to track play and download. And the play event is implemented. But who can I track downloads?

Thanks and Greetings
Ralph

Ralph Keser
  • Oct 14 2019
  • Reply

Hi Julius,

thanks for the great article. I was looking for a solution to track play and download. And the play event is implemented. But how can I track downloads in the controller?

Thanks and Greetings
Ralph

    Julius Fedorovicius
    • Oct 14 2019
    • Reply

    I would try using the click trigger.

Arunprabu Sivapprakasam
  • Dec 19 2019
  • Reply

Hi Julius
Is it possible to fire a trigger when the user clicks the Download button inside the Audio player?
If yes please tell me how.

    Julius Fedorovicius
    • Dec 19 2019
    • Reply

    Use regular all element clicks trigger. If that does not work, you're out of luck.

Arunprabu Sivapprakasam
  • Dec 19 2019
  • Reply

It seems I am out of Luck. :(
I have tried it already.

Maxim
  • Feb 11 2020
  • Reply

Thank you very much! It works )

Renan
  • May 7 2020
  • Reply

Hi Julius, I did everything right, but there was no ready audio gift on the left side

    Julius
    • May 8 2020
    • Reply

    Maybe the player is not html5

Kushal Agarwal
  • Nov 5 2020
  • Reply

Hi Julius

What change do i make if i onyl want to track the plays and not the progress of pause events.

Also i have multiple pages where i have the audio element but only the audio elements on the landing page are firing a GA event and not on other pages.

Junghee
  • Jan 6 2021
  • Reply

Hi Julius,

I read the article well, thank you
I've tried changing the divisor to "5" but then it only fires at 5 and then at 50, 55, 60, etc.
Do you know what problem is it?

Thanks.
Junghee

Rebecca
  • Feb 8 2021
  • Reply

Fantastic tutorial - worked perfectly to capture play on an audio link (what I'm interested in tracking).

Brad
  • Oct 14 2022
  • Reply

This works for GA4 as well. Thanks, David and Julius.

Chris
  • Oct 18 2022
  • Reply

I am having a little trouble translating this to GA4. Would you consider updating this tutorial to the new standard?

Thank you

    Julius Fedorovicius
    • Oct 26 2022
    • Reply

    Probably, but not anytime soon.

    Everything remains the same except the tag. Just use the GA4 event tag. Event name can be whatever you want, like audio_{{dlv - audioPlayerAction}}, and then send a parameter "audio_file" of which value is another data layer variable.

    I would highly recommend investing more time into understanding how GTM and GA4 works. Your goal should be to understand the things under the hood (so that you would be able to build/troubleshoot similar things yourself). Otherwise, people just get stuck when a tutorial slightly does not match the current interface.

Leave a comment Cancel reply

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

 

Hi, I'm Julius Fedorovicius and I'm here to help you learn Google Tag Manager and Google Analytics. Join thousands of other digital marketers and digital analysts in this exciting journey. Read more
Analytics Mania
  • Google Tag Manager Courses
  • Google Tag Manager Recipes
  • Google Tag Manager Resources
  • Google Tag Manager Community
  • Login to courses
Follow Analytics Mania
  • Subscribe to newsletter
Recent Posts
  • Introduction to Google Tag Manager Server-side Tagging
  • 3 Ways to Pull Data from Data Layer with Google Tag Manager
  • Cannot See the Google Tag Manager Option in Google Ads Conversion?
Analytics Mania - Google Tag Manager and Google Analytics Blog | Privacy Policy
Manage Cookie Settings