Track dwell time with Google Tag Manager

This is one the hacks I love the most about Tag Manager, discovering bounce rates from users coming from Google search results. In other words, users coming from Google dwell on your page and then go back to a search result by clicking the back button on their browsers.

This metric is different than bounce rate, because bounce rate can be referred to any traffic source, not just Google organic traffic. And also bounce rate can be manipulated on Google Analytics, hence it’s not a ranking signal.

Dwell time instead is referred only and exclusively to Google as traffic source and cannot be manipulated. It can be, however, measured. This is a great indication of relevancy between what users search, click and then find on your landing page. So, in theory, the longer users stay on your landing page (without going back to SERPs), the more relevant your result was for Google.

This hack is very complex to implement so but it works if done right. The idea for this post came to from a case study I am presenting at SMXL Milan 2018, where I speak about the link between user experience on the landing page and increased rankings on Google. During my preparation for the case study, I have read an experiment back in 2015 from Rand Fishkin about dwell time. Google must have been taking this metric very seriously because if users go back to search results very quickly, the result wasn’t relevant for them.

So the metric that everyone said cannot be measured, but only guessed, made me think.

What if it can be measured?

And I wanted to start measuring it to have better reports on Google Analytics. Luckily we got Tag Manager that allows us to do just this: measure dwell time.

Challenges with tracking dwell time

One of the most challenging problems with this metric is that, for tracking it, we would need to know where the user go after he clicks the back button on his browser: but we don’t have any clue where it goes. This is your browser security right there.

The other problem is the back button on the browser: we can’t measure that either because the button is not on your web page, it’s outside of it.

Luckily I am not the first one to encounter – and try to solve – these problems as Simo Ahava resolved them before me with an amazing, yet complex, hack. So I am going to thank Simo and use his JavaScript for tracking users’ browser history.


We hereby create the first of 2 tags to setup our hack.

  1. Go on Tag Manager
  2. Click new Tag
  3. Choose Custom HTML Tag
  4. Name it “GA – Dwell time – HTML”
  5. Insert the JavaScript code provided below
  6. Click Save


(function() {

var s =;

var h = document.location.hash;

var e = {{Event}};

var n = {{New History Fragment}};

var o = {{Old History Fragment}};

// Only run if the History API is supported

if (window.history) {

// Create a new history state if the user lands from Google’s SERP

if (e === ‘gtm.js’ &&

document.referrer.indexOf(‘’) > -1 &&

s.indexOf(‘gclid’) === -1 &&

s.indexOf(‘utm_’) === -1 &&

h !== ‘#gref’) {

window.oldFragment = false;


} else if (e === ‘gtm.js’) {

window.oldFragment = true;


// When the user tries to return to the SERP using browser back, fire the

// Google Analytics timing event, and after it’s dispatched, manually

// navigate to the previous history entry, i.e. the SERP

if (e === ‘gtm.historyChange’ &&

n === ” &&

o === ‘gref’) {

var time = new Date().getTime() – {{DLV – gtm.start}};

if (!window.oldFragment) {


‘event’ : ‘returnToSerp’,

‘timeToSerp’ : time,

‘eventCallback’ : function() {




} else {








This is a simple double-check to make sure the variables are ticked.

You also need Page URL and Event variables ticked.


In this step you learn how to instruct Tag Manager to track a browser history event, that we can call popstate.

Trigger number 1

  1. Go to trigger
  2. Create New Trigger
  3. Name it : Event – History Change with gref
  4. Trigger type: History Change
  5. Trigger Fires on: Some history changes
  6. From the Drop Down menu choose “New History Fragment”
  7. Second Drop Down: Matches Regex and then ^$
  8. From the Second Drop Down menu choose “History Source”
  9. Drop menu next to it: equals and then popstate
  10. Save

This Trigger only launches when a browser history event is detected which is also a popstate, and the new history fragment is empty.

Trigger number 2

The second trigger is a default All Pages trigger. This is the screenshot:


Create the following Data Layer Variables.

Variable 1: This one stores the time when the GTM container snippet was executed.

Variable 2: This is where the time spent on the landing page is stored.


With this trigger, you instruct Tag Manager to fire a custom event that is the ReturnToSerp, which is pushed via the Custom HTML Tag (we have built this before).

Also, we have instructed Tag Manager not to start a new session if the user stays longer than 30 minutes, which is the default time for a session to expire in Google Analytics.


This is the last step of this guide, where you create the timing tag. With this tag, we are setting the timing category in Google Analytics and a Page URL as variable, together with time spent on the landing page as value.

This tag is fired by the trigger we created in the 5: Event – ReturnToSerp

  1. Go to Tags
  2. Click New Tag
  3. Name it GA – Event – Serp Bounce
  4. Tag Type: choose Google Universal Analytics
  5. Track Type: Timing
  6. Var: {{Page URL}}
  7. Category: SERP Bounce (just type it)
  8. Value: {{DLV – timeToSerp}}
  9. Label : leave it blank
  10. Google Analytics Settings: You google analytics variable
  11. Triggering: Event – ReturnToSerp
  12. Save


Start the preview on Tag Manager and check the tags firing. If they do, you can publish your work.

Now it’s time to check the reports in Google Analytics:

  1. Go to Behaviour
  2. Site Speed
  3. User Timing

If you click on SERP bounce, you are going to see a report like this one:


Now try to get into the data and click to SERP Bounce highlighted above to dig into each individual SERP landing page URL and their bounce timings. This is how I would use the report.

Grab information on SERP URLs and associated dwell times

The dwell time is a great indication of content and user experience. Normally high dwell time can indicate good user experience and great content.

Better measure engagement on a page

If you use Dwell time report and Scroll Rate report for a page, you can have a pretty good idea of what readers are doing on your page. Are they scrolling down? Or are they just distracted by something else and not scrolling anywhere?

Look at below 10 seconds average SERP bounce

If your URLs show a bounce from SERP below 10 seconds, it’s likely they only read above the fold content, but not much else. It’s an indication the page is not worth reading.

Higher granularity with further dimensions

Even though I don’t use them as much, city, country and other secondary dimensions can help you gather more data.

Using country dimensions will let you know how your landing pages are used internationally, which is of course highly useful if you target users in more than one country.

If you’re doing a lot of content marketing, perhaps you’ll use the page URL report to only check URLs that have low SERP bounce (according to whatever you establish as low), while filtering by country is great for international sites, as you might expect.


This report doesn’t report ALL the data, but some data. There is so much more work to be done to find data on a keyword level, but I haven’t uncovered this yet.

Dwell time is tracked by Google and it’s a ranking factor so measuring it is one of your top priorities in digital analytics.

Recent Posts

Looking for Higher Rankings in 2023?

Receive 9 SEO guides & resources (Advanced stuff)