Upcoming LunaMetrics Events
San Francisco, Apr 28-30 Los Angeles, May 12-16 New York City, May 19-23 Chicago, Jun 16-18

Cheat and Win with Google Tag Manager: Easy Dynamic Content Tracking

Sometimes Tag Manager is so easy it feels like cheating. In a good way. Like getting a super acorn power-up and turning into Flying Squirrel Mario.


Recently I used my flying squirrel powers to beat the dynamic content boss. My client wanted to track how visitors used a couple different search forms, each with multiple options. Every time an option was selected, new search results would appear dynamically and a parameter would be added to the URL hash.

For example, if the visitor chose to view all the seminars on day 1, the URL would become /seminarsearch#day=1. Search those seminars by topic X and the URL would change to /seminarsearch#day=1&topic=x.

Or it might be a different search form, say for vendors, and the URL might look like /vendorsearch#category=abc&location=bldg2.

How was I going to tackle all those moving parts and get the data I needed into Google Analytics? I wrote a couple different pieces of code that were unsatisfactory for one reason or another.

And then I found my super acorn.

<script type="text/javascript">
window.onhashchange = function() {


Deceptively simple! Don’t worry about listening for clicks and trying to identify if they’re the clicks I’m interested in. Just detect when the hash changes and send an event to the data layer. This tag fires on every search form page.

Now I use the data layer event to control all kinds of tracking. When a visitor interacts with one of my search forms, an event rule (“event=hashchange”) fires these tags:

  1. a virtual pageview – it’s a new page of content, so I treat it that way – I capture the URL with the hash, which means for each of those extended URLs I get all the page metrics in my GA content reports (not to mention more useful flow viz reports and the ability to create goal funnels, although I haven’t done that yet)
  2. a search form click event – so I can get site usage and ecommerce metrics, along with the hierarchy of the GA event reports
  3. plus scroll tracking events! – from Justin Cutroni’s scroll tracking code, which I adapted for Tag Manager (did the visitor start scrolling through the search results and did they scroll all the way to the bottom? I included the custom variable for how fast they scrolled)

Here’s the adapted part (get the entire original tag here):

// If user starts to scroll send an event
if (bottom > scrollerLocation && !scroller) {
    currentTime = new Date();
    scrollStart = currentTime.getTime();
    timeToScroll = Math.round((scrollStart - beginning) / 1000);
    if (!debugMode) {
        dataLayer.push({'event':'scrolling', 'eventAction':'start-scrolling', 'eventLabel':'{{url path}}', 'eventValue':timeToScroll});
    } else {
        alert('started scrolling ' + timeToScroll);
    scroller = true;

// If user has hit the bottom of the results, then send an event
if (bottom >= $('#results').scrollTop() + $('#results').innerHeight() && !endContent) {
    currentTime = new Date();
    contentScrollEnd = currentTime.getTime();
    timeToContentEnd = Math.round((contentScrollEnd - scrollStart) / 1000);
    if (!debugMode) {
        if (timeToContentEnd < 30) {
            dataLayer.push({'customVarKey':'scroller-type', 'customVarValue':'scanner'});
        } else {
            dataLayer.push({'customVarKey':'scroller-type', 'customVarValue':'reader'});
        dataLayer.push({'event':'scrolling', 'eventAction':'content-bottom', 'eventLabel':'{{url path}}', 'eventValue':timeToContentEnd});
    } else {
        alert('end content section '+ timeToContentEnd);
    endContent = true;
    didComplete = true;

The scroll tracking tag fires either after the window loads or when the hash changes, with a simple revision of the rule from “event equals hashchange” to “event matches RegEx gtm.load|hashchange”. That way I don’t have to wait for the visitor to click any options, in case they start scrolling through the default content (featured seminars or vendors).

And then finally I have tags that fire when the scroll tracking tag pushes events to the data layer. These tags send my events and custom variables to Google Analytics.

custom var gtm

Remember: to make sure your custom variable info is not just set, but also sent, hitch it to an event. Tag Manager makes it easy with the options under “More Settings” as shown above.

Has dynamic content made it more difficult to get the data you need to answer important questions? How have you tackled it? Please share in the comments.

Dorcas Alexander

About Dorcas Alexander

Dorcas Alexander is a Digital Analyst working with Google Analytics. Her path to LunaMetrics included stints in ad agency creative, math, computer science, language technology research, and corporate training. She loves to learn and teach what she’s learned. One of the top-rated tournament Scrabble players in Pennsylvania, Dorcas has an insatiable drive to compete and win. “Impossible” is not in her vocabulary.


5 Responses to “Cheat and Win with Google Tag Manager: Easy Dynamic Content Tracking”

Sheldon says:

Hi Dorcas,

Thank you so much for this article. I have found very little information regarding the correct use of Google Tag Manager, for more complicated subjects like Dynamic Custom Variables and javascript.

I would love to read any more articles that you have!


Lorraine says:

Hi Dorcas,

Thanks for the article. Great reading with easy to follow instructions.

Did you publish the window.onhashchange script through Tag Manager or place it directly in the source code of the page. I have been trying to do something very similar for a while now and the problem I have is that because the anchored page is not a new page load, GTM doesn’t load up tags unless I refresh the page.


Dorcas Alexander Dorcas Alexander says:

Hi Lorraine, Yes, I have window.onhashchange in a tag, not in the source code of the page. Instead of using a rule to fire your tag on the anchored page (which you’ve found won’t work anyway), use a rule that fires it on the non-anchored page path. You should have other tags that can fire later based on event=hashchange. But the tag that detects the hash change can fire earlier and sit there waiting to do its job. Hope that helps!

Primož says:


I just started using google tag manager. I managed to merge different domains to a single analytics property and some other things. Now I am trying to track hashtags as pageviews so I can create Goal funnel with them.

My question is: where do I put your “super acorn”, under custom html or..? And will this help me with hashtag tracking as pageview?

Dorcas Alexander Dorcas Alexander says:

Hi Primož, Create a custom HTML tag and insert the super acorn script. Then create a pageview tag that fires when event = hashchange, and in this tag set up the virtual pageview under More settings > Basic Configuration > Virtual Page Path. You can send whatever you want as the virtual page path. In my tag, I send window.location.pathname + window.location.search + window.location.hash.

Leave a Reply