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

June 26, 2025

Track Spotify Player with Google Analytics 4 and Google Tag Manager

Even though GA4’s automatic tracking is more capable than the previous version (Universal Analytics), it still has its limitations. Especially if you have a niche situation, like wanting to track the usage of a Spotify player. With the help of a listener created by Tomás Foch Nalle, it’s actually pretty simple to do this.

In this tutorial, we will cover how to track Spotify Player with Google Analytics 4 and Google Tag Manager. Let’s get into it!

 

Table of Contents

Here’s what you will learn in this article

  • Add a listener to your GTM container
    • Add the listener to GTM to listen for usage of a Spotify Player
  • Send data on interactions with a Spotify player to GA4
    • Create a trigger for when a user interacts with Spotify player
    • Create Data Layer variables for additional information
    • Create a tag to track the Spotify player
  • Find Spotify Player data in GA4
  • A Caveat
  • GTM recipe for Spotify player tracking
  • Final Words
Subscribe and Get the Ebook - working with reports in ga4

Add a listener to your GTM container

A listener is a function (or a bunch of functions) that is programmed to look for certain interactions on a page and then execute code in response to that action. In this case, the listener will be looking for interactions with the Spotify player. If it detects one, it’ll push data to the data layer, and we’ll be able to see it in Preview and Debug mode.

The creator of the listener we’re using today is Tomás Foch Nalle, who was kind to share his listener with me and Analytics Mania’s readers. You can check his GitHub repository here.

The code for the listener is included below:

