Track Adjusted Bounce Rate In Universal Analytics

ShareShare on Google+17Tweet about this on Twitter3Share on LinkedIn2Share on Facebook0

So here we are again. Universal Analytics and Google Tag Manager, the dynamic duo, ready to strike again.

First, remember to check my previous two tips for UA and GTM use in custom scenarios:

* Weather as a custom dimension
* Tracking page load time

In this post, I visit the idea of adjusted bounce rate, which I came across a year ago in the Google Analytics blog.

Adjusted bounce rate basically refers to tweaking the traditional bounce rate collection method (single engagement hits / total visits) so that visits which only included a single page view would not count towards a bounce, as long as they met some qualitative requirements.

By the way, check this great post on bounce rate by Yehoshua Coren if you need a refresher on what the term means.

For these custom events, I use the generic event container I created in my previous post.

The easy method: visit duration

This is the easiest to implement. It’s also the one in the Google Analytics blog post I referred to above.

What it does is fire a setTimeout() method as soon as the page has loaded. If the timer runs out (the time is 30 seconds in this script), an interaction event is fired, meaning the visit is not counted as a bounce.

The end result is this:
Calculate visit duration

And here’s how to do it.

1. Create a new custom tag called “Dwell time”
2. Set Tag Type as Custom HTML tag
3. Add the following code in the HTML field:

<script>
setTimeout("dataLayer.push({ 'event': 'GAEvent', 'eventCategory': 'NoBounce', 'eventAction': 'Over 30 seconds' })", 30000);
</script>

4. Add {{event}} equals gtm.dom as the firing rule
5. Save tag
6. Save container and publish

See, I told you it was easy. What happens here is that after the DOM has loaded (the firing rule), a timer starts. If the user stays on the page when the timer goes off, the event is fired. Remember, you need the generic event container for this to work. So remember to check my previous post for instructions how to build it (it’s easy, I promise!).

The intermediate method: measure scrolling

This method was inspired by a Google+ post I came across by Avinash Kaushik, where he detailed a script written by Nick Mihailovski. This script is used here extensively, with just the event call in a different format (to support UA and GTM).

What happens here is that the event listener waits for a scroll event (so you actually scroll the page down), and fires the no-bounce event after that. Interesting! The statement is that if you scroll, you read, and if you read, you’re engaged (with the content).

1. Create a new tag “Scroll the page”
2. Set Tag Type as Custom HTML tag
3. Add the following code in the HTML field

<script>
window.addEventListener ?
  window.addEventListener('scroll', testScroll, false) :
  window.attachEvent('onScroll', testScroll);

var scrollCount = 0;

function testScroll() {
  ++scrollCount;
  if (scrollCount == 2) {
    dataLayer.push({ 'event': 'GAEvent', 'eventCategory': 'NoBounce', 'eventAction': 'Scrolled the page' });
  }
}
</script>

4. Set {{event}} equals gtm.dom as the firing rule
5. Save tag
6. Save container and publish

And you’re done. So what the script does is measure if a scroll event occurs during your page view. If it does, the event is fired. Note that it won’t fire the event with every subsequent scroll, so you don’t have to worry about clogging your 500 events per session quotas.

This isn’t fool-proof, of course. It just checks whether the user scrolls. What this DOES prevent is the miscalculation of page visit duration if the user just opens the page in a separate tab and leaves it be. Now you actually need interaction, albeit a very minimal one, to produce an engagement and neutralize the bounce.

The advanced method: page load AND scroll

So what about measuring whether there was a scroll event and the visit duration on the page was over 30 seconds? Wouldn’t that be an even better way to calculate engagement? I think so. So here’s what you do. First, make sure the two tags you just created are not active any more (otherwise you’ll be sending multiple bounce-wrecking events).

1. Create new tag “Dwell and scroll”
2. Set Tag Type as Custom HTML Tag
3. Add the following code in the HTML field:

<script>
var visitTookTime = false;
var didScroll = false;
var bounceSent = false;

setTimeout("timeElapsed()", 30000);

window.addEventListener ?
  window.addEventListener('scroll', testScroll, false) :
  window.attachEvent('onScroll', testScroll);

var scrollCount = 0;

function testScroll() {
  ++scrollCount;
  if (scrollCount == 2) { didScroll = true };
  sendNoBounce();
}

function timeElapsed() {
  visitTookTime = true;
  sendNoBounce();
}

function sendNoBounce() {
  if ((didScroll) && (visitTookTime) && !(bounceSent)) {
    bounceSent = true;
    dataLayer.push({ 'event': 'GAEvent', 'eventCategory': 'NoBounce', 'eventAction': 'Time spent and page scrolled' });
  }
}
</script>

