YouTube video tracking in Google Tag Manager
Google Tag Manager for WordPress can report how your visitors watch the YouTube videos embedded on your site. Starting playback, pausing, buffering and reaching the end all become data layer events that you can use as triggers in Google Tag Manager.
Read the next section before you set this up. Google Tag Manager now measures YouTube playback on its own, and for a new setup that is the better route.
This page describes GTM4WP 2.0.0 and newer. Features introduced by that release are marked New in 2.0.0. Where the legacy 1.x versions of the plugin behaved differently, the older behavior is marked with a bold GTM4WP 1.x: lead-in.
New in 2.0.0. This option is deprecated and carries a Deprecated badge in the plugin settings. It still works and is still maintained, but it receives no new development.
Consider the native Google Tag Manager trigger instead
Google Tag Manager has a YouTube Video trigger of its own. It measures starts, completions, pauses and progress without any help from this plugin, Google maintains it, and it fills the built-in Video variables directly. In Google Tag Manager, create a trigger of type YouTube Video, tick the events you want to capture, and tick the option that adds JavaScript API support to all YouTube videos so the trigger can also control players embedded without it.
The GTM4WP option still earns its place in two cases: your container already reads the gtm4wp.media event names and you do not want to rebuild those triggers, or you track several players and prefer one set of triggers that covers all of them. Do not run both at once. Each play would be measured twice.
Turning YouTube tracking on
Open the plugin settings, go to the Media events section, expand the Media players group and check YouTube video events. The option is switched off by default.
Which embeds are detected
The tracker wires every iframe on the page whose src begins with https://www.youtube.com/embed. Where that iframe came from does not matter: a video in your post content, in a widget, in a footer, in a page builder template or in an archive listing is treated the same way.
GTM4WP 1.x: the tracker was only loaded when the post being viewed had a YouTube address in its own content. That dropped every embed which did not live in the main post body, so a video in a widget or a template went unmeasured. The check is gone: whether a page has a player can only be answered once the page has been built, and the plugin now asks that question in the browser instead.
Privacy enhanced embeds served from youtube-nocookie.com do not match that address and are not tracked.
The YouTube iframe API only accepts commands from a player that was embedded with enablejsapi=1, so the plugin adds that parameter together with an origin parameter. It does so twice over: once on the server when WordPress builds the embed code, and again in the browser for any player iframe that still lacks it. If the address carries a fragment, the parameters go in front of it, since anything after a # never reaches YouTube at all.
The API itself is only requested once the tracker has actually found a YouTube player on the page, so a page without one never contacts YouTube.
A video that is in the page when it loads is wired straight away. A video inserted later, for example in a popup, a lightbox or a section loaded by AJAX, needs the Track dynamically inserted players option in the Advanced group as well.
Playback states
The gtm4wp.mediaPlayerStateChange event fires with these values in the mediaPlayerState variable:
| mediaPlayerState | Fires when |
|---|---|
play | The video starts playing. |
pause | The visitor pauses the video. |
buffering | The player is buffering. |
ended | The video reaches its end. |
cued | A video has been loaded and is ready to play. |
unstarted | The player reports that the video has not started. |
unknown | The player reports a state the plugin does not recognize. |
YouTube reports no seek event of its own, so there is no seeked state here. Jumping to another position usually shows up as a buffering state followed by play.
Player events
The gtm4wp.mediaPlayerEvent event carries the name of the event in the mediaPlayerEvent variable and the accompanying value in mediaPlayerEventParam.
| mediaPlayerEvent | mediaPlayerEventParam |
|---|---|
quality-change | The playback quality the player switched to. |
ratechange | The new playback rate. |
error | The error code reported by YouTube. |
api-change | Reports that the player loaded or unloaded a module that exposes API methods. |
The gtm4wp.mediaApiReady event
YouTube is the only player that fires gtm4wp.mediaApiReady. It is pushed once per page, when the YouTube iframe API has finished loading and before any individual player is wired. No video is involved at that point, so the event carries mediaType and nothing else, and it is the one media event that does not fill the built-in Video variables.
What mediaData holds for a YouTube video
| Variable | Contents |
|---|---|
mediaData.id | The YouTube video ID. |
mediaData.author | The name of the channel that published the video. YouTube is one of only four players that report this. |
mediaData.title | The title of the video, as reported by the player. |
mediaData.url | The watch URL of the video. |
mediaData.duration | The length of the video in seconds. |
The mediaType variable is youtube in every event.
Google Tag Manager built-in Video variables
New in 2.0.0. Every YouTube media event except gtm4wp.mediaApiReady also populates the built-in Video variables of Google Tag Manager, with Video Provider set to youtube. The section on built-in Video variables explains how to enable and use them.
The cued, unstarted and unknown states have no counterpart in Google Tag Manager, so Video Status is empty for all three. Read mediaPlayerState when you need to tell them apart.
Video Visible is measured on the player iframe, so it reports whether that video was on screen when the event fired. See Video Visible on the hub page for exactly what is and is not detected.
Building a trigger in Google Tag Manager
To fire a tag when a visitor starts a YouTube video:
- Create a Data Layer Variable named
mediaPlayerState. - Create a Custom Event trigger whose event name is
gtm4wp.mediaPlayerStateChange. - Add the condition
mediaPlayerStateequalsplayto the trigger. - Attach the trigger to your tag. To send the title of the video along with it, create a second Data Layer Variable named
mediaData.title.
Use ended in place of play to measure a video that was watched to the end. To measure progress, build the trigger on gtm4wp.mediaPlaybackPercentage and add a condition on mediaPercentage instead.
Limitations
- The option is deprecated. Google Tag Manager measures YouTube natively, and that route gets the ongoing development.
- Privacy enhanced embeds on
youtube-nocookie.comare not detected. - The tracker claims the global
onYouTubeIframeAPIReadycallback that the YouTube API calls when it loads. Only one script on a page can own it. If another plugin or a Google Tag Manager tag has already defined it, GTM4WP stops with an error and no YouTube tracking happens at all. - There is no
seekedstate, because the YouTube API reports no seek event. - Progress is measured by asking the player for its position once a second while it plays, so a milestone can land a fraction of a second after the visitor passes it.
- There is no 100 percent milestone. Measure a full watch with the
endedstate, as described under playback percentage milestones.
Related pages
The overview of media player tracking describes the events, data layer variables and playback milestones that every player shares. See also Vimeo, the other widely used video host, and dynamically inserted players if your videos open in a popup or a lightbox.