<script>
(function spotifyAudioListenerTag() {
  // - Edit the list below to setup Progress events detected
  // percentage values:
  var spotifyPercentagesToBeDetected = [
    10, 20, 30, 40, 50, 60, 70, 80, 90, 99
  ]
  // - The operation below is needed to ensure the list of
  // percentages to be detected as progress events follow
  // the correct format.
  spotifyPercentagesToBeDetected = (function(arr) {
    var onlyNumsTruncatedList = arr.filter(function(element) {
      return typeof element === 'number';
    }).map(function(element) {
      return Math.trunc(element);
    }).filter(function(element) {
      return element > 0 && element < 100;
    });
    var uniqueValuesObject = {};
    for (var i = 0; i < onlyNumsTruncatedList.length; i++) {
      uniqueValuesObject[onlyNumsTruncatedList[i]] = true;
    }
    var uniqueList = Object.keys(uniqueValuesObject).map(function(key) {
      return parseInt(key, 10);
    });
    uniqueList.sort(function(a, b) {
      return a - b;
    });
    return uniqueList;
  })(spotifyPercentagesToBeDetected);
  var minDetectionValue = Math.min.apply(null, spotifyPercentagesToBeDetected);

  // - Check if a calculated percentage value should or
  // not be detected.
  function shouldPercentageBeDetected(percent, detectionList) {
    for (var i = 0; i < detectionList.length; i++) {
      if (percent >= detectionList[i] && !(detectionList[i+1] && detectionList[i+1] <= percent)) {
        return { check: true, value: detectionList[i] };
      }
    }
    return { check: false, value: undefined };
  }

  window.dataLayer = window.dataLayer || [];
  var spotifyWasPaused = false;
  var spotifyRegisteredProgress = [];
  var spotifyLastDuration = 0.0;
  var spotifyLastURI = '';
  var spotifyLastEventString = '';
  sessionStorage.setItem('spotifyLastStatus', '');
  window.addEventListener('message', function(event) {
    // Leave if not a Spotify Event
    if (!(event.origin === 'https://open.spotify.com'))
      return;
    var spotifyEventString = event.data.payload
      && (JSON.stringify(event.data.payload.isPaused)
      + JSON.stringify(event.data.payload.position)
      + JSON.stringify(event.data.payload.playingUri)) || '';
    // Leave if current event is the same as last event, otherwise update
    if (spotifyEventString === spotifyLastEventString)
      return;
    else
      spotifyLastEventString = spotifyEventString;
    var audioPercent = Math.trunc((event.data.payload.position / event.data.payload.duration) * 100) || 0;
    var audioCurrentTime = (event.data.payload.position / 1000) || 0;
    var audioDuration = (event.data.payload.duration / 1000) || 0;
    var spotifyURI = event.data.payload.playingURI;
    var reSpotifyUri = /spotify:([^:]+):([^:]+)/i;
    var audioData = (function(uri) {
      var result = { contentType: '', url: '' };
      if (reSpotifyUri.test(uri)) {
        var parts = reSpotifyUri.exec(uri);
        result.contentType = parts && parts[1];
        result.url = parts && 'https://open.spotify.com/'+parts[1]+'/'+parts[2];
      }
      return result;
    })(spotifyURI);
    var spotifyEvent = {
      event: 'spotifyEvent',
      audioPercent: audioPercent,
      audioCurrentTime: audioCurrentTime,
      audioDuration: audioDuration,
      audioContentType: audioData.contentType,
      audioUrl: audioData.url,
      spotifyURI: spotifyURI
    }
    // - Detect playback restart
    if ((sessionStorage.getItem('spotifyLastStatus') === 'complete'
      && audioData.contentType !== 'episode') || event.data.type === 'playback_started')
      sessionStorage.setItem('spotifyLastStatus', 'playback_started');
    // - Detect track rewind or restart
    if (audioData.contentType === 'track' && audioPercent < minDetectionValue) {
      spotifyWasPaused = false;
      spotifyRegisteredProgress = [];
    }
    // - Restart Playback Control Variables in case URI or duration has
    // changed or a complete event has just fired (track change detection
    // within playlist, album or artist).
    if ((spotifyURI && spotifyURI !== spotifyLastURI)
      || event.data.type === 'playback_started'
      || sessionStorage.getItem('spotifyLastStatus') === 'complete'
      || (spotifyURI && spotifyURI === spotifyLastURI
        && Math.trunc(audioDuration) !== Math.trunc(spotifyLastDuration))) {
      spotifyWasPaused = false;
      spotifyRegisteredProgress = [];
    }
    // 1. Playback updates
    // 1.1. Playback Start
    if (spotifyURI && event.data.type === 'playback_started') {
      spotifyEvent.audioStatus = 'playback_started';
      window.dataLayer.push(spotifyEvent);
      spotifyLastURI = spotifyURI;
      spotifyLastStatus = spotifyEvent.audioStatus;
      // 1.2. Playback Paused
    } else if (spotifyURI && event.data.type === 'playback_update' && event.data.payload.isPaused
      && audioCurrentTime && !spotifyWasPaused) {
      spotifyEvent.audioStatus = 'playback_paused';
      window.dataLayer.push(spotifyEvent);
      spotifyLastURI = spotifyURI;
      spotifyLastDuration = audioDuration;
      spotifyWasPaused = true;
      sessionStorage.setItem('spotifyLastStatus', spotifyEvent.audioStatus);
      // 1.3. Playback Resumed
    } else if (spotifyURI && event.data.type === 'playback_update'
      && !event.data.payload.isPaused && spotifyWasPaused && event.data.payload.position) {
      spotifyEvent.audioStatus = 'playback_resumed';
      window.dataLayer.push(spotifyEvent);
      spotifyLastURI = spotifyURI;
      spotifyLastDuration = audioDuration;
      spotifyWasPaused = false;
      sessionStorage.setItem('spotifyLastStatus', spotifyEvent.audioStatus);
      // 1.4. Complete
    } else if (spotifyURI && event.data.type === 'playback_update' && audioDuration === audioCurrentTime
      && sessionStorage.getItem('spotifyLastStatus') !== 'complete') {
      spotifyEvent.audioStatus = 'complete';
      spotifyEvent.audioPercent = 100;
      window.dataLayer.push(spotifyEvent);
      spotifyLastURI = spotifyURI;
      spotifyLastDuration = audioDuration;
      sessionStorage.setItem('spotifyLastStatus', spotifyEvent.audioStatus);
    }
    // - No progress events after a complete event
    if (sessionStorage.getItem('spotifyLastStatus') === 'complete')
      return;
    // 2. Progress Events
    if (spotifyURI && shouldPercentageBeDetected(audioPercent, spotifyPercentagesToBeDetected).check) {
      if (!spotifyRegisteredProgress.includes(shouldPercentageBeDetected(audioPercent, spotifyPercentagesToBeDetected).value)) {
        spotifyRegisteredProgress.push(shouldPercentageBeDetected(audioPercent, spotifyPercentagesToBeDetected).value);
        spotifyEvent.audioStatus = 'progress';
        spotifyEvent.audioPercent = shouldPercentageBeDetected(audioPercent, spotifyPercentagesToBeDetected).value;
        window.dataLayer.push(spotifyEvent);
        spotifyLastURI = spotifyURI;
        spotifyLastDuration = audioDuration;
      }
    }
  }, false);
})();
</script>

