Time on Site and Bounce Rate: Fixing Google Analytics’ Flaws

UPDATE: This post from 2012 and the code presented here became mostly obsolete since the release of “universal analytics”. I’m leaving it here “as-is” for reference, but please note that the code and the WordPress plugin which uses it are now useless and will likely have no effect if you are using an up to date universal analytics code (which you should!).

Google Analytics is one of the best tracking tools for web traffic, and by far the most used across the web. Moreover, it’s free. But it also has it’s flaws and downsides.

Here’s a major one: Analytics gives you the “time [spent] on site” and “bounce rate”, but these data are only based on Pageviews, because the code only fires once when a page is loaded. See where this goes ? The time spent on site, according to Analytics, is actually the time between the moment an user enters the site, and the moment when the last page of his visit is loaded.

Here’s what it means: say an user enters your site, spend 3 minutes reading an article, and leave (maybe he even added your site to his bookmarks to come back later). Analytics says the time on site is exactly 0:00, and counts this visit as a bounce.

So you have a 80% bounce rate and was wondering why ? It’s not because your site is not interesting, nor because your visitors are crazy freaks clicking everywhere without thinking! (at least not all of them…)

Another scenario is when your visitor lands on your site, spend 2 minutes reading an article, clicks a link and sped 3 more minutes on another page before leaving your site. Did you guess how Analytics will reflect this visit? 2 Pageviews and 2 minutes on site (instead of the actual 5 minutes).


“What’s the point of this criticism if you can’t do better anyway?” you ask. Well we can! Thanks to the Analytics’ API and this code by Brian Cray, you can help Analytics gather more accurate data.

This tiny javascript snippet will simply update Analytics every ten seconds while an user stays on a page. The accuracy of the “time on site” will still have a 10 seconds margin, but that’s better than 0:00 (and a bounce) for every user that only visit one page.

<script type="text/javascript">// <![CDATA[
(function (tos) {
  window.setInterval(function () {
    tos = (function (t) {
      return t[0] == 50 ? (parseInt(t[1]) + 1) + ':00' : (t[1] || '0') + ':' + (parseInt(t[0]) + 10);
    window.pageTracker ? pageTracker._trackEvent('Time', 'Log', tos) : _gaq.push(['_trackEvent', 'Time', 'Log', tos]);
  }, 10000);
// ]]></script>

Simply copy/paste this snippet at the bottom of your page, just before the </body> tag, and come back tomorrow to check your Analytics reports to find out how inaccurate your previous data were. This works no matter if you are using the old or new tracking code.

A visual example

I’ve installed this code on one of my sites at the end of February. The average pageviews on this site is about 2, most of the visitors come from Google and land on the very page they were interested in. Most of them they simply read it and then leave the site.

There were no difference in traffic between february and march, but take a look at the differences in Time on site (above) and Bounce Rate (below). We’re not even talking about accuracy anymore, the previous data were completely wrong.

Implementing in WordPress

Option #1: the neophyte coding handyman

Heresy! If WordPress was a religion, you would be excommunicated for doing this. But that’s still a working solution that many uninitiated would come up with:

From your WordPress dashboard, go to Appearence > Editor, and edit the footer.php file. Locate the closing </body> tag and paste this code just above. Done. This will work, but that’s a messy work.

WordPress doesn’t like hardcoded scripts in template files, and this is why it offers functions to properly handle scripts (wp_register_script() et wp_enqueue_script()). Using them will also improve performance and avoid conflicts between scripts.

There is another major downside to this option: this involves editing your theme, so what happens if you update it and decide to change for another theme in the future? The code you’ve just added will be lost, and you will need to manually add it again.

There is a better, and easier way…

Option #2: the done-for-you plugin

Here a tiny plugin I crafted to make you life easier. Using it is as easy as install, activate, forget!

What it does is simply properly register and enqueue a minified version of this script, so WordPress will call it where your theme has its “wp_footer()” hook.

How to use:
– Download GABounceFix.zip. (UPDATED: removed link since this is now completely obsolete, see update at the top of this post)
– From your WordPress Dashboard, go to Plugins > Add New > Upload. Pick the .zip file you’ve just downloaded and click “Install Now”.
– A few seconds later, WordPress tells you it has been successfully installed, and offers to activate it. So simply click “Activate”.
– Done. From now on this code will fire on every page of your site, and you will enjoy more real data in your Analytics reports!

Share the love!

7 Responses to Time on Site and Bounce Rate: Fixing Google Analytics’ Flaws

  1. So this little line of code pings Analytics every 10 seconds. My personal feeling here is that the Bounce rate is more deceiving than useful in this case. You’re already factoring in the bookmarker into a normal analysis, so you’re not getting a benefit there — and that user is cookied, so they won’t be counted twice anyway. If you’re considering everyone who stays on-page 10 seconds to be an engaged user, then you’re undervaluing your content (is 10 seconds really the read-time of your content?).

    The time on site is interesting, though, for sure. Is there a way to not affect Bounce Rate while still doing this kind of more valuable Time-On-Page data grabbing?

    • Hey Douglas, thanks for dropping by :)

      You’ve made a point here, an user who only stays 10-20 seconds is indeed not what we’d call an engaged user, but this shouldn’t be considered as a bounce either.

      Back to the definition (by Avinash Kaushik), a bounce is when “people come to your website and leave instantly”. So after more than 10 seconds, that non-engagement, but it’s not a “bounce” either.

      Then counting those who stay longer (like a few minutes) and then leave the site without browsing further as bouncing visitors is even more deceiving in my opinion – and this scenario seems to be happen more frequently.

      Actually the bounce rate shouldn’t really be used to measure user engagement, and that’s where time on site data becomes even more interesting.

      Pinging Analytics that way gives you the actual bounce rate (those who leave *immediately*), and the more accurate time on site allows you to tell who stayed long enough to be “an engaged user” and who is in-between. And as you pointed, the definition of “long enough” depends on your content.

      To answer your last question, due to the way Analytics works, I’m afraid there is no way to affect the time-on-site data grabbing without affecting how the bounce rate is calculated. You could still change this code, like pinging analytics only after 1 minute on a page and then every few seconds, but this would ruin the accuracy of time-on-site tracking, especially for multiple pageviews.

  2. Good to note – this fix would probably give a greater insight into what your affiliate based traffic is doing as the priority is to get them in and then click-out.

  3. Great post!

    It was just what I was looking for.
    But I have one question.

    If I want to change it to 20 seconds instead of, should I just change (parseInt (a [0]) + 10)} to (parseInt (a [0]) + 20)} or what?

  4. I think there may be an issue with this code. I tested it in the footer and searched with a unique keyword. Clicked in and kept the browser open on that page for a little over 5 minutes (timed). Then I clicked to another tab that was already open and left it that way for nearly an hour.

    When I saw that keyword show up in my blog reports, I found that it had timed the session to 50 minutes. It should have stopped pinging GA after I clicked away from the tab.

    So I cannot trust the time visit duration with this code because people often click to another tab when done.