Track audio plays in Google Analytics 4 on WordPress: a plugin you can build today

· 5 min read

Running an audio site without knowing what people actually listen to means publishing in the dark. WordPress handles the player and GA4 handles the data, but the two do not talk to each other out of the box. GA4 records pageviews reliably. It does not record whether anyone clicked play, how far they got, or whether they stayed until the end.

MonsterInsights Pro includes media tracking as part of a full analytics suite. If you are already using MonsterInsights for ecommerce reports, form conversions, or scroll depth, the audio tracking comes along for the ride and switching it on costs nothing extra. If you installed GA4 with Site Kit and you just need it to know when someone presses play, you are paying for a large plugin to add one JavaScript event listener.

The plugin described here adds a settings field for your GA4 Measurement ID and a script that attaches to every HTML5 audio element on your site. When a visitor plays, pauses, or finishes a track, a GA4 event fires with the audio title and source URL. That is the complete scope.

What one build gives you

  • Fires audio_play with the track title and URL when playback starts on any HTML5 audio element
  • Fires audio_pause when a visitor pauses and audio_complete when the track reaches the end
  • Works with WordPress's built-in audio block and playlist block
  • Settings screen under Settings > Audio Analytics for the GA4 Measurement ID
  • Loads the Google tag directly: no Site Kit or other analytics plugin required

What it does not do

  • Playback milestone events at 25, 50, or 75 per cent completion
  • Audio players rendered by podcast plugins that do not use a plain HTML5 audio element
  • Per-listener or logged-in user attribution
  • Video tracking of any kind
  • Playlist navigation events when a visitor skips to a different track mid-session

MonsterInsights does these. This covers the part most sites use.

The prompt

Loads into the composer so you can edit it first. Nothing is built, and nothing is charged, until you send it.

Build a WordPress plugin called Simple Audio Analytics. Plugin Name: Simple Audio Analytics. Description: Fires GA4 events when visitors play, pause, or finish HTML5 audio elements on WordPress pages. Single PHP file. Register a settings group using register_setting with option group audio_analytics and option name audio_analytics_settings. Add a settings page using add_options_page with page title Audio Analytics, menu title Audio Analytics, capability manage_options, and slug audio-analytics. In the settings page callback, output a form with method post posting to options.php. Call settings_fields with audio_analytics. Output a table with one row: a label for audio_analytics_settings[measurement_id], a text input with name audio_analytics_settings[measurement_id] and value set to esc_attr of the current option, and a description paragraph reading Your GA4 Measurement ID in the format G-XXXXXXXXXX. Add a submit button using get_submit_button. Register a settings section with id audio_analytics_main on page audio-analytics. Register a settings field for measurement_id on that page and section. Hook into wp_footer at priority 20. In the callback, get measurement_id from get_option('audio_analytics_settings')['measurement_id'] and pass it through esc_js. If it is empty, return early. Output a script tag with async attribute and src set to https://www.googletagmanager.com/gtag/js?id= followed by the measurement ID. Then output an inline script block that: declares window.dataLayer as window.dataLayer or an empty array, declares the gtag function pushing arguments to dataLayer, calls gtag js with new Date(), calls gtag config with the measurement ID and {send_page_view: false}. After the config call, add a DOMContentLoaded event listener that: calls document.querySelectorAll('audio'), loops the resulting elements, and for each adds three event listeners. On play: call gtag event audio_play with parameters audio_title set to element.title if truthy or else the last segment of element.currentSrc split on slash, and audio_url set to element.currentSrc. On pause: call gtag event audio_pause with the same parameters. On ended: call gtag event audio_complete with the same parameters.

Build this pluginAbout 55 credits · the free plan includes enough for one

What GA4 tracks by default and what it misses

GA4's enhanced measurement handles pageviews, scrolls, outbound link clicks, site search, form interactions, and video engagement. The video engagement events cover embedded YouTube players specifically. They do not apply to HTML5 audio elements hosted on your own server or a CDN.

For an audio drama site with thirty episodes, the pageview count tells you someone visited the episode page. It says nothing about whether they pressed play, listened to two minutes, or made it to the end. Those questions live at the level of the audio element itself, and GA4 does not touch it without custom events.

The gap is a small one: attaching JavaScript event listeners to audio elements and calling gtag when they fire. It does not justify a large analytics plugin unless you were going to use the rest of one anyway.

How the events reach GA4

On every page load, a small script scans the DOM for audio elements. WordPress's built-in audio block renders one of these. The playlist block renders several. The script attaches listeners to each one when the page is ready.

When a visitor plays a track, the script fires an audio_play event with two parameters: audio_title set to the filename of the playing track, and audio_url set to the full source. Pause fires audio_pause. When the ended event triggers, the script fires audio_complete. All three appear in GA4 under Reports, then Engagement, then Events within about 24 hours of the first playback, or immediately in the Realtime view.

