{"id":89504,"date":"2025-02-15T10:30:15","date_gmt":"2025-02-15T10:30:15","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/track-interactions-in-the-shadow-dom-using-google-tag-manager\/"},"modified":"2025-02-15T10:30:15","modified_gmt":"2025-02-15T10:30:15","slug":"track-interactions-in-the-shadow-dom-using-google-tag-manager","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=89504","title":{"rendered":"Track Interactions In The Shadow DOM Using Google Tag Manager"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div> when it actually landed on the element within <code>#shadow-root<\/code>. Similarly, because the shadow DOM\u2019s contents are hidden from the parent structure, the <a href=\"https:\/\/www.simoahava.com\/analytics\/matches-css-selector-operator-in-gtm-triggers\/\">matches CSS selector<\/a> predicate can\u2019t be used to see what\u2019s inside the clicked element.<\/p>\n<p>We can work around this! We can\u2019t use GTM\u2019s built-in triggers as they don\u2019t let us access the <code>event<\/code> object itself. But we can use a <a href=\"https:\/\/www.simoahava.com\/analytics\/simple-custom-event-listeners-gtm\/\">custom event listener<\/a>.<\/p>\n<blockquote>\n<p>For more details on how event handling within the shadow DOM works, take a look at <a href=\"https:\/\/dev.to\/open-wc\/composed-true-considered-harmful-5g59\">this excellent article on the topic<\/a>.<\/p>\n<\/blockquote>\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=\"how-event-handling-works-with-the-shadow-dom\">How event handling works with the shadow DOM<\/h2>\n<p>Event listeners within the shadow DOM work just like event listeners on regular DOM structures. An event is registered, and it populates a path through the layers of the site during the <a href=\"https:\/\/javascript.info\/bubbling-and-capturing\"><code>capture<\/code> and <code>bubble<\/code> phases<\/a>.<\/p>\n<p>Some events bubble up towards the top of the DOM tree, some stay on the node where the event was registered.<\/p>\n<p>The main difference with the shadow DOM is that events that start making their way up only cross the shadow DOM boundary if they have the property <code>composed<\/code> set to <code>true<\/code>.<\/p>\n<p>Most events have <code>composed<\/code> set to <code>true<\/code>. Typically, the exceptions are events that are not based on UI interactions. Like these:<\/p>\n<p>For events that have <code>composed<\/code> set to <code>true<\/code>, we can attach a custom event listener on the <code>document<\/code> node, for example, and the events that take place within the shadow DOM will propagate to our listener (assuming they also <strong>bubble<\/strong>, or the listener has been set to detect the <strong>capture<\/strong> phase instead).<\/p>\n<p>However, we are still faced with the problem introduced in the beginning of this article. All events that take place in the shadow DOM are auto-delegated to the parent of the <code>#shadow-root<\/code>. This isn\u2019t very helpful. The shadow DOM could be a huge, sprawling thing, so we need <em>precision<\/em>.<\/p>\n<p>Luckily, we can use the <code>Event.composedPath()<\/code> method to get an array that represents the <em>path<\/em> the event took as it bubbled up. The very first member in the array is the item that was <em>actually<\/em> clicked (unless the shadow DOM was <code>closed<\/code>, but we\u2019ll get back to that in a minute).<\/p>\n<p>We can use this information to build our listener.<\/p>\n<h2 id=\"the-listener\">The listener<\/h2>\n<p>In Google Tag Manager, create a <strong>Custom HTML tag<\/strong>, and type or copy-paste 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:#00a\">function<\/span>() {\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Set to the event you want to track\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> eventName = <span style=\"color:#a50\">'click'<\/span>,\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Set to false if you don't want to use capture phase\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        useCapture = <span style=\"color:#00a\">true<\/span>,\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Set to false if you want to track all events and not just those in shadow DOM\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        trackOnlyShadowDom = <span style=\"color:#00a\">true<\/span>;\n\n    <span style=\"color:#00a\">var<\/span> callback = <span style=\"color:#00a\">function<\/span>(event) {\n      <span style=\"color:#00a\">if<\/span> (<span style=\"color:#a50\">'composed'<\/span> <span style=\"color:#00a\">in<\/span> event &amp;&amp; <span style=\"color:#00a\">typeof<\/span> event.composedPath === <span style=\"color:#a50\">'function'<\/span>) {\n        <span style=\"color:#aaa;font-style:italic\">\/\/ Get the path of elements the event climbed through, e.g.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#aaa;font-style:italic\">\/\/ [span, div, div, section, body]\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#00a\">var<\/span> path = event.composedPath();\n        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Fetch reference to the element that was actually clicked\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#00a\">var<\/span> targetElement = path[<span style=\"color:#099\">0<\/span>];\n        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Check if the element is WITHIN the shadow DOM (ignoring the root)\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#00a\">var<\/span> shadowFound = path.length ? path.filter(<span style=\"color:#00a\">function<\/span>(i) {\n          <span style=\"color:#00a\">return<\/span> !targetElement.shadowRoot &amp;&amp; !!i.shadowRoot;\n        }).length &gt; <span style=\"color:#099\">0<\/span> : <span style=\"color:#00a\">false<\/span>;\n        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ If only shadow DOM events should be tracked and the element is not within one, return\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#00a\">if<\/span> (trackOnlyShadowDom &amp;&amp; !shadowFound) <span style=\"color:#00a\">return<\/span>;\n        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Push to dataLayer\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#0aa\">window<\/span>.dataLayer.push({\n          event: <span style=\"color:#a50\">'custom_event_'<\/span> + event.type,\n          custom_event: {\n            element: targetElement,\n            elementId: targetElement.id || <span style=\"color:#a50\">''<\/span>,\n            elementClasses: targetElement.className ||\u00a0<span style=\"color:#a50\">''<\/span>,\n            elementUrl: targetElement.href || targetElement.action || <span style=\"color:#a50\">''<\/span>,\n            elementTarget: targetElement.target || <span style=\"color:#a50\">''<\/span>,\n            originalEvent: event,\n            inShadowDom: shadowFound\n          }\n        });\n      }\n    };\n    \n    <span style=\"color:#0aa\">document<\/span>.addEventListener(eventName, callback, useCapture);\n  })();\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>You can attach a <strong>Page View<\/strong> trigger to this tag. After that, every single click on pages where the listener is active will be pushed into <code>dataLayer<\/code> with an object content that looks like this:<\/p>\n<div style=\"aspect-ratio: 1522 \/ 448;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/05\/datalayer-object.jpg\" title=\"Data Layer object\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"448\" width=\"1522\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/05\/datalayer-object.jpg#ZgotmplZ\" alt=\"Data Layer object\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In this case, the click fell on a <code><\/p>\n<div> with very few attributes, but which was contained in the shadow Dom (as <code>isShadowDom<\/code> is <code>true<\/code>).<\/p>\n<p>You can then create a Custom Event trigger for <code>custom_event_click<\/code>:<\/p>\n<div style=\"aspect-ratio: 1850 \/ 772;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/05\/custom-event-trigger.jpg\" title=\"Custom Event trigger\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"772\" width=\"1850\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/05\/custom-event-trigger.jpg#ZgotmplZ\" alt=\"Custom Event trigger\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>And you can create Data Layer variables for the individual items in the pushed object like this:<\/p>\n<div style=\"aspect-ratio: 1582 \/ 936;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2020\/05\/data-layer-variable.jpg\" title=\"Data Layer Variable\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"936\" width=\"1582\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2020\/05\/data-layer-variable.jpg#ZgotmplZ\" alt=\"Data Layer Variable\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>By switching <code>eventName<\/code> to, say, <code>submit<\/code>, you can listen for form submissions instead.<\/p>\n<p>If you want to avoid having the script push a message with <em>every single event instance<\/em>, you can add checks within the callback that verify the event target was a specific type of element. For example, to only push to dataLayer if the click landed on a link, you could do something like this:<\/p>\n<pre><code class=\"language-javacsript\" data-lang=\"javacsript\">var callback = function(event) {\n  ...\n  var targetElement = path[0];\n  if (targetElement.matches('a, a *')) {\n    \/\/ Run the dataLayer.push() here\n  }\n  ...\n...<\/code><\/pre>\n<blockquote>\n<p>Note! Though it was just an example, you should be aware that <code>.matches()<\/code> won\u2019t work in IE, and you\u2019ll need to use <code>.msMatchesSelector()<\/code>.<\/p>\n<\/blockquote>\n<h2 id=\"what-about-non-composed-events\">What about non-composed events?<\/h2>\n<p>What if you want to track events that don\u2019t have the <code>composed<\/code> flag set to <code>true<\/code>? If you remember, those events will not propagate past the shadow DOM boundaries. Similarly, if you use the script above, they will also have the <code>inShadowDom<\/code> flag set to <code>false<\/code>, as they are practically oblivious to the fact that they are in a shadow DOM (Matrix-style).<\/p>\n<p>So, you\u2019ll have to do event handling without the power of delegation. In other words, you\u2019ll need to add the listeners directly to the elements.<\/p>\n<p>For example, if you wanted to track a <code>load<\/code> event for a <code><script\/><\/code> within the shadow DOM, the script would look 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-html\" data-lang=\"html\">script&gt;\n  (<span style=\"color:#00a\">function<\/span>() {\n    <span style=\"color:#aaa;font-style:italic\">\/\/ Set to the event you want to track\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> eventName = <span style=\"color:#a50\">'load'<\/span>;\n    <span style=\"color:#aaa;font-style:italic\">\/\/ useCapture is irrelevant as we'll be tracking the element itself\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#aaa;font-style:italic\">\/\/  useCapture = true,\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#aaa;font-style:italic\">\/\/ trackOnlyShadowDom is irrelevant as we'll be only tracking an element in the shadow DOM\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#aaa;font-style:italic\">\/\/  trackOnlyShadowDom = true;\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>\n    <span style=\"color:#00a\">var<\/span> callback = <span style=\"color:#00a\">function<\/span>(event) {\n      <span style=\"color:#00a\">if<\/span> (<span style=\"color:#a50\">'composed'<\/span> <span style=\"color:#00a\">in<\/span> event &amp;&amp; <span style=\"color:#00a\">typeof<\/span> event.composedPath === <span style=\"color:#a50\">'function'<\/span>) {\n        <span style=\"color:#aaa;font-style:italic\">\/\/ Irrelevant in this solution, as we are tracking the element itself\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#aaa;font-style:italic\">\/\/ var path = event.composedPath();\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Irrelevant.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#aaa;font-style:italic\">\/\/ var targetElement = path[0];\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        \n        <span style=\"color:#00a\">var<\/span> targetElement = event.target;\n        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Irrelevant.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#aaa;font-style:italic\">\/\/ var shadowFound = path.length ? path.filter(function(i) {\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#aaa;font-style:italic\">\/\/   return !targetElement.shadowRoot &amp;&amp; !!i.shadowRoot;\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#aaa;font-style:italic\">\/\/ }).length &gt; 0 : false;\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Irrelevant\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#aaa;font-style:italic\">\/\/ if (trackOnlyShadowDom &amp;&amp; !shadowFound) return;\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        \n        <span style=\"color:#aaa;font-style:italic\">\/\/ Push to dataLayer\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>        <span style=\"color:#0aa\">window<\/span>.dataLayer.push({\n          event: <span style=\"color:#a50\">'custom_event_'<\/span> + event.type,\n          custom_event: {\n            element: targetElement,\n            elementId: targetElement.id || <span style=\"color:#a50\">''<\/span>,\n            elementClasses: targetElement.className ||\u00a0<span style=\"color:#a50\">''<\/span>,\n            elementUrl: targetElement.href || targetElement.action || <span style=\"color:#a50\">''<\/span>,\n            elementTarget: targetElement.target || <span style=\"color:#a50\">''<\/span>,\n            originalEvent: event,\n            inShadowDom: <span style=\"color:#00a\">true<\/span>\n          }\n        });\n      }\n    };\n    \n    <span style=\"color:#aaa;font-style:italic\">\/\/ This is where the script sets the listener on the actual element in the shadow root\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#aaa;font-style:italic\">\/\/ The script checks if the container exists in the standard DOM, then it checks if the container\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#aaa;font-style:italic\">\/\/ is the shadow root, and finally it checks if the shadow DOM has the script element.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> shadowContainer = <span style=\"color:#0aa\">document<\/span>.querySelector(<span style=\"color:#a50\">'.shadowDomContainer'<\/span>);\n    <span style=\"color:#00a\">if<\/span> (!!shadowContainer &amp;&amp; !!shadowContainer.shadowRoot) {\n      <span style=\"color:#00a\">var<\/span> scriptTarget = shadowContainer.shadowRoot.querySelector(<span style=\"color:#a50\">'script#someId'<\/span>);\n      <span style=\"color:#00a\">if<\/span> (!!scriptTarget) scriptTarget.addEventListener(eventName, callback);\n    }\n  })();\n<span style=\"color:#1e90ff;font-weight:bold\">script<\/span>&gt;<\/code><\/pre>\n<\/div>\n<p>Here the <code>addEventListener<\/code> call at the end is quite a bit more complex than the generic one we used before. You first need to find the node to which the shadow DOM is embedded (the <strong>shadow root<\/strong>). Then, accessing its <code>shadowRoot<\/code> property, you are allowed to query for elements within the shadow DOM (assuming the shadow DOM is <code>open<\/code>).<\/p>\n<p>After the usual checks for whether the element exists, you can then add your listener directly to the element, and it will invoke the callback as soon as it registers the event.<\/p>\n<h2 id=\"what-about-a-closed-shadow-dom\">What about a closed shadow DOM?<\/h2>\n<p>If the shadow DOM is created in <code>closed<\/code> mode, you are basically unable to do anything with the <code>shadowRoot<\/code>. If you try to access it with DOM methods, the <code>shadowRoot<\/code> property will simply return <code>null<\/code>, and similarly the <code>composedPath()<\/code> returns an array of elements that stops with the shadow root node.<\/p>\n<p>Thus, on a superficial level, there\u2019s really nothing you can do to track the precise interactions within the shadow DOM.<\/p>\n<p>However, there is a workaround.<\/p>\n<p>When the shadow DOM is created, if the developers store a reference to it in a global variable, you can interact with it, and you can add listeners to the elements in the document fragment if you wish.<\/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:#aaa;font-style:italic\">\/\/ Create a shadow DOM\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">var<\/span> container = <span style=\"color:#0aa\">document<\/span>.querySelector(<span style=\"color:#a50\">'.someContainer'<\/span>);\n<span style=\"color:#0aa\">window<\/span>._shadowRoot = container.attachShadow({mode: <span style=\"color:#a50\">'closed'<\/span>});\n<\/code><\/pre>\n<\/div>\n<p>In the sample above, the global variable <code>_shadowRoot<\/code> maintains a reference to the shadow DOM, and thus you can use methods like <code>window._shadowRoot.addEventListener(...)<\/code> to manipulate and interact with elements within the shadow DOM.<\/p>\n<p>It does require some cooperation with the developers, and you\u2019d also need to justify why the mode is set to <code>closed<\/code> in the first place if the developers add an opening by way of a global variable.<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>Hopefully this article has been instructive. I have a gut feeling that the shadow DOM is somewhat of a mystery to many web analytics developers simply because it\u2019s not the most common way to add elements to the web page.<\/p>\n<p>However, it offers powerful tools for encapsulation and separation of concerns, and especially in lieu of clumsy iframe embeds it might make a lot of sense from a web development point of view.<\/p>\n<p>The pointers in this article should give you the tools for identifying yet another potential issue with Google Tag Manager\u2019s built-in listeners, and it should help you tackle it with the power of some custom scripting.<\/p>\n<\/p><\/div>\n<p>          <\/code><\/p>\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>when it actually landed on the element within #shadow-root. Similarly, because the shadow DOM\u2019s contents are hidden from the parent structure, the matches CSS selector predicate can\u2019t be used to see what\u2019s inside the clicked element. We can work around this! We can\u2019t use GTM\u2019s built-in triggers as they don\u2019t let us access the event [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":89505,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[43511,1531,43510,14495,5606,1791,1018],"dealstore":[],"offerexpiration":[],"class_list":["post-89504","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-dom","tag-google","tag-interactions","tag-manager","tag-shadow","tag-tag","tag-track"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Track Interactions In The Shadow DOM Using 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=89504\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Track Interactions In The Shadow DOM Using Google Tag Manager - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"when it actually landed on the element within #shadow-root. Similarly, because the shadow DOM\u2019s contents are hidden from the parent structure, the matches CSS selector predicate can\u2019t be used to see what\u2019s inside the clicked element. We can work around this! We can\u2019t use GTM\u2019s built-in triggers as they don\u2019t let us access the event [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=89504\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-15T10:30:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1376\" \/>\n\t<meta property=\"og:image:height\" content=\"344\" \/>\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=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=89504#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=89504\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"Track Interactions In The Shadow DOM Using Google Tag Manager\",\"datePublished\":\"2025-02-15T10:30:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=89504\"},\"wordCount\":1064,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=89504#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg\",\"keywords\":[\"DOM\",\"Google\",\"Interactions\",\"Manager\",\"Shadow\",\"TAG\",\"Track\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=89504#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=89504\",\"url\":\"https:\/\/fivemor.com\/?p=89504\",\"name\":\"Track Interactions In The Shadow DOM Using Google Tag Manager - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=89504#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=89504#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg\",\"datePublished\":\"2025-02-15T10:30:15+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=89504#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=89504\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=89504#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg\",\"width\":1376,\"height\":344},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=89504#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Track Interactions In The Shadow DOM Using 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 Interactions In The Shadow DOM Using 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=89504","og_locale":"en_US","og_type":"article","og_title":"Track Interactions In The Shadow DOM Using Google Tag Manager - Som2ny Network","og_description":"when it actually landed on the element within #shadow-root. Similarly, because the shadow DOM\u2019s contents are hidden from the parent structure, the matches CSS selector predicate can\u2019t be used to see what\u2019s inside the clicked element. We can work around this! We can\u2019t use GTM\u2019s built-in triggers as they don\u2019t let us access the event [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=89504","og_site_name":"Som2ny Network","article_published_time":"2025-02-15T10:30:15+00:00","og_image":[{"width":1376,"height":344,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=89504#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=89504"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"Track Interactions In The Shadow DOM Using Google Tag Manager","datePublished":"2025-02-15T10:30:15+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=89504"},"wordCount":1064,"commentCount":2,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=89504#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg","keywords":["DOM","Google","Interactions","Manager","Shadow","TAG","Track"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=89504#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=89504","url":"https:\/\/fivemor.com\/?p=89504","name":"Track Interactions In The Shadow DOM Using Google Tag Manager - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=89504#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=89504#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg","datePublished":"2025-02-15T10:30:15+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=89504#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=89504"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=89504#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/shadow-dom.jpg","width":1376,"height":344},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=89504#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"Track Interactions In The Shadow DOM Using 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\/89504","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=89504"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/89504\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/89505"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=89504"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=89504"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=89504"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=89504"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=89504"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}