Add the listener to GTM to listen for usage of a Spotify Player

Copy the code above, go to the Tags section in GTM and create a new tag. For the Tag configuration, select “Custom HTML“ and paste the listener code.

 

Set the listener to fire on the “All Pages” trigger, name the tag “cHTML – spotify listener” and save.

As always, we need to test the event, so go to the Preview mode and enter the URL of your site. Once a new tab/window with your site opens, click to play a song or podcast from Spotify. Now, check the Tag Assistant (GTM preview mode), and you’ll probably see multiple spotifyEvent events appearing in the left-hand tab. Click on one of these events.

Open the API Call to see the information collected in the Data Layer.

 

The audioStatus parameter will tell you more details about the specific action a user took. The three we are interested in are:

  • playback_started: When a user clicks the play button.
  • progress: Triggers every 10% of the audio from 10% to 99%.
  • complete: When a user reaches the end of a song or podcast.
Subscribe and Get the Ebook - Server-side tagging

Send data on interactions with a Spotify player to GA4

Now that the listener is sending some useful information to the Data Layer, we need to create a tag to help us collect this information and send it to Google Analytics 4.

 

Create a trigger for when a user interacts with Spotify player

For this tutorial, we will only trigger our event when the audioStatus is playback_started, progress, or complete. Therefore, we need to create a data layer variable for audioStatus, as it will indicate the user’s action.

In GTM, go to the Variables tab and select “New” under User-Defined Variables.

For the Variable configuration, select “Data Layer Variable”, enter “audioStatus” in the textbox, name the variable “dlv – audioStatus”, and save.

Now, go to the Triggers tab and create a new trigger. For the Trigger configuration, choose “Custom Event” and enter the event name “spotifyEvent” (exactly as it shows up in GTM preview mode from the previous chapter).

Since we want this to only fire on specific values of audioStatus, click “Some custom events”.

In the condition, enter: “dlv – audioStatus matches RegEx playback_started|progress|complete” (catch up on your regular expression here).

Name the trigger “custom – spotifyEvent” and save.

 

Create Data Layer variables for additional information

While you could just go into creating the tag from here, sometimes it’s nice to send some extra information with events that provide a bit more insight on exactly what the user interacted with; in this case, we can include:

  • audioPercent: This will always be 0 when audioStatus is started_payback and 100 when audioStatus is complete.
  • audioUrl: The URL to the song or podcast on Spotify.
  • audioContentType: This will be track for a song and episode for a podcast.

Again, go to Variables to create a new variable. For the Variable configuration, select “Data Layer Variable” and enter “audioPercent” for the name. Name the variable “dlv – audioPercent” and save.

Repeat this for audioURL (“dlv – audioURL”) and audioContentType (“dlv – audioURL”).

 

Create a tag to track the Spotify player

Let’s put it all together now. Create a new tag, and under the Tag configuration, select Google Analytics > Google Analytics: GA4 Event.

Paste the Measurement ID, which you can find in the GA4 config tag within the container (labelled as the Tag ID in the config tag).

For the event name, we will be sending different event names depending on the value of audioStatus. You don’t have to do this, but it can make reporting on events a bit more clear. To do this, set the event name to: audio_{{dlv – audioStatus}}.

Included with the events will be the following parameters (that we made variables for in the previous step):

  • audio_percent: {{dlv – audioPercent}}
  • audio_url: {{dlv – audioUrl}}
  • audio_type: {{dlv – audioContentType}}

Important: If you named your variables differently, then you’ll need to use different values for the event parameters.

If you want to track other parameters, you should create data layer variables for those parameters and include them in the tag, e.g., audioCurrentTime or audioContentType.

For the trigger, add the custom event trigger we created above. Name the event “GA4 event – spotify player” and save.

To make sure everything works, preview the container. Find the Spotify player on your site and listen to a song or podcast from start to finish to test that each event is working properly.

When you start the audio, the audio_playback_started will trigger. Let the audio play for a bit and check that you see the audio_progress event, and when you get to the end of the audio, the audio_playback_complete event should come through.

