{"id":108923,"date":"2025-02-25T10:20:15","date_gmt":"2025-02-25T10:20:15","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/customize-the-scroll-depth-trigger-in-google-tag-manager\/"},"modified":"2025-02-25T10:20:15","modified_gmt":"2025-02-25T10:20:15","slug":"customize-the-scroll-depth-trigger-in-google-tag-manager","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=108923","title":{"rendered":"Customize The Scroll Depth Trigger In Google Tag Manager"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p><em>Last updated 9 March 2018 with some new tips.<\/em><\/p>\n<p>The <a href=\"https:\/\/www.simoahava.com\/analytics\/scroll-depth-trigger-google-tag-manager\/\">Scroll Depth trigger<\/a> in <a href=\"https:\/\/tagmanager.google.com\/\">Google Tag Manager<\/a> has a lot going for it. Tracking how far users scroll down a given page has <a href=\"http:\/\/cutroni.com\/blog\/2014\/02\/12\/advanced-content-tracking-with-universal-analytics\/\">long since<\/a> been recognized as an important cog in the <em>engagement tracking<\/em> machine, and there have been <a href=\"http:\/\/scrolldepth.parsnip.io\/\">really<\/a> <a href=\"https:\/\/www.bounteous.com\/labs\/recipes\/scroll-tracking\/\">great<\/a> solutions for implementing scroll depth tracking for web analytics over the years.<\/p>\n<p>With Google Tag Manager\u2019s native Scroll Depth trigger, it\u2019s tempting to think we now have a be-all end-all solution that covers all the bases. However, as with everything else in analytics, the native scroll depth trigger does require customization to provide you with relevant information about your content and the visitors interacting with it.<\/p>\n<div style=\"aspect-ratio: 1860 \/ 630;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/03\/scroll-depth-trigger-customizations.jpg\" title=\"Customizing the scroll depth trigger\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"630\" width=\"1860\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/03\/scroll-depth-trigger-customizations.jpg#ZgotmplZ\" alt=\"Customizing the scroll depth trigger\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In this article, I\u2019ll explore some tricks that you might find useful when customizing the scroll depth trigger.<\/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=\"1-variable-percentages-depending-on-page\">1. Variable percentages depending on page<\/h2>\n<p>The easiest customization you can make is to track different percentages depending on the page in question. For example, on article pages in my blog I might be interested in tracking in increments of 25% of vertical depth scrolled. But on list pages and summary pages I might only be interested in knowing who scrolls down to the bottom.<\/p>\n<p>The <strong>Vertical Scroll Depths<\/strong> and <strong>Horizontal Scroll Depths<\/strong> fields require a number or a list of numbers (comma-separated) to work. Thus you can easily use a <strong>Custom JavaScript variable<\/strong> to return one list of numbers for a certain condition, and a different list of numbers for some other condition.<\/p>\n<p>For example, here\u2019s a Custom JavaScript variable that does what I described in the first paragraph of this chapter.<\/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>() {\n  <span style=\"color:#00a\">return<\/span> {{Page Path}}.indexOf(<span style=\"color:#a50\">'\/analytics\/'<\/span>) &gt; -<span style=\"color:#099\">1<\/span> ? <span style=\"color:#a50\">'25,50,75,100'<\/span> : <span style=\"color:#a50\">'75,100'<\/span>;\n}\n<\/code><\/pre>\n<\/div>\n<p>This variable returns the string <code>25,50,75,100<\/code> if the page URL contains <code>\/analytics\/<\/code>, and <code>75,100<\/code> otherwise. Thus, on blog pages, it will measure scroll depth in increments of 25 percent, but on other pages only scrolling up to 75% and 100% in depth.<\/p>\n<p>Then you can just add this variable to the trigger like so:<\/p>\n<div style=\"aspect-ratio: 1860 \/ 630;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/03\/get-variables-per-page-type.jpg\" title=\"Variables per page type\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"630\" width=\"1860\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/03\/get-variables-per-page-type.jpg#ZgotmplZ\" alt=\"Variables per page type\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>You don\u2019t <em>have<\/em> to use a Custom JavaScript variable. I\u2019m quirky in that I prefer to use it, always. But you could just as well use a <a href=\"https:\/\/www.simoahava.com\/analytics\/the-regex-table-variable-in-google-tag-manager\/\">RegEx Table variable<\/a> to achieve the same thing:<\/p>\n<div style=\"aspect-ratio: 1782 \/ 836;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/03\/regex-table-scroll-depths.jpg\" title=\"Regex table for scroll depths\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"836\" width=\"1782\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/03\/regex-table-scroll-depths.jpg#ZgotmplZ\" alt=\"Regex table for scroll depths\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>This is a simple customization, but it does allow you to measure relevant metrics for pages where it makes sense.<\/p>\n<h2 id=\"2-only-fire-the-scroll-depth-trigger-on-relevant-pages\">2. Only fire the scroll depth trigger on relevant pages<\/h2>\n<p>This should be a no-brainer, too. It might make sense to have the scroll depth trigger fire your tags only on pages where you are genuinely interested in scroll depth tracking. For example, I\u2019m actually only interested in knowing how far users scroll on my blog pages and nowhere else. Thus I could make this simple modification to the trigger to delimit its firing capabilities:<\/p>\n<div style=\"aspect-ratio: 1774 \/ 874;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/03\/fire-only-on-relevant-pages.jpg\" title=\"Fire scroll depth trigger only on relevant pages\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"874\" width=\"1774\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/03\/fire-only-on-relevant-pages.jpg#ZgotmplZ\" alt=\"Fire scroll depth trigger only on relevant pages\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>A very simple modification but helps you collect only meaningful data.<\/p>\n<h3 id=\"21-prevent-the-scroll-depth-trigger-from-activating\">2.1. Prevent the Scroll Depth trigger from activating<\/h3>\n<p>As you can see, there\u2019s no <a href=\"https:\/\/www.simoahava.com\/gtm-tips\/enable-fire-triggers-google-tag-manager\/\">\u201cEnable when\u2026&#8221;<\/a> option on the Scroll Depth trigger, similar to what you might see with a Just Links trigger, for example. Thus you might be tempted to think that there\u2019s no way to prevent those pesky <code>gtm.scrollDepth<\/code> events from populating the <code>dataLayer<\/code> on pages where you are not interested in tracking scroll depths.<\/p>\n<p>However, there\u2019s a very easy hack to make sure the trigger doesn\u2019t push anything to <code>dataLayer<\/code>. Just set the percentage threshold to <code>101<\/code>. It\u2019s impossible to scroll to 101% length of the page, so by setting the threshold to this you\u2019ll deactivate the trigger, effectively.<\/p>\n<p>Thus you could modify #2 above by putting the following Custom JavaScript variable into the <strong>Percentages<\/strong> field of the trigger:<\/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>() {\n  <span style=\"color:#00a\">return<\/span> {{Page Path}}.indexOf(<span style=\"color:#a50\">'\/analytics\/'<\/span>) &gt; -<span style=\"color:#099\">1<\/span> ? <span style=\"color:#a50\">'25,50,75,100'<\/span> : <span style=\"color:#a50\">'101'<\/span>;\n}\n<\/code><\/pre>\n<\/div>\n<p>This sets the thresholds to \u201825,50,75,100\u2019 on pages where the URL contains <strong>\/analytics\/<\/strong>, and \u2018101\u2019 elsewhere.<\/p>\n<h2 id=\"3-only-fire-tags-on-pages-where-thresholds-are-not-auto-collected\">3. Only fire tags on pages where thresholds are not auto-collected<\/h2>\n<p>One problem with the Scroll Depth trigger is that it doesn\u2019t care if the page is long or short. If you have a very short page, it\u2019s possible that all the thresholds are met when the page is loaded, which leads to a bunch of <code>gtm.scrollDepth<\/code> events pushed into <code>dataLayer<\/code>, firing your tags even though the user never scrolled!<\/p>\n<div style=\"aspect-ratio: 1168 \/ 562;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/03\/automatically-fire-trigger.jpg\" title=\"automatically fire scroll depth on short pages\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"562\" width=\"1168\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/03\/automatically-fire-trigger.jpg#ZgotmplZ\" alt=\"automatically fire scroll depth on short pages\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>Luckily there\u2019s a nifty trick we can use to fight this. We can prevent the Scroll Depth trigger from functioning on pages where the <strong>ratio between browser viewport height and page height is too high<\/strong>. The <strong>browser viewport<\/strong> is the area of the web browser that is filled by your page. The page itself is the entire document, parts of which are likely to be invisible below the fold of the viewport.<\/p>\n<p>The higher the ratio between the height of the visible viewport and the height of the page, the less there is to scroll. For example, if the visible viewport is 400 pixels in height, and the page height is also 400 pixels, there is nothing to scroll. The entire page will be visible in the viewport, and any vertical thresholds you have defined in the Scroll Depth trigger will auto-fire.<\/p>\n<p>So, if you want to only fire the trigger when the user actually scrolls to 25%, 50%, 75%, and 100%, you need to make sure the ratio between the visible viewport height and the page height is <em>less than 0.25<\/em>. This means that less than 25% of the page is visible in the browser viewport.<\/p>\n<p>To do this, you need to create a <strong>Custom JavaScript variable<\/strong> that looks 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>() {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Change this to reflect the percentages or pixels you want to fire the trigger for\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> verticalScrollDepths = <span style=\"color:#a50\">'25,50,75,100'<\/span>;\n  \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Change this to the MAXIMUM ratio of viewport height \/ page height you want the trigger to activate for\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> maximumRatio = <span style=\"color:#099\">0.25<\/span>;\n  \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Change this to what thresholds should be tracked if the ratio is more than the maximum\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#aaa;font-style:italic\">\/\/ Leave it at '101' if you want to prevent the trigger from functioning in this case\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> fallbackDepths = <span style=\"color:#a50\">'101'<\/span>;\n  \n  <span style=\"color:#00a\">var<\/span> heightOfPage = <span style=\"color:#0aa\">Math<\/span>.max(<span style=\"color:#0aa\">document<\/span>.body.scrollHeight, <span style=\"color:#0aa\">document<\/span>.body.offsetHeight, <span style=\"color:#0aa\">document<\/span>.documentElement.clientHeight, <span style=\"color:#0aa\">document<\/span>.documentElement.scrollHeight, <span style=\"color:#0aa\">document<\/span>.documentElement.offsetHeight);\n  \n  <span style=\"color:#00a\">var<\/span> heightOfViewport = <span style=\"color:#0aa\">Math<\/span>.max(<span style=\"color:#0aa\">document<\/span>.documentElement.clientHeight, <span style=\"color:#0aa\">window<\/span>.innerHeight);\n  \n  <span style=\"color:#00a\">var<\/span> ratio = heightOfViewport \/ heightOfPage;\n  \n  <span style=\"color:#00a\">return<\/span> ratio <\/code><\/pre>\n<\/div>\n<p>First thing you\u2019ll need to do is edit the <code>verticalScrollDepths<\/code> variable to reflect the list of thresholds you want to track if the page passes the ratio check.<\/p>\n<p>Then, edit the <code>maximumRatio<\/code> to reflect the maximum ratio (between 0 and 1) of the height of the visible viewport vs. height of the actual page. A value of <code>0.25<\/code> would mean that at most 25% of the page can be visible in the viewport when the page is loaded.<\/p>\n<p>Finally, edit the <code>fallbackDepths<\/code> variable to give a \u201cdefault\u201d value for the cases when the maximum ratio is surpassed. If you want to prevent the Scroll Depth trigger from working at all when the maximum ratio is surpassed, use the value <code>101<\/code>, because a depth of 101% can never be tracked.<\/p>\n<p>Then just add this to the \u201cVertical Scroll Depths\u201d field and you should be all set.<\/p>\n<p>Now the trigger will only fire in cases where the page is long enough to make sense for your tracking.<\/p>\n<h2 id=\"4-track-scroll-percentages-of-a-specific-content-element\">4. Track scroll percentages of a specific content element<\/h2>\n<p>This is a bit trickier, but still doable with some JavaScript magic.<\/p>\n<p>By default, the Scroll Depth trigger calculates vertical scrolling depth from the top of the page to the bottom of the page. But you might only be interested in knowing the scroll depths of a specific content element, such as the article body. For example, on my site, I don\u2019t really care if users scroll past the article end, through the Disqus comments, all the way to the bottom. But I do care if they scroll to the bottom of the main article body.<\/p>\n<p>The way to make this work is to first calculate the height of the HTML element that contains the content whose scroll depths you want to track. Then, you need to check how far from the top of the page this element is. Finally, you need to tell the Scroll Depth trigger to track pixel thresholds that correspond with the desired depths of the content element, and add the distance to the top of the page to those numbers.<\/p>\n<p>I think it\u2019s easier to illustrate.<\/p>\n<div style=\"aspect-ratio: 1874 \/ 1598;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/03\/dynamic-scroll-thresholds.jpg\" title=\"dynamically resolved scroll thresholds\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"1598\" width=\"1874\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/03\/dynamic-scroll-thresholds.jpg#ZgotmplZ\" alt=\"dynamically resolved scroll thresholds\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>As you can see, the total height of the element is <strong>1200 pixels<\/strong>. If I want to track scroll depth increments of 33%, it means that the respective marks are at 400, 800, and 1200 pixels. Since the top of the content element is exactly <strong>250 pixels<\/strong> from the top of the page, I need to add this number to the thresholds before I feed it into the Scroll Depth trigger, because it measures everything counting from the top of the page. Thus the final pixel depths would be <strong>650<\/strong>, <strong>1050<\/strong>, and <strong>1450<\/strong> pixels.<\/p>\n<p>Now, since we don\u2019t want to hard-code these into the trigger, as that would lead to a horrible mess to manage (every single page would need its own trigger), we can use a <strong>Custom JavaScript variable<\/strong> to dynamically calculate the pixel depths.<\/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>() {\n  <span style=\"color:#aaa;font-style:italic\">\/\/ Change the contents of this array to reflect the percentages of scroll depth you want to track\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> verticalPercentages = [<span style=\"color:#099\">25<\/span>,<span style=\"color:#099\">50<\/span>,<span style=\"color:#099\">75<\/span>,<span style=\"color:#099\">100<\/span>];\n  \n  <span style=\"color:#aaa;font-style:italic\">\/\/ Change this to fetch the element you want to track scrolling in\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>  <span style=\"color:#00a\">var<\/span> targetElement = <span style=\"color:#0aa\">document<\/span>.querySelector(<span style=\"color:#a50\">'div.post-content .main-content-wrap'<\/span>);\n  \n  <span style=\"color:#00a\">var<\/span> elementHeight = targetElement.offsetHeight;\n  \n  <span style=\"color:#00a\">var<\/span> totalOffsetTop = <span style=\"color:#099\">0<\/span>;\n  \n  <span style=\"color:#00a\">while<\/span> (targetElement) {\n    totalOffsetTop += (targetElement.offsetTop - targetElement.scrollTop + targetElement.clientTop);\n    targetElement = targetElement.offsetParent;\n  }\n  \n  <span style=\"color:#00a\">return<\/span> verticalPercentages.map(<span style=\"color:#00a\">function<\/span>(percentage) {\n    <span style=\"color:#00a\">return<\/span> <span style=\"color:#0aa\">parseInt<\/span>(elementHeight * (percentage * <span style=\"color:#099\">0.01<\/span>) + totalOffsetTop);\n  }).join();\n}\n<\/code><\/pre>\n<\/div>\n<p>You\u2019d then need to add this variable reference to the <strong>Pixel<\/strong> field in the Vertical Scroll Depths selection of the trigger:<\/p>\n<div style=\"aspect-ratio: 1156 \/ 488;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2018\/03\/vertical-scroll-increments.jpg\" title=\"Dynamically computed vertical scroll increments\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"488\" width=\"1156\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2018\/03\/vertical-scroll-increments.jpg#ZgotmplZ\" alt=\"Dynamically computed vertical scroll increments\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>This setup calculates dynamically the correct pixel thresholds based on the percentages you wrote in the <code>verticalPercentages<\/code> array. This way, 0 percent depth is the top of the content element (specified in <code>targetElement<\/code>), and 100 percent depth is the bottom of the content element.<\/p>\n<p>With this workaround, you can get more meaningful measurements on pages which have lots of different content areas filling up the real estate of the document itself.<\/p>\n<h3 id=\"41-return-the-scroll-depth-percentage-of-element-scrolling\">4.1. Return the scroll depth percentage of element scrolling<\/h3>\n<p>One thing missing from #4 is the option to report on the <em>percentages<\/em> the user scrolled down the element. Because the trigger is setup using pixel depths rather than percentages, the {{Scroll Depth Threshold}} built-in variable will always return the pixel depth the user scrolled past, rather than the respective percentage of scrolling.<\/p>\n<p>Getting the percentage is actually a bit of a hack. The problem with the Scroll Depth trigger is that it\u2019s initialized fairly early in the page load, often before DOM Ready and any dynamically injected content is added to the page. This means that the thresholds of scrolling might be smaller than what the percentages <em>actually<\/em> would reflect.<\/p>\n<p>This is, unfortunately, unavoidable right now. The Scroll Depth trigger has no options to delay its initialization until such a time as the content is completely loaded.<\/p>\n<p>What this also means is that any variables you use to determine the height of the content and, subsequently, what the respective percentages actually reflect, can change from one trigger event to the next. Thus, in order to get the <em>actual<\/em> percentages used by the Scroll Depth trigger, we\u2019ll need to do something that I\u2019ve <a href=\"https:\/\/www.simoahava.com\/analytics\/100-google-tag-manager-learnings\/#76-should-avoid-side-effects\">repeatedly<\/a> instructed to avoid at all costs: implement a side effect in the Custom JavaScript variable.<\/p>\n<p>Basically, we\u2019ll need to store the scroll thresholds in a <strong>global<\/strong> variable when the Custom JavaScript variable is first run. After the initial run, we\u2019ll always pull whatever was stored in the global variable instead of generating a new set each time the variable is invoked. This way, any triggers and tags that use the thresholds will always access the same values, even if they might be off a bit from what the content thresholds <em>actually<\/em> are.<\/p>\n<p>The modification looks 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>() {\n  \n  <span style=\"color:#00a\">if<\/span> (<span style=\"color:#00a\">typeof<\/span> <span style=\"color:#0aa\">window<\/span>._gtm_scroll_set === <span style=\"color:#a50\">'undefined'<\/span>) {\n    \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Change the contents of this array to reflect the percentages of scroll depth you want to track\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> verticalPercentages = [<span style=\"color:#099\">25<\/span>,<span style=\"color:#099\">50<\/span>,<span style=\"color:#099\">75<\/span>,<span style=\"color:#099\">100<\/span>];\n  \n    <span style=\"color:#aaa;font-style:italic\">\/\/ Change this to fetch the element you want to track scrolling in\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>    <span style=\"color:#00a\">var<\/span> targetElement = <span style=\"color:#0aa\">document<\/span>.querySelector(<span style=\"color:#a50\">'div.post-content .main-content-wrap'<\/span>);\n  \n    <span style=\"color:#00a\">var<\/span> elementHeight = targetElement.offsetHeight;\n  \n    <span style=\"color:#00a\">var<\/span> totalOffsetTop = <span style=\"color:#099\">0<\/span>;\n  \n    <span style=\"color:#00a\">while<\/span> (targetElement) {\n      totalOffsetTop += (targetElement.offsetTop - targetElement.scrollTop + targetElement.clientTop);\n      targetElement = targetElement.offsetParent;\n    }\n    \n    <span style=\"color:#0aa\">window<\/span>._gtm_scroll_set = {\n      thresholds: verticalPercentages.map(<span style=\"color:#00a\">function<\/span>(percentage) {\n          <span style=\"color:#00a\">return<\/span> <span style=\"color:#0aa\">parseInt<\/span>(elementHeight * (percentage * <span style=\"color:#099\">0.01<\/span>) + totalOffsetTop);\n        }).join(),\n      percentages: verticalPercentages\n    };\n    \n  }\n  \n  <span style=\"color:#00a\">return<\/span> <span style=\"color:#0aa\">window<\/span>._gtm_scroll_set.thresholds;\n}\n<\/code><\/pre>\n<\/div>\n<p>As you can see, we populate a global variable <code>window._gtm_scroll_set<\/code> with an object that contains two properties:<\/p>\n<p>Now that we know what the thresholds are, what the percentages are, and we can trust that the same thresholds are returned whenever this Custom JavaScript variable is invoked, we can create <strong>another<\/strong> Custom JavaScript variable whose only job is to return which percentage the user scrolled past when the trigger fired. This is what that variable looks 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>() {\n  <span style=\"color:#00a\">if<\/span> (<span style=\"color:#00a\">typeof<\/span> <span style=\"color:#0aa\">window<\/span>._gtm_scroll_set !== <span style=\"color:#a50\">'undefined'<\/span>) {\n    \n    <span style=\"color:#00a\">var<\/span> percentages = <span style=\"color:#0aa\">window<\/span>._gtm_scroll_set.percentages;\n  \n    <span style=\"color:#00a\">var<\/span> thresholds = <span style=\"color:#0aa\">window<\/span>._gtm_scroll_set.thresholds.split(<span style=\"color:#a50\">','<\/span>).map(<span style=\"color:#00a\">function<\/span>(t) {\n      <span style=\"color:#00a\">return<\/span> <span style=\"color:#0aa\">parseInt<\/span>(t);\n    });\n    \n    <span style=\"color:#00a\">var<\/span> crossedIndex = thresholds.indexOf({{Scroll Depth Threshold}});\n\n    <span style=\"color:#00a\">return<\/span> percentages[crossedIndex];\n  \n  }\n  <span style=\"color:#00a\">return<\/span> {{Scroll Depth Threshold}};\n}\n<\/code><\/pre>\n<\/div>\n<p>This Custom JavaScript variable checks which threshold was returned by {{Scroll Depth Threshold}}, and returns the respective percentage value.<\/p>\n<p>The order of things is thus:<\/p>\n<ol>\n<li>\n<p>Use the first Custom JavaScript variable in the Scroll Depth trigger\u2019s Pixel Depths field.<\/p>\n<\/li>\n<li>\n<p>Use the second Custom JavaScript variable wherever you want to get the percentage value for the scroll depth reached when the trigger fires.<\/p>\n<\/li>\n<\/ol>\n<p>Note that even though I am introducing a side effect in the Custom JavaScript variable, it is mitigated by checking if the global variable has already been set. Thus the typical downside of side effects (constantly and unpredictably updating global state) is mitigated.<\/p>\n<p>It\u2019s not perfect &#8211; nothing that impacts global state ever is. There\u2019s always the risk that some other JavaScript accesses and modifies <code>window._gtm_scroll_set<\/code>, which would break your setup.<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>These four tips ranged from the really simple to the moderately complex.<\/p>\n<p>There are many ways in which you can customize Google Tag Manager\u2019s default trigger. With the scroll depth trigger, these customizations are almost necessary, because the trigger itself is lacking in some critical configurations options for now.<\/p>\n<p>For example, I would like to see the following features in the trigger:<\/p>\n<ul>\n<li>\n<p>Option to establish <strong>when<\/strong> the trigger is initialized (e.g. after DOM Ready, with a Data Layer event, etc.).<\/p>\n<\/li>\n<li>\n<p>Option to prevent the trigger from auto-firing if the thresholds have been crossed when the page loads.<\/p>\n<\/li>\n<li>\n<p>Option to reset the trigger manually, which is useful especially on single-page apps.<\/p>\n<\/li>\n<li>\n<p>Option to define a content element instead of the entire page for determining scroll depth.<\/p>\n<\/li>\n<\/ul>\n<p>With the tips in this article, you can do plenty, but especially the feature where you could reset the trigger is sorely missing from the current implementation.<\/p>\n<p>Do you have tips you want to share for Google Tag Manager\u2019s Scroll Depth trigger?<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Last updated 9 March 2018 with some new tips. The Scroll Depth trigger in Google Tag Manager has a lot going for it. Tracking how far users scroll down a given page has long since been recognized as an important cog in the engagement tracking machine, and there have been really great solutions for implementing [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":108924,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[39407,1375,1531,14495,15981,1791,22089],"dealstore":[],"offerexpiration":[],"class_list":["post-108923","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-customize","tag-depth","tag-google","tag-manager","tag-scroll","tag-tag","tag-trigger"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Customize The Scroll Depth Trigger 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=108923\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Customize The Scroll Depth Trigger In Google Tag Manager - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"Last updated 9 March 2018 with some new tips. The Scroll Depth trigger in Google Tag Manager has a lot going for it. Tracking how far users scroll down a given page has long since been recognized as an important cog in the engagement tracking machine, and there have been really great solutions for implementing [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=108923\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-25T10:20:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1860\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\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=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=108923#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=108923\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"Customize The Scroll Depth Trigger In Google Tag Manager\",\"datePublished\":\"2025-02-25T10:20:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=108923\"},\"wordCount\":2162,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=108923#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg\",\"keywords\":[\"customize\",\"Depth\",\"Google\",\"Manager\",\"Scroll\",\"TAG\",\"Trigger\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=108923#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=108923\",\"url\":\"https:\/\/fivemor.com\/?p=108923\",\"name\":\"Customize The Scroll Depth Trigger In Google Tag Manager - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=108923#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=108923#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg\",\"datePublished\":\"2025-02-25T10:20:15+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=108923#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=108923\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=108923#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg\",\"width\":1860,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=108923#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Customize The Scroll Depth Trigger 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":"Customize The Scroll Depth Trigger 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=108923","og_locale":"en_US","og_type":"article","og_title":"Customize The Scroll Depth Trigger In Google Tag Manager - Som2ny Network","og_description":"Last updated 9 March 2018 with some new tips. The Scroll Depth trigger in Google Tag Manager has a lot going for it. Tracking how far users scroll down a given page has long since been recognized as an important cog in the engagement tracking machine, and there have been really great solutions for implementing [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=108923","og_site_name":"Som2ny Network","article_published_time":"2025-02-25T10:20:15+00:00","og_image":[{"width":1860,"height":630,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=108923#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=108923"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"Customize The Scroll Depth Trigger In Google Tag Manager","datePublished":"2025-02-25T10:20:15+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=108923"},"wordCount":2162,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=108923#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg","keywords":["customize","Depth","Google","Manager","Scroll","TAG","Trigger"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=108923#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=108923","url":"https:\/\/fivemor.com\/?p=108923","name":"Customize The Scroll Depth Trigger In Google Tag Manager - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=108923#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=108923#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg","datePublished":"2025-02-25T10:20:15+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=108923#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=108923"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=108923#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/scroll-depth-trigger-customizations.jpg","width":1860,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=108923#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"Customize The Scroll Depth Trigger 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\/108923","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=108923"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/108923\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/108924"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=108923"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=108923"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=108923"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=108923"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=108923"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}