{"id":135776,"date":"2025-03-15T19:30:10","date_gmt":"2025-03-15T19:30:10","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/track-dynamically-loaded-youtube-videos-in-google-tag-manager\/"},"modified":"2025-03-15T19:30:10","modified_gmt":"2025-03-15T19:30:10","slug":"track-dynamically-loaded-youtube-videos-in-google-tag-manager","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=135776","title":{"rendered":"Track Dynamically Loaded YouTube Videos In Google Tag Manager"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p>Tracking <a href=\"https:\/\/www.youtube.com\/\">YouTube<\/a> videos in <a href=\"https:\/\/tagmanager.google.com\">Google Tag Manager<\/a> is one of the more useful things you can do in terms of tracking. YouTube has a wonderful <a href=\"https:\/\/developers.google.com\/youtube\/js_api_reference?hl=en\">API<\/a> that you can tap into and convert the detected events into <code>dataLayer<\/code> messages.<\/p>\n<p>There are some really good solutions out there for tracking YouTube videos in GTM:<\/p>\n<p>Both do a great job of tracking videos that have been loaded with the page. However, both have difficulties with tracking <strong>dynamically<\/strong> loaded videos. That means videos which are loaded lazily, or in pop-ups, or when some content link is clicked.<\/p>\n<div style=\"aspect-ratio: 1986 \/ 1290;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2015\/12\/youtube-videos-dynamic-tracking.jpg\" title=\"Track youtube videos dynamically google tag manager\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1290\" width=\"1986\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2015\/12\/youtube-videos-dynamic-tracking.jpg#ZgotmplZ\" alt=\"Track youtube videos dynamically google tag manager\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In this article, I\u2019m going to show how you can track dynamically loaded videos using Bounteous\u2019 solution with slight modifications. Bounteous is my favorite group of geeks in North America, and they bribed me with their awesome book just before Christmas, which would already be reason enough to use their code. However, their solution is also all kinds of robust, and it really lends itself to tracking dynamic stuff as well.<\/p>\n<p>                <span class=\"simmer\"><br \/>\n  <span class=\"close\">X<\/span><\/p>\n<p>\n    <span class=\"fa fa-md fa-bell\"\/><br \/>\n    <strong>The Simmer Newsletter<\/strong>\n  <\/p>\n<p>\n    Subscribe to the <a href=\"https:\/\/www.simoahava.com\/newsletter\/\">Simmer newsletter<\/a> to get the latest news and content from Simo Ahava into your email inbox!\n  <\/p>\n<p>  <\/span><\/p>\n<h2 id=\"what-youll-need\">What you\u2019ll need<\/h2>\n<p>The modifications will be done to the JavaScript code in the Custom HTML Tag. In other words, you can\u2019t use <a href=\"https:\/\/www.jsdelivr.com\/projects\/youtube-google-analytics\">Bounteous\u2019 CDN<\/a> for this. You will have to create a Custom HTML Tag, and copy-paste the code in the next chapter within.<\/p>\n<p>As for the rest of the stuff, just follow Bounteous\u2019 guide. All this does is add a method you can trigger when videos have been loaded dynamically. Don\u2019t worry, I\u2019ll explain the method later on as well.<\/p>\n<h2 id=\"the-modified-custom-html-tag\">The modified Custom HTML Tag<\/h2>\n<p>So, follow the <a href=\"https:\/\/www.bounteous.com\/insights\/2015\/05\/11\/updated-youtube-tracking-google-analytics-gtm\/\">Bounteous guide<\/a>, avoiding the CDN, and when you come to the chapter titled <strong>Google Tag Manager Installation<\/strong>, read the following instead.<\/p>\n<p>Create a new Custom HTML Tag, and give it some cool name like <strong>Utility &#8211; Video Tracking Bomb Overload Christmas Awesome<\/strong>.<\/p>\n<p>Sorry for that.<\/p>\n<p>Next, add the following code.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-html\" data-lang=\"html\">script&gt;\n<span style=\"color:#aaa;font-style:italic\">\/\/ Respectfully copied and modified from \n<\/span><span style=\"color:#aaa;font-style:italic\">\/\/ https:\/\/github.com\/lunametrics\/youtube-google-analytics\n<\/span><span style=\"color:#aaa;font-style:italic\">\/\/ \n<\/span><span style=\"color:#aaa;font-style:italic\">\/\/ Original implementation by Bounteous\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> ytTracker = (<span style=\"color:#00a\">function<\/span>( <span style=\"color:#0aa\">document<\/span>, <span style=\"color:#0aa\">window<\/span>, config ) {\n\n  <span style=\"color:#a50\">'use strict'<\/span>;\n\n  <span style=\"color:#0aa\">window<\/span>.onYouTubeIframeAPIReady = (<span style=\"color:#00a\">function<\/span>() {\n    \n    <span style=\"color:#00a\">var<\/span> cached = <span style=\"color:#0aa\">window<\/span>.onYouTubeIframeAPIReady;\n\n    <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">function<\/span>() {\n        \n      <span style=\"color:#00a\">if<\/span>( cached ) {\n\n        cached.apply(<span style=\"color:#00a\">this<\/span>, arguments);\n\n      }\n\n      <span style=\"color:#aaa;font-style:italic\">\/\/ This script won't work on IE 6 or 7, so we bail at this point if we detect that UA\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>      <span style=\"color:#00a\">if<\/span>( !navigator.userAgent.match( <span style=\"color:#099\">\/MSIE [67]\\.\/gi<\/span> ) ) {\n\n        init(); \n    \n      }\n\n    };\n\n  })();\n  \n  <span style=\"color:#00a\">var<\/span> _config = config || {};\n  <span style=\"color:#00a\">var<\/span> forceSyntax = _config.forceSyntax || <span style=\"color:#099\">0<\/span>;\n  <span style=\"color:#00a\">var<\/span> dataLayerName = _config.dataLayerName || <span style=\"color:#a50\">'dataLayer'<\/span>;\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Default configuration for events\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> eventsFired = {\n    <span style=\"color:#a50\">'Play'<\/span>        : <span style=\"color:#00a\">true<\/span>,\n    <span style=\"color:#a50\">'Pause'<\/span>       : <span style=\"color:#00a\">true<\/span>,\n    <span style=\"color:#a50\">'Watch to End'<\/span>: <span style=\"color:#00a\">true<\/span>\n  };\n  \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Overwrites defaults with customizations, if any\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> key;\n  <span style=\"color:#00a\">for<\/span>( key <span style=\"color:#00a\">in<\/span> _config.events ) {\n\n    <span style=\"color:#00a\">if<\/span>( _config.events.hasOwnProperty( key ) ) {\n\n      eventsFired[ key ] = _config.events[ key ];\n\n    }\n\n  }\n  \n  <span style=\"color:#aaa;font-style:italic\">\/\/*****\/\/\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#aaa;font-style:italic\">\/\/ DO NOT EDIT ANYTHING BELOW THIS LINE EXCEPT CONFIG AT THE BOTTOM\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#aaa;font-style:italic\">\/\/*****\/\/\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Invoked by the YouTube API when it's ready\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">function<\/span> init() {\n\n    <span style=\"color:#00a\">var<\/span> iframes = <span style=\"color:#0aa\">document<\/span>.getElementsByTagName( <span style=\"color:#a50\">'iframe'<\/span> );\n    <span style=\"color:#00a\">var<\/span> embeds  = <span style=\"color:#0aa\">document<\/span>.getElementsByTagName( <span style=\"color:#a50\">'embed'<\/span> );\n\n    digestPotentialVideos( iframes );\n    digestPotentialVideos( embeds );\n\n  }\n\n  <span style=\"color:#00a\">var<\/span> tag            = <span style=\"color:#0aa\">document<\/span>.createElement( <span style=\"color:#a50\">'script'<\/span> );\n  tag.src            = <span style=\"color:#a50\">'\/\/www.youtube.com\/iframe_api'<\/span>;\n  <span style=\"color:#00a\">var<\/span> firstScriptTag = <span style=\"color:#0aa\">document<\/span>.getElementsByTagName( <span style=\"color:#a50\">'script'<\/span> )[<span style=\"color:#099\">0<\/span>];\n  firstScriptTag.parentNode.insertBefore( tag, firstScriptTag );\n\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Take our videos and turn them into trackable videos with events\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">function<\/span> digestPotentialVideos( potentialVideos ) {\n\n    <span style=\"color:#00a\">var<\/span> i;\n\n    <span style=\"color:#00a\">for<\/span>( i = <span style=\"color:#099\">0<\/span>; i var isYouTubeVideo = checkIfYouTubeVideo( potentialVideos[ i ] );       \n      <span style=\"color:#00a\">if<\/span>( isYouTubeVideo ) {\n        <span style=\"color:#00a\">var<\/span> normalizedYouTubeIframe = normalizeYouTubeIframe( potentialVideos[ i ] );\n        addYouTubeEvents( normalizedYouTubeIframe );\n      }\n    }\n\n  }   \n\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Determine if the element is a YouTube video or not   \n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">function<\/span> checkIfYouTubeVideo( potentialYouTubeVideo ) {\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Exclude already decorated videos     \n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">if<\/span> (potentialYouTubeVideo.getAttribute(<span style=\"color:#a50\">'data-gtm-yt'<\/span>)) {       \n      <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">false<\/span>;\n    }\n\n    <span style=\"color:#00a\">var<\/span> potentialYouTubeVideoSrc = potentialYouTubeVideo.src || <span style=\"color:#a50\">''<\/span>;     \n    <span style=\"color:#00a\">if<\/span>( potentialYouTubeVideoSrc.indexOf( <span style=\"color:#a50\">'youtube.com\/embed\/'<\/span> ) &gt; -<span style=\"color:#099\">1<\/span> || potentialYouTubeVideoSrc.indexOf( <span style=\"color:#a50\">'youtube.com\/v\/'<\/span> ) &gt; -<span style=\"color:#099\">1<\/span> ) {\n\n      <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">true<\/span>;\n\n    }\n\n    <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">false<\/span>;\n\n  }\n\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Turn embed objects into iframe objects and ensure they have the right parameters\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">function<\/span> normalizeYouTubeIframe( youTubeVideo ) {\n    \n    <span style=\"color:#00a\">var<\/span> a           = <span style=\"color:#0aa\">document<\/span>.createElement( <span style=\"color:#a50\">'a'<\/span> );\n        a.href      = youTubeVideo.src;\n        a.hostname  = <span style=\"color:#a50\">'www.youtube.com'<\/span>;\n        a.protocol  = <span style=\"color:#0aa\">document<\/span>.location.protocol;\n    <span style=\"color:#00a\">var<\/span> tmpPathname = a.pathname.charAt( <span style=\"color:#099\">0<\/span> ) === <span style=\"color:#a50\">'\/'<\/span> ? a.pathname : <span style=\"color:#a50\">'\/'<\/span> + a.pathname;  <span style=\"color:#aaa;font-style:italic\">\/\/ IE10 shim\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    \n    <span style=\"color:#aaa;font-style:italic\">\/\/ For security reasons, YouTube wants an origin parameter set that matches our hostname\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> origin = <span style=\"color:#0aa\">window<\/span>.location.protocol + <span style=\"color:#a50\">'%2F%2F'<\/span> + <span style=\"color:#0aa\">window<\/span>.location.hostname + ( <span style=\"color:#0aa\">window<\/span>.location.port ? <span style=\"color:#a50\">':'<\/span> + <span style=\"color:#0aa\">window<\/span>.location.port : <span style=\"color:#a50\">''<\/span> );\n\n    <span style=\"color:#00a\">if<\/span>( a.search.indexOf( <span style=\"color:#a50\">'enablejsapi'<\/span> ) === -<span style=\"color:#099\">1<\/span> ) {\n\n      a.search = ( a.search.length &gt; <span style=\"color:#099\">0<\/span> ? a.search + <span style=\"color:#a50\">'&amp;'<\/span> : <span style=\"color:#a50\">''<\/span> ) + <span style=\"color:#a50\">'enablejsapi=1'<\/span>;\n\n    }\n\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Don't set if testing locally\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">if<\/span>( a.search.indexOf( <span style=\"color:#a50\">'origin'<\/span> ) === -<span style=\"color:#099\">1<\/span>  &amp;&amp; <span style=\"color:#0aa\">window<\/span>.location.hostname.indexOf( <span style=\"color:#a50\">'localhost'<\/span> ) === -<span style=\"color:#099\">1<\/span> ) {\n\n      a.search = a.search + <span style=\"color:#a50\">'&amp;origin='<\/span> + origin;\n\n    }\n\n    <span style=\"color:#00a\">if<\/span>( youTubeVideo.type === <span style=\"color:#a50\">'application\/x-shockwave-flash'<\/span> ) {\n\n      <span style=\"color:#00a\">var<\/span> newIframe     = <span style=\"color:#0aa\">document<\/span>.createElement( <span style=\"color:#a50\">'iframe'<\/span> );\n      newIframe.height  = youTubeVideo.height;\n      newIframe.width   = youTubeVideo.width;\n      tmpPathname = tmpPathname.replace(<span style=\"color:#a50\">'\/v\/'<\/span>, <span style=\"color:#a50\">'\/embed\/'<\/span>);\n\n      youTubeVideo.parentNode.parentNode.replaceChild( newIframe, youTubeVideo.parentNode );\n\n      youTubeVideo = newIframe;\n\n    }\n\n    a.pathname       = tmpPathname;\n    <span style=\"color:#00a\">if<\/span>(youTubeVideo.src !== a.href + a.hash) {\n    \n      youTubeVideo.src = a.href + a.hash;\n\n    }\n\n    youTubeVideo.setAttribute(<span style=\"color:#a50\">'data-gtm-yt'<\/span>, <span style=\"color:#a50\">'true'<\/span>);\n\n    <span style=\"color:#00a\">return<\/span> youTubeVideo;\n\n  }\n\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Add event handlers for events emitted by the YouTube API\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">function<\/span> addYouTubeEvents( youTubeIframe ) {\n\n    youTubeIframe.pauseFlag  = <span style=\"color:#00a\">false<\/span>;\n\n    <span style=\"color:#00a\">new<\/span> YT.Player( youTubeIframe, {\n\n      events: {\n\n        onStateChange: <span style=\"color:#00a\">function<\/span>( evt ) {\n\n          onStateChangeHandler( evt, youTubeIframe );\n\n        }\n\n      }\n\n    } );\n\n  }\n\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Returns key\/value pairs of percentages: number of seconds to achieve\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">function<\/span> getMarks(duration) {\n\n    <span style=\"color:#00a\">var<\/span> marks = {}; \n\n    <span style=\"color:#aaa;font-style:italic\">\/\/ For full support, we're handling Watch to End with percentage viewed\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">if<\/span> (_config.events[ <span style=\"color:#a50\">'Watch to End'<\/span> ] ) {\n\n      marks[ <span style=\"color:#a50\">'Watch to End'<\/span> ] = duration * <span style=\"color:#099\">99<\/span> \/ <span style=\"color:#099\">100<\/span>;\n\n    }\n\n    <span style=\"color:#00a\">if<\/span>( _config.percentageTracking ) {\n\n      <span style=\"color:#00a\">var<\/span> points = [];\n      <span style=\"color:#00a\">var<\/span> i;\n\n      <span style=\"color:#00a\">if<\/span>( _config.percentageTracking.each ) {\n\n        points = points.concat( _config.percentageTracking.each );\n\n      }\n\n      <span style=\"color:#00a\">if<\/span>( _config.percentageTracking.every ) {\n\n        <span style=\"color:#00a\">var<\/span> every = <span style=\"color:#0aa\">parseInt<\/span>( _config.percentageTracking.every, <span style=\"color:#099\">10<\/span> );\n        <span style=\"color:#00a\">var<\/span> num = <span style=\"color:#099\">100<\/span> \/ every;\n        \n        <span style=\"color:#00a\">for<\/span>( i = <span style=\"color:#099\">1<\/span>; i for(i = <span style=\"color:#099\">0<\/span>; i var _point = points[i];\n        <span style=\"color:#00a\">var<\/span> _mark = _point + <span style=\"color:#a50\">'%'<\/span>;\n        <span style=\"color:#00a\">var<\/span> _time = duration * _point \/ <span style=\"color:#099\">100<\/span>;\n        \n        marks[_mark] = <span style=\"color:#0aa\">Math<\/span>.floor( _time );\n\n      }\n\n    }\n\n    <span style=\"color:#00a\">return<\/span> marks;\n\n  }\n\n  <span style=\"color:#00a\">function<\/span> checkCompletion(player, marks, videoId) {\n\n    <span style=\"color:#00a\">var<\/span> duration     = player.getDuration();\n    <span style=\"color:#00a\">var<\/span> currentTime  = player.getCurrentTime();\n    <span style=\"color:#00a\">var<\/span> playbackRate = player.getPlaybackRate();\n    player[videoId] = player[videoId] || {};\n    <span style=\"color:#00a\">var<\/span> key;\n\n    <span style=\"color:#00a\">for<\/span>( key <span style=\"color:#00a\">in<\/span> marks ) {\n\n      <span style=\"color:#00a\">if<\/span>( marks[key] true;\n        fireAnalyticsEvent( videoId, key );\n\n      }\n\n    }\n\n  }\n\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Event handler for events emitted from the YouTube API\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">function<\/span> onStateChangeHandler( evt, youTubeIframe ) {\n \n    <span style=\"color:#00a\">var<\/span> stateIndex     = evt.data;\n    <span style=\"color:#00a\">var<\/span> player         = evt.target;\n    <span style=\"color:#00a\">var<\/span> targetVideoUrl = player.getVideoUrl();\n    <span style=\"color:#00a\">var<\/span> targetVideoId  = targetVideoUrl.match( <span style=\"color:#099\">\/[?&amp;]v=([^]*)\/<\/span> )[ <span style=\"color:#099\">1<\/span> ];  <span style=\"color:#aaa;font-style:italic\">\/\/ Extract the ID    \n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> playerState    = player.getPlayerState();\n    <span style=\"color:#00a\">var<\/span> duration       = player.getDuration();\n    <span style=\"color:#00a\">var<\/span> marks          = getMarks(duration);\n    <span style=\"color:#00a\">var<\/span> playerStatesIndex = {\n      <span style=\"color:#a50\">'1'<\/span> : <span style=\"color:#a50\">'Play'<\/span>,\n      <span style=\"color:#a50\">'2'<\/span> : <span style=\"color:#a50\">'Pause'<\/span>\n    };\n    <span style=\"color:#00a\">var<\/span> state = playerStatesIndex[ stateIndex ]; \n\n    youTubeIframe.playTracker = youTubeIframe.playTracker || {};\n\n    <span style=\"color:#00a\">if<\/span>( playerState === <span style=\"color:#099\">1<\/span> &amp;&amp; !youTubeIframe.timer ) {\n\n      clearInterval(youTubeIframe.timer);\n\n      youTubeIframe.timer = setInterval(<span style=\"color:#00a\">function<\/span>() {\n\n        <span style=\"color:#aaa;font-style:italic\">\/\/ Check every second to see if we've hit any of our percentage viewed marks\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        checkCompletion(player, marks, youTubeIframe.videoId);\n\n      }, <span style=\"color:#099\">1000<\/span>);\n\n    } <span style=\"color:#00a\">else<\/span> {\n\n      clearInterval(youTubeIframe.timer);\n      youTubeIframe.timer = <span style=\"color:#00a\">false<\/span>;\n\n    }\n\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Playlist edge-case handler\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">if<\/span>( stateIndex === <span style=\"color:#099\">1<\/span> ) {\n\n      youTubeIframe.playTracker[ targetVideoId ] = <span style=\"color:#00a\">true<\/span>;\n      youTubeIframe.videoId = targetVideoId;\n      youTubeIframe.pauseFlag = <span style=\"color:#00a\">false<\/span>;\n\n    }\n\n    <span style=\"color:#00a\">if<\/span>( !youTubeIframe.playTracker[ youTubeIframe.videoId ] ) {\n\n      <span style=\"color:#aaa;font-style:italic\">\/\/ This video hasn't started yet, so this is spam\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>      <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">false<\/span>;\n\n    }\n\n    <span style=\"color:#00a\">if<\/span>( stateIndex === <span style=\"color:#099\">2<\/span> ) {\n\n      <span style=\"color:#00a\">if<\/span>( !youTubeIframe.pauseFlag ) { \n      \n        youTubeIframe.pauseFlag = <span style=\"color:#00a\">true<\/span>;\n\n      } <span style=\"color:#00a\">else<\/span> {\n\n        <span style=\"color:#aaa;font-style:italic\">\/\/ We don't want to fire consecutive pause events\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">false<\/span>;\n\n      }\n\n    }\n\n    <span style=\"color:#aaa;font-style:italic\">\/\/ If we're meant to track this event, fire it\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">if<\/span>( eventsFired[ state ] ) {\n    \n      fireAnalyticsEvent( youTubeIframe.videoId, state );\n\n    }\n\n  }\n\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Fire an event to Google Analytics or Google Tag Manager\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">function<\/span> fireAnalyticsEvent( videoId, state ) {\n\n    <span style=\"color:#00a\">var<\/span> videoUrl = <span style=\"color:#a50\">'https:\/\/www.youtube.com\/watch?v='<\/span> + videoId;\n    <span style=\"color:#00a\">var<\/span> _ga = <span style=\"color:#0aa\">window<\/span>.GoogleAnalyticsObject;\n\n    <span style=\"color:#00a\">if<\/span>( <span style=\"color:#00a\">typeof<\/span> <span style=\"color:#0aa\">window<\/span>[ dataLayerName ] !== <span style=\"color:#a50\">'undefined'<\/span> &amp;&amp; !_config.forceSyntax ) { \n      \n      <span style=\"color:#0aa\">window<\/span>[ dataLayerName ].push( {\n\n        <span style=\"color:#a50\">'event'<\/span>     : <span style=\"color:#a50\">'youTubeTrack'<\/span>,\n        <span style=\"color:#a50\">'attributes'<\/span>: {\n\n          <span style=\"color:#a50\">'videoUrl'<\/span>: videoUrl,\n          <span style=\"color:#a50\">'videoAction'<\/span>: state\n\n        }\n\n      } );\n\n    } <span style=\"color:#00a\">else<\/span> <span style=\"color:#00a\">if<\/span>( <span style=\"color:#00a\">typeof<\/span> <span style=\"color:#0aa\">window<\/span>[ _ga ] === <span style=\"color:#a50\">'function'<\/span> &amp;&amp; \n               <span style=\"color:#00a\">typeof<\/span> <span style=\"color:#0aa\">window<\/span>[ _ga ].getAll === <span style=\"color:#a50\">'function'<\/span> &amp;&amp; \n               _config.forceSyntax !== <span style=\"color:#099\">2<\/span> ) \n    {\n\n      <span style=\"color:#0aa\">window<\/span>[ _ga ]( <span style=\"color:#a50\">'send'<\/span>, <span style=\"color:#a50\">'event'<\/span>, <span style=\"color:#a50\">'Videos'<\/span>, state, videoUrl );\n\n    } <span style=\"color:#00a\">else<\/span> <span style=\"color:#00a\">if<\/span>( <span style=\"color:#00a\">typeof<\/span> <span style=\"color:#0aa\">window<\/span>._gaq !== <span style=\"color:#a50\">'undefined'<\/span> &amp;&amp; forceSyntax !== <span style=\"color:#099\">1<\/span> ) {\n\n      <span style=\"color:#0aa\">window<\/span>._gaq.push( [ <span style=\"color:#a50\">'_trackEvent'<\/span>, <span style=\"color:#a50\">'Videos'<\/span>, state, videoUrl ] );\n\n    }\n\n  }\n  \n  <span style=\"color:#00a\">return<\/span> {\n    init : init,\n    digestPotentialVideos : digestPotentialVideos\n  }\n    \n})(<span style=\"color:#0aa\">document<\/span>, <span style=\"color:#0aa\">window<\/span>, {\n  <span style=\"color:#a50\">'events'<\/span>: {\n    <span style=\"color:#a50\">'Play'<\/span>: <span style=\"color:#00a\">true<\/span>,\n    <span style=\"color:#a50\">'Pause'<\/span>: <span style=\"color:#00a\">true<\/span>,\n    <span style=\"color:#a50\">'Watch to End'<\/span>: <span style=\"color:#00a\">true<\/span>\n  },\n  <span style=\"color:#a50\">'percentageTracking'<\/span>: {\n    <span style=\"color:#a50\">'every'<\/span>: <span style=\"color:#099\">25<\/span>,\n    <span style=\"color:#a50\">'each'<\/span>: [ <span style=\"color:#099\">10<\/span>, <span style=\"color:#099\">90<\/span> ]\n  }\n});\n<span style=\"color:#aaa;font-style:italic\">\/*\n<\/span><span style=\"color:#aaa;font-style:italic\"> * Configuration Details\n<\/span><span style=\"color:#aaa;font-style:italic\"> *\n<\/span><span style=\"color:#aaa;font-style:italic\"> * @property events object\n<\/span><span style=\"color:#aaa;font-style:italic\"> * Defines which events emitted by YouTube API\n<\/span><span style=\"color:#aaa;font-style:italic\"> * will be turned into Google Analytics or GTM events\n<\/span><span style=\"color:#aaa;font-style:italic\"> *\n<\/span><span style=\"color:#aaa;font-style:italic\"> * @property percentageTracking object\n<\/span><span style=\"color:#aaa;font-style:italic\"> * Object with configurations for percentage viewed events\n<\/span><span style=\"color:#aaa;font-style:italic\"> *\n<\/span><span style=\"color:#aaa;font-style:italic\"> *   @property each array\n<\/span><span style=\"color:#aaa;font-style:italic\"> *   Fires an event once each percentage ahs been reached\n<\/span><span style=\"color:#aaa;font-style:italic\"> *\n<\/span><span style=\"color:#aaa;font-style:italic\"> *   @property every number\n<\/span><span style=\"color:#aaa;font-style:italic\"> *   Fires an event for every n% viewed\n<\/span><span style=\"color:#aaa;font-style:italic\"> *\n<\/span><span style=\"color:#aaa;font-style:italic\"> * @property forceSyntax int 0, 1, or 2\n<\/span><span style=\"color:#aaa;font-style:italic\"> * Forces script to use Classic (2) or Universal(1)\n<\/span><span style=\"color:#aaa;font-style:italic\"> *\n<\/span><span style=\"color:#aaa;font-style:italic\"> * @property dataLayerName string\n<\/span><span style=\"color:#aaa;font-style:italic\"> * Tells script to use custom dataLayer name instead of default\n<\/span><span style=\"color:#aaa;font-style:italic\"> *\/<\/span>\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>Yes, that is a LOT of stuff. Bear with me, though.<\/p>\n<p>The modifications to Bounteous\u2019 solution are few but significant.<\/p>\n<p>First of all, instead of using an <strong>anonymous function<\/strong>, we\u2019re actually reserving a slot in the global namespace, and exposing the function in a variable named <code>ytTracker<\/code>.<\/p>\n<p>We do this because we want to invoke certain methods in the setup after the initial execution. If we didn\u2019t expose a public method for it, we\u2019d need to run the whole thing again and again, each time a video is dynamically loaded, and that\u2019s just a huge strain on performance.<\/p>\n<p>Next thing we\u2019re doing is adding a single line into the <code>normalizeYouTubeIframe()<\/code> method:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span> normalizeYouTubeIframe( youTubeVideo ) {\n  ...\n  youTubeVideo.setAttribute(<span style=\"color:#a50\">'data-gtm-yt'<\/span>, <span style=\"color:#a50\">'true'<\/span>); <span style=\"color:#aaa;font-style:italic\">\/\/ <span style=\"color:#aaa;font-style:italic\"\/>\n  <span style=\"color:#00a\">return<\/span> youTubeVideo;\n}\n<\/span><\/code><\/pre>\n<\/div>\n<p>The <code>youTubeVideo.setAttribute()<\/code> command is used to add a data attribute to all iframes which have already been treated by the script. This is because we want to avoid running the initialization methods again and again for videos which have already been configured for tracking. In my testing, if a video was tracked multiple times it led to runtime conflicts.<\/p>\n<p>Now that the data attribute is there, we need to check for its existence. In the <code>checkIfYouTubeVideo()<\/code> method, we\u2019ll add the check like this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span> checkIfYouTubeVideo( potentialYouTubeVideo ) {    \n  <span style=\"color:#00a\">if<\/span> (potentialYouTubeVideo.getAttribute(<span style=\"color:#a50\">'data-gtm-yt'<\/span>)) {\n    <span style=\"color:#00a\">return<\/span> <span style=\"color:#00a\">false<\/span>;\n  }\n  ...\n}\n<\/code><\/pre>\n<\/div>\n<p>This check just looks for the <strong>data-gtm-yt<\/strong> attribute we added in the previous step, and if it\u2019s found, the initialization is skipped for this particular video.<\/p>\n<p>This way only videos which have <strong>not<\/strong> been treated yet will be processed.<\/p>\n<p>Finally, we need to expose two methods in the <code>ytTracker<\/code> interface. These will let us handle dynamically added videos. Lets do that in the very end of the function expression.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">var<\/span> ytTracker = (<span style=\"color:#00a\">function<\/span>(...) {\n  ...\n  <span style=\"color:#00a\">return<\/span> {\n    init : init,\n    digestPotentialVideos : digestPotentialVideos\n  }\n})(...);\n<\/code><\/pre>\n<\/div>\n<p>We <strong>return<\/strong> an object with two members: <code>init<\/code> and <code>digestPotentialVideos<\/code>. So, when we call <code>ytTracker.init()<\/code>, the script is basically run again, and all newly added, yet untreated YouTube iframe embeds will be processed and decorated with event trackers.<\/p>\n<p>If you want it to be a bit more robust, you can use <code>ytTracker.digestPotentialVideos(iframe)<\/code> instead. You pass an iframe object as its parameter, and the script will only treat the one video. This is better since it won\u2019t loop through all the iframes on the page, and instead just decorates the one you want.<\/p>\n<p>Finally, set the Custom HTML Tag to fire on a <strong>Page View \/ DOM Ready<\/strong> Trigger.<\/p>\n<p>That\u2019s the changes right there, ladies and gentlemen.<\/p>\n<h2 id=\"how-to-use-it\">How to use it<\/h2>\n<p>As said, there\u2019s two new methods in town:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\">ytTracker.init(); <span style=\"color:#aaa;font-style:italic\">\/\/ <span style=\"color:#aaa;font-style:italic\"\/>ytTracker.digestPotentialVideos(iframe); <span style=\"color:#aaa;font-style:italic\">\/\/ <\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Making the solution work will still most likely require developer help. If your developers have added some complex, dynamic content loaders, which add the videos after some awesome jQuery fade-in has finished, you\u2019ll need to cooperate with them to add the <code>ytTracker.init()<\/code> or <code>ytTracker.digestPotentialVideos()<\/code> command in the right place.<\/p>\n<p>Here\u2019s an example of what a modified content loader might look like:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">function<\/span> processVideoClick(ytEmbedSrc) {\n  <span style=\"color:#00a\">var<\/span> video = <span style=\"color:#0aa\">document<\/span>.createElement(<span style=\"color:#a50\">'iframe'<\/span>);\n  video.src = ytEmbedSrc;\n  <span style=\"color:#00a\">var<\/span> content = <span style=\"color:#0aa\">document<\/span>.querySelector(<span style=\"color:#a50\">'#content'<\/span>);\n  content.appendChild(video);\n  <span style=\"color:#0aa\">window<\/span>.ytTracker.digestPotentialVideos(video);\n}\n<\/code><\/pre>\n<\/div>\n<p>After the video is injected, you call <code>ytTracker.digestPotentialVideos()<\/code>. You could use the <code>init()<\/code> method without any parameters, but since you already have the iframe element at hand, it\u2019s better to use the more direct method.<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>Since loading content dynamically is notoriously standard-free, it\u2019s difficult to give a generic solution for managing dynamically loaded content in your analytics or tag management platform. However, Bounteous\u2019 original solution has a very nice set of tools to tackle dynamically loaded YouTube videos as well, without having to make drastic modifications to the code.<\/p>\n<p>Bounteous\u2019 solution is so flexible and useful. Poking some holes into its interface to let some light out just makes it even better, in my own, humble opinion.<\/p>\n<p>The optimal way of working with it is to cooperate with your developers. I hope we\u2019ve all matured past the notion of <a href=\"https:\/\/www.simoahava.com\/analytics\/tag-management-make-redundant\/\">GTM being developer-independent<\/a>. So, communicate with your developers, ask them to modify the JavaScript controlling the dynamic video injection, and request that they\u2019ll add the simple <code>ytTracker<\/code> methods to the handlers they create.<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Tracking YouTube videos in Google Tag Manager is one of the more useful things you can do in terms of tracking. YouTube has a wonderful API that you can tap into and convert the detected events into dataLayer messages. There are some really good solutions out there for tracking YouTube videos in GTM: Both do [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":135777,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[58362,1531,6870,14495,1791,1018,13073,14285],"dealstore":[],"offerexpiration":[],"class_list":["post-135776","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-dynamically","tag-google","tag-loaded","tag-manager","tag-tag","tag-track","tag-videos","tag-youtube"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Track Dynamically Loaded YouTube Videos In Google Tag Manager - Som2ny Network<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fivemor.com\/?p=135776\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Track Dynamically Loaded YouTube Videos In Google Tag Manager - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"Tracking YouTube videos in Google Tag Manager is one of the more useful things you can do in terms of tracking. YouTube has a wonderful API that you can tap into and convert the detected events into dataLayer messages. There are some really good solutions out there for tracking YouTube videos in GTM: Both do [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=135776\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-15T19:30:10+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1986\" \/>\n\t<meta property=\"og:image:height\" content=\"1290\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=135776#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=135776\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"Track Dynamically Loaded YouTube Videos In Google Tag Manager\",\"datePublished\":\"2025-03-15T19:30:10+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=135776\"},\"wordCount\":969,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=135776#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg\",\"keywords\":[\"Dynamically\",\"Google\",\"Loaded\",\"Manager\",\"TAG\",\"Track\",\"Videos\",\"YouTube\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=135776#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=135776\",\"url\":\"https:\/\/fivemor.com\/?p=135776\",\"name\":\"Track Dynamically Loaded YouTube Videos In Google Tag Manager - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=135776#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=135776#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg\",\"datePublished\":\"2025-03-15T19:30:10+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=135776#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=135776\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=135776#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg\",\"width\":1986,\"height\":1290},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=135776#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Track Dynamically Loaded YouTube Videos In Google Tag Manager\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fivemor.com\/#website\",\"url\":\"https:\/\/fivemor.com\/\",\"name\":\"Som2ny Network\",\"description\":\"Daily Deals\",\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fivemor.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/fivemor.com\/#organization\",\"name\":\"Som2ny Network\",\"url\":\"https:\/\/fivemor.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"width\":300,\"height\":86,\"caption\":\"Som2ny Network\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"caption\":\"admin\"},\"sameAs\":[\"https:\/\/fivemor.com\"],\"url\":\"https:\/\/fivemor.com\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Track Dynamically Loaded YouTube Videos In Google Tag Manager - Som2ny Network","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fivemor.com\/?p=135776","og_locale":"en_US","og_type":"article","og_title":"Track Dynamically Loaded YouTube Videos In Google Tag Manager - Som2ny Network","og_description":"Tracking YouTube videos in Google Tag Manager is one of the more useful things you can do in terms of tracking. YouTube has a wonderful API that you can tap into and convert the detected events into dataLayer messages. There are some really good solutions out there for tracking YouTube videos in GTM: Both do [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=135776","og_site_name":"Som2ny Network","article_published_time":"2025-03-15T19:30:10+00:00","og_image":[{"width":1986,"height":1290,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=135776#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=135776"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"Track Dynamically Loaded YouTube Videos In Google Tag Manager","datePublished":"2025-03-15T19:30:10+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=135776"},"wordCount":969,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=135776#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg","keywords":["Dynamically","Google","Loaded","Manager","TAG","Track","Videos","YouTube"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=135776#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=135776","url":"https:\/\/fivemor.com\/?p=135776","name":"Track Dynamically Loaded YouTube Videos In Google Tag Manager - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=135776#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=135776#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg","datePublished":"2025-03-15T19:30:10+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=135776#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=135776"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=135776#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/03\/youtube-videos-dynamic-tracking.jpg","width":1986,"height":1290},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=135776#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"Track Dynamically Loaded YouTube Videos In Google Tag Manager"}]},{"@type":"WebSite","@id":"https:\/\/fivemor.com\/#website","url":"https:\/\/fivemor.com\/","name":"Som2ny Network","description":"Daily Deals","publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fivemor.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/fivemor.com\/#organization","name":"Som2ny Network","url":"https:\/\/fivemor.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","width":300,"height":86,"caption":"Som2ny Network"},"image":{"@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371","name":"admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","caption":"admin"},"sameAs":["https:\/\/fivemor.com"],"url":"https:\/\/fivemor.com\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/135776","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=135776"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/135776\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/135777"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=135776"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=135776"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=135776"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=135776"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=135776"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}