Tracking Content Scrollers, Scanners & Readers in Google Analytics

A couple of weeks ago Justin Cutroni wrote 2 awesome blog posts about Advanced Content Tracking using Google Analytics.

In Part 1 he shared the script he has written and is using, and in Part 2 he shared his findings and experience with this method.

I have been using his method with some small tweaks since before he published these blog posts, and since someone asked me if I could publish the script with my tweaks - here it is.

Differences between this script & Justin's script

  • Reader classification: 30 seconds. If you use more than 30 seconds to scroll the Content Area you will be classified as a Reader.
  • Check if content area has to be scrolled: Tracked as Scrolling Allowed.
  • Tracking of Content Length in pixels: Gives you more opportunity to analyze Readers vs. Scanners.
  • All tracking is done using Non-Bounce Events: You can change that, but I wanted to be able to compare Bounce Rate on a article level with Readers and Scanners.
  • Naming are different: The naming I'm using in my script is different from Justin's naming. I used a different Content Tracking script earlier, and kept the namings I used in that script.

Bonus: Analyzing your content in Excel

As Justin wrote, this data begs for Excel.

Google Analytics Content Readers - Excel Dashboard

You can therefor download this Excel spreadsheet to analyze your data further. The spreadsheet requires the Next Analytics Excel plugin.

Using the Excel spreadsheet

In the _actions tab, change the following values:

  • Site Name
  • Date Start & Date End
  • Google Analytics Profile ID

The Google Analytics script for tracking Readers & Scrollers

  • Values in Blue: You may change these values
  • Values in Red: You have to change these values
  • The script requires jQuery.

Remove formatting from Code

  1. // This script was originally written by Justin Cutroni, see
  2. var readerTime = 30; // Seconds after scroll to bottom of content before visitor is classified as "Reader"
  3. var readerLocation = 150; // # px before tracking a reader
  4. var callBackTime = 100; // Default time delay before checking location
  5. // Set some flags for tracking & execution
  6. var timer = 0;
  7. var contentLength = 0; // Content Length -> Length of content area
  8. var scroller = false;
  9. var endContent = false;
  10. var didComplete = false;
  11. // Set some time variables to calculate reading time etc.
  12. var pageTimeLoad = 0;
  13. var scrollTimeStart = 0;
  14. var timeToScroll = 0;
  15. var contentTime = 0;
  16. var endTime = 0;
  17. jQuery(function($) {
  18. // Check if content has to be scrolled
  19. if ($(window).height() < $('#contentArea').height()) { // Replace contentArea with the name (class or ID) of your content wrappers name
  20. pageTimeLoad = new Date().getTime();
  21. contentLength = $('#contentArea').height();
  22. _gaq.push(['_trackEvent','Page Scroll','Page Scroll: Allowed',window.location.pathname,contentLength,true]);
  23. }
  24. // Check the location and track user
  25. function trackLocation() {
  26. bottom = $(window).height() + $(window).scrollTop();
  27. height = $(document).height();
  28. // If user has scrolled beyond threshold send an event
  29. if (bottom > readerLocation && !scroller) {
  30. scroller = true;
  31. scrollTimeStart = new Date().getTime();
  32. if (pageTimeLoad > 0) {
  33. timeToScroll = Math.round((scrollTimeStart-pageTimeLoad)/1000);
  34. } else {
  35. timeToScroll = ""
  36. }
  37. // Article scroll started
  38. _gaq.push(['_trackEvent','Page Scroll','Page Scroll: Started',window.location.pathname,timeToScroll,true]);
  39. }
  40. // If user has hit the bottom of the content send an event
  41. if (bottom >= $('#contentArea').scrollTop() + $('#contentArea').innerHeight() && !endContent) {
  42. timeToScroll = new Date().getTime();
  43. contentTime = Math.round((timeToScroll-scrollTimeStart)/1000);
  44. if (contentTime < readerTime) {
  45. _gaq.push(['_setCustomVar',1,'ReaderType','Scanner',3]);
  46. _gaq.push(['_trackEvent','Page Scroll','Page Scroll: Content Scanner',window.location.pathname,contentTime,true]);
  47. } else {
  48. _gaq.push(['_setCustomVar',1,'ReaderType','Reader',3]);
  49. _gaq.push(['_trackEvent','Page Scroll','Page Scroll: Content Reader',window.location.pathname,contentTime,true]);
  50. }
  51. endContent = true;
  52. }
  53. // If user has hit the bottom send an event
  54. if (bottom == height && !didComplete) {
  55. endTime = new Date().getTime();
  56. totalTime = Math.round((endTime - scrollTimeStart)/1000);
  57. _gaq.push(['_trackEvent','Page Scroll','Page Scroll: Page Bottom',window.location.pathname,totalTime,true]);
  58. didComplete = true;
  59. }
  60. }
  61. // Track the scrolling and track location
  62. $(window).scroll(function() {
  63. if (timer) {
  64. clearTimeout(timer);
  65. }
  66. // Use a buffer so we don't call trackLocation too often.
  67. timer = setTimeout(trackLocation, callBackTime);
  68. });
  69. });

Some final words

Before starting to use this script, you should read both blog posts from Justin Cutroni to get a grip of the differences between this script and his script.

Other people I should thank for this content tracking method is Thomas Baekdal (and I really recommend his Plus Content).

If you think the tweaks I have done to the code could be improved, feel free to comment (I'm not a programmer).

Related articles

Du kan følge kommentarer til denne posten med RSS. Du må ha javascript aktivert for å kunne kommentere. Tilbaketråkk er deaktivert.

Tags : , , , ,

  • Comments are closed
  • power
  • 12/1/2012 3:32:51 AM
After add this script, My Event Value suddenly increased to 1 billion . How to control it?
You can't control it. Event Value is based on your visitors time spent before they scroll, or how long time they use to scroll/read an article or scroll to bottom of the page measured in seconds.

If you don't want this information, remove tracking of Event Value.
  • Jens
  • 2/1/2013 4:27:16 AM
I noticed that $(window).scroll() fires once on page load. Wouldn't this influence results?

There's a workaround here (bottom of page):
Good question.
You have to scroll 150px before the script fires, so it shouldn't influence results.

/ Eivind
  • Jens
  • 2/3/2013 10:47:11 PM
Actually, for me it fires straight on page load, not after the user scrolled 150px.

So I modified the code like this (note "scrollStarted" variable):

var scrollStarted = false;
$(window).scroll(function () {
if ( scrollStarted ) { // Avoid starting processing on page load
if (timer) {
// Use a buffer so we don't call trackLocation too often.
timer = setTimeout(trackLocation, callBackTime);
scrollStarted = true;
Thank you Jens.
Comments like this is highly appreciated.
/ Eivind
You sir, need to write your own book! I was about to comment and ask/suggest you share the Excel document, but you already have.

Keep up the good work.

Hey ! That's an amazing contribution to the community you've made here. Thanks a million for that. You've just earned a loyal follower (and eager learner) for the years to come.

Just a quick question : as someone pointed out, the result of this tracking script will be a HUGE amount of new events in GA.

Won't it hit some kind of limitation ?

My website gets between 13 000 to 15 000 unique visitors a day, won't all these new events overload my free GA account ?

Should I be worried about that, before implementing this script ?

Thanks for your feedback Baptiste.

There are some hit limitations in Google Analytics.

Session limits: 500 hits per session.

Monthly limit: 10 million hits per month.


With that said, the 10 millions per month limit has never been executed by Google Analytics to my knowledge.

/ Eivind

XClick to move the comment field