The plugin includes a settings screen under Settings, then Audio Analytics, where you enter your GA4 Measurement ID. The ID takes the form G-XXXXXXXXXX and is on the Data Streams page in your GA4 property. The plugin loads the Google tag directly, so no Site Kit or other analytics plugin is required.

Reading the data in GA4

The three events appear in the Events table once they have fired. To see which episodes attract the most plays, add audio_title as a custom dimension in GA4. Go to Admin, then Data Display, then Custom Dimensions, and create a new event-scoped dimension with the parameter name audio_title. It takes up to 24 hours to populate, after which you can filter the audio_play event by title to see per-episode play counts.

To surface episode completions as conversions, find audio_complete in the Events list and toggle Mark as conversion. GA4 then includes it in the Conversions report alongside any other conversion events you have defined.

Comparing audio_play and audio_complete counts for the same title gives a completion rate without any additional setup. If a show has 400 plays and 180 completes, roughly 45 per cent of listeners reach the end. That number is available the moment both events have enough data.

When MonsterInsights is the better answer

If you are already using MonsterInsights for any reason, its media tracking covers audio alongside video and requires no separate plugin. The MonsterInsights dashboard surfaces a Media report with play counts, percentage-played data, and a comparison across tracks. None of that requires writing a line of code.

MonsterInsights Pro also provides percentage-completion milestones: how many listeners reached 25, 50, 75, and 100 per cent of each track. The plugin described here does not include those milestones. If listener retention curves matter to how you plan content, MonsterInsights Pro is the right tool.

The case for building your own is a practical one: if you do not already pay for MonsterInsights and you only need play and completion counts, the annual cost of the full suite does not match the size of the problem.

Questions

GA4 is already installed via Site Kit. Will entering my Measurement ID here cause a conflict?

If you enter the same ID in both, GA4 receives a double pageview on each page load. To avoid this, leave the Measurement ID field blank here: the audio events will still fire through the gtag function Site Kit already loaded. Alternatively, enter the ID here and disable the GA4 snippet inside Site Kit. Confirm with the GA4 Realtime report after making any change.

Which audio players does this work with?

Any player that renders a standard HTML5 audio element. WordPress's built-in audio block and playlist block both do. Podcast plugins such as Seriously Simple Podcasting and PowerPress use custom players that may not expose a plain audio tag. Check the page source for an audio element before assuming the plugin will detect the player.

No events are appearing in GA4. What should I check?

Three things: confirm the Measurement ID matches your GA4 Data Stream exactly; check the Realtime report during testing rather than the standard reports, which have a 24-48 hour delay; open the browser console and look for JavaScript errors when you press play. An ad blocker can also suppress gtag calls.

Can I track how far into a track someone listened?

Not with this build. Percentage-completion milestones require monitoring the currentTime and duration on a timeupdate listener and firing each threshold exactly once per session. Ask Steem to extend the plugin with milestone tracking once the basic events are running.

Does this add anything visible to the page?

No. The plugin outputs two script tags in the page footer and attaches event listeners to audio elements. Visitors see nothing different.

The prompt

Loads into the composer so you can edit it first. Nothing is built, and nothing is charged, until you send it.

Build a WordPress plugin called Simple Audio Analytics. Plugin Name: Simple Audio Analytics. Description: Fires GA4 events when visitors play, pause, or finish HTML5 audio elements on WordPress pages. Single PHP file. Register a settings group using register_setting with option group audio_analytics and option name audio_analytics_settings. Add a settings page using add_options_page with page title Audio Analytics, menu title Audio Analytics, capability manage_options, and slug audio-analytics. In the settings page callback, output a form with method post posting to options.php. Call settings_fields with audio_analytics. Output a table with one row: a label for audio_analytics_settings[measurement_id], a text input with name audio_analytics_settings[measurement_id] and value set to esc_attr of the current option, and a description paragraph reading Your GA4 Measurement ID in the format G-XXXXXXXXXX. Add a submit button using get_submit_button. Register a settings section with id audio_analytics_main on page audio-analytics. Register a settings field for measurement_id on that page and section. Hook into wp_footer at priority 20. In the callback, get measurement_id from get_option('audio_analytics_settings')['measurement_id'] and pass it through esc_js. If it is empty, return early. Output a script tag with async attribute and src set to https://www.googletagmanager.com/gtag/js?id= followed by the measurement ID. Then output an inline script block that: declares window.dataLayer as window.dataLayer or an empty array, declares the gtag function pushing arguments to dataLayer, calls gtag js with new Date(), calls gtag config with the measurement ID and {send_page_view: false}. After the config call, add a DOMContentLoaded event listener that: calls document.querySelectorAll('audio'), loops the resulting elements, and for each adds three event listeners. On play: call gtag event audio_play with parameters audio_title set to element.title if truthy or else the last segment of element.currentSrc split on slash, and audio_url set to element.currentSrc. On pause: call gtag event audio_pause with the same parameters. On ended: call gtag event audio_complete with the same parameters.

Build this pluginAbout 55 credits · the free plan includes enough for one

Read next

Other plugins you can build this way

Each loads into the composer, ready to edit.