4. Set {{event}} equals gtm.dom as the firing rule
5. Save tag
6. Save container version and publish

Here the timer starts first. As soon as it hits 30 seconds, it calls the sendBounce() method. This method checks if the user has also scrolled, and if they have, the event is fired. Note that I also make sure that the event is sent only once with the boolean variable bounceSent.

When the user scrolls, the same method is called and the same check is made.

So there are four different scenarios resulting from this script:

1) The user doesn’t scroll, but stays on the page for 0-to-infinite seconds, and the event is not fired (visit is a bounce)
2) The user scrolls, but the timer hasn’t gone off, and the event is not fired (visit is a bounce)
4) The timer goes off, and the user has already scrolled, and the event is fired (visit is not a bounce)
5) The user scrolls, and the timer goes off, and the event is fired (visit is not a bounce)

A much healthier way of calculating adjusted bounce rate, in my opinion.

Conclusion

The way you measure bounce rate should always be in relation to the goals you set for a page or for your site. If engagement is important, remember to add clear calls-to-action, so that you don’t have to resort to artificial adjustments like those depicted in this post.

However, for a simple blog like this, measuring engagement by a combination of visit time and scrolling interaction is probably a pretty good way of getting a more realistic metric for tracking visit quality.

An even more advanced (and qualitative) method would be to see just where the user scrolls to. Is it to the end of the post or just the first paragraph? In other words, does the user read or just skim. That’s a crucial question, and I might just return to the issue in a later post.

ShareShare on Google+17Tweet about this on Twitter3Share on LinkedIn2Share on Facebook0