Click each tag to check that the parameters are as expected, too.

To see how GA4 receives this data, go to Admin > Data display > DebugView. DebugView is a tool that allows you to see real-time event data as it’s sent from your website. It displays incoming events and their parameters, making testing and troubleshooting your tracking setup easier.

Confirm you see the three events.

By clicking on the events, you can also see the parameters collected with the event under the Parameters tab.

Once everything looks good, publish the GTM container and wait 24-48 hours for data to appear in GA4!

Subscribe and Get the Ebook - Mastering GA4 event tracking

Find Spotify Player data in GA4

If you want to create reports using the audio_percent, audio_type, and audio_url parameters, you will need to create custom dimensions. This is pretty simple. In GA4, go to Admin > Data Display > Custom Dimensions. Click “Create Custom Dimension”.

There are three elements that you need to consider (you’ll need to do this for each):

  • The Dimension name is the name that will be displayed in GA4 reports, i.e., Audio Percent, Audio Type and Audio URL
  • The Event property needs to be the same name as in Google Tag Manager, i.e., audio_percent, audio_type and audio_url
  • Set the scope to “Event”

Remember, this won’t work retroactively, so make sure you do it right after publishing your container so that you have these available in GA4 as your data starts to come in.

To view the incoming data, create a GA4 Exploration by going to Explore in the left-side navigation. Click “Blank” to start a new report.

To this report, select the following dimensions, metrics and filters (click the plus sign next to the element):

  • Dimensions: Event name, Audio Percent, Audio URL and Audio Type

  • Metrics: Event count and Total users

  • Filter: Event name begins with “audio_”

We will create a report with two tabs. The first tab will just be an overview of event counts for the three different events, and the second tab will also contain all the parameters.

For the first tab, double-click on Event Name and both of the metrics to add them to the report.

Now, “Duplicate” the tab so that you don’t need to re-add the dimensions, metrics and filter.

In the second tab, double-click on each of the event parameters to add them to the report.

Remember, you can build out any report that makes the most sense to what you want to know and include any of the event parameters that you added as custom dimensions. In this next example, I want to know which URLs had the most starts and the most completes.

To do this, we want to update the filters:

  • Event name exactly matchs “audio_progress” since we only want to look at this event to see users progress through each song and podcast.
  • Audio Percent matches regex “100|0” so that we only see events the fire when a user started the song and when they got to the end.

For the Row dimensions, we just want Audio URL and in the Column dimensions, add Audio Percent. For the Metrics, just keep Event count.

This report will have three columns: one for when the percent of audio listened is 0, another for when its 100 and then the total for each row, which will show the sum of events from both columns.

Now, you can look at the how often a song or podcast is started versus finished, and see the specific tracks and episodes with the most completions.

As a bonus, you could export this report to Google Sheets and find the completion rates by diving the event count when audio progress is 100 by the event count when its 0.

 

A Caveat

Spotify’s events that we are tracking do not contain the names of the author, artist, episode, or song so reports won’t include user-friendly names. However, if the GA4 user copies and opens the Audio URL, it will actually open the song or podcast episode. So, technically, it is still possible to know which songs or episodes people are listening to.

 

GTM recipe for Spotify player tracking

Those who have been following Analytics Mania for a while know that I have compiled a library of ready-made GTM container templates (called recipes). I have added a new recipe for Spotify player tracking. Go to this page, download the needed files, and carefully read the installation/configuration instructions.

 

Track Spotify Player with Google Analytics 4 and GTM: Final Words

In the end, while GA4 is good for basic tracking, you can do even more with event listeners, like the Spotify player tracker from Tomás Foch Nalle, and custom event tracking thanks to Google Tag Manager.

By following these steps, you can easily get important info about how people use the Spotify player on your site, helping you understand what your website visitors are doing.

If you have any questions, leave them down below!

Subscribe and Get the Ebook - JavaScript for Google Tag Manager
Julius Fedorovicius
In Google Analytics Tips
1 COMMENT
Jati
  • Jun 24 2025
  • Reply

Awesome. Thanks a lot for the tips, Julius!!!

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
  • Setting up cookie consent for Microsoft Clarity (V2)
  • Conversion rate in Google Analytics 4
  • Google Tag Manager Data Layer Explained
Analytics Mania - Google Tag Manager and Google Analytics Blog | Privacy Policy
Manage Cookie Settings