Comments

  1. Jim says

    Hi Simo,

    The above script look good; I am using similar script for the old tracking code right now and want to switch to Universal.

    I have tried the Easy Method but no luck yet. The Universal status is still Tracking Not Installed, so I should try it again after a couple of days.

    Is it possible to put a copy/paste version of the Advanced Method. It’s so long…

    Thanks for the clear explanation. Very useful!

    Jim

      • Jim says

        Great! I’m going to try it again since on the Analytics side everything is working.

  2. says

    Hi,
    I’m using the Google Analyticator WordPress which allows inserting code before and/or after the Universal tracking code initialisation. Is this where I could insert your codes if using a plugin. I’d love to have my GA stuff confined in a plugin for better management.
    Thanks for a great article too. I was using something similar for the old GA code.

    • says

      Hi Martin,

      Google Tag Manager is a self-sufficient system, and it’s not optimal to have it running alongside other Google Analytics tracking implementations. So the best way to do it is to:

      * Just have the GTM container code right after the opening tag
      * Not have any other Google Analytics tracking codes on the page template

      You can use GTM to set up Analytics without the need for any WordPress plugins. Sure, you can use a WP-plugin to insert the GTM container code, but other than that, GTM will handle (almost) all your tracking needs.

  3. says

    Hmm, I’ve got a default Tag Manager Universal Analytics tag and added your Dwell and Scroll.
    I can’t see that it is working at all. I would have thought I’d see an Event fire when I look at GA Real Time > Events but I’ve never seen one.
    Am I doing this right or have I missed something? I do love what you’re doing with Tag Manager, great info.

    • says

      Hi Martin,

      Have you created the generic event container?

      You need it for these scripts to work, since they push data in to the data layer, which is then processed and sent via the event tag.

      If you have and you still have problems, here are a few things to check:

      * Are you sure you’re running Universal Analytics on your site?
      * Do other GTM tags work fine?

      If you want more help, send mail to me at simo@simoahava.com and I can take a closer look at your implementation (I’ll need your site URL for the check).

      Best regards,

      Simo

      • Bryan Mc. says

        i dont understand the instructions, im sorry, do i need to do all the steps listed in your post “Page Load Time In Universal Analytics” or do i skip the Create some macros in GTM and just go with the Create a generic event container instructions listed under that post? if so, what to i need to fill when i create the event container? the same as the create a generic event container example? it will be too much to ask to make a step by step tutorial from start to bottom from creating the event, what to fill, then how to create the dwell tag and how to put them together to make it work? thanks

    • says

      Hamed, all my tutorials are for Universal Analytics, so no ga.js involved here.

      The reason I refer to my old tutorials is because I use macros for event attributes (e.g. category, action, label), and they need to be created before this tutorial works. So read the post on “Page Load Time”, and create the generic event container before you create the custom HTML tags in this post.

      If you don’t have Universal Analytics, you’ll need to upgrade for these tutorials to work. I won’t be writing tutorials for ga.js, since it will be deprecated in the coming months.

    • says

      Hi Kenneth,

      Indeed it does. There’s a lot of things you can do with scroll length. I’ve seen implementations, where there’s scroll length of 25 % of page, 50 % of page, 75 % of page and 100 % of page, and each fire a unique event. This way you could observe just how much your readers are digesting your content.

      The main intent of this script is to weed out immediate bounces and those who just open it in a new tab or leave it be. Like I said, there’s a LOT more that you can do with this idea.

      And you’re right. I’ve been on the lookout for a new template anyway, and that’s a feature that has to be in the new one.

  4. H.Yang says

    Hi Simo,

    Thanks for sharing this great article,

    I just had one problem after implement this code in my site, I getting abnormal high Total events data (48) when I compare it with Total Visits data in All Traffic Acquisition (17). am I doing it wrong? I’m still new in this analytics thing.

    • says

      Hi,

      No, you’re not doing it wrong :) That’s just how the script works at the moment. It sends a “NoBounce” event with every single pageview, which is a bit overkill, but it does its job. Normally it would be enough to just have it send the NoBounce just once per visit (e.g. by using a custom cookie), but understandably this is a bit hard to do. Another way to do it is to check the HTTP Referrer (using the {{referrer}} macro), and if it isn’t your own domain, it means the pageview is a landing page. This doesn’t mean that it’s the first of the visit, since visits can spawn over many exits and entrances, but it would make it a bit more accurate.

      Personally, I don’t see anything wrong with getting these “extra” events, since I can just disregard them in my analysis.

  5. says

    Hi Simo,

    i have a question where you maybe could be of help. When going for the simple solution you use the vent racking for universal analytics. However, if you do not want to reduce your bouncerate as you are potentially then comprmising all your old data i would love to use the noninteraction value. Do oyu think it is possible that this is not working together with the setTimeout. This is the code i was using. Please be aware i am not a developer. Maybe i used the wrong order or is missed an hyphen. However i checked plenty of times.
    setTimeout(“ga(‘send’, ‘event’, ‘nobounce’, ’35 seconds’, {‘nonInteraction': 1})”,35000);

    Anything wrong?
    Thanks very much and best regards from germany
    Alexander

    • says

      Hi,

      Hm, your code looks good. You might try changing ‘nonInteraction': 1 to ‘nonInteraction': true, since the documentation states that the value should be boolean (true/false), even if all the examples use numeric 1 to denote a non-interaction event.

      If that doesn’t work, you might want to use the recommended syntax with something like: setTimeout(“ga(‘set’, ‘nonInteraction’, true);ga(‘send’, ‘event’, ‘nobounce’, ’35 seconds’)”,35000);

  6. says

    Hi Simo, this is absolutely awesome and exactly what I was looking for, thank you!
    We are, however, not using Google Tag Manager at the moment. Would it be possible to get a script to add just below the UA-Tracking Code? (Without use of the Tag Manager)… How would you implement this?

  7. Nipun says

    Hey,

    1st of all thanks a lot for bringing us this awesome post. It indeed is working for us. We have setTimeout(“ga(‘set’, ‘nonInteraction’, true);ga(‘send’, ‘event’, ‘nobounce’, ’50 seconds’)”,50000); and our bounce rate has reduced to 10+- from 60+.

    But this doesn’t stop here and my major concern is something related to sudden shift in Page Views. (Though its an upward shift :))

    Earlier from 25000 Unique Page views I used to get 36000 Page Views but since we have added this code the ratio has improved way ahead. Now we get 55000 Page views from same set of 25000 Unique page views.

    IS IT BECAUSE OF HITS/EVENTS THAT ARE BEING SENT THROUGH ABOVE STATED PROCEDURE?

    IS GOOGLE TAKING THOSE EVENTS AS SOME KIND A PAGE LOAD?

    P.S. Also we have done some remarkable changes in our site regarding speed and page load, We just need to know which factor has lead to higher page views.

    • Nipun says

      Sorry it is

      setTimeout(“dataLayer.push({ ‘event': ‘GAEvent’, ‘eventCategory': ‘NoBounce’, ‘eventAction': ‘Over 50 seconds’ })”, 50000);

      • says

        Hi,

        There is nothing in my guide that should start sending double-hits with your pageviews. Are you sure you have just one page view tag, and it doesn’t have multiple rules attached (multiple rules = potentially multiple hits per page load)?

        If you want to give me the URL to your site, I can do some debugging (you can send this privately if you wish).

Leave a Reply

Your email address will not be published. Required fields are marked *

Please do not write HTML or other formatted code in your comments!