Update 10/24/13: The Scroll Depth Plugin tag has been updated below for the custom HTML tag that goes in Google Tag Manager. Everything should work!

Update 2/15/14: Rob Flaherty updated his Scroll Depth plugin to support GTM, so I removed the steps that used a fork of his plugin. Great work Rob!

I’ve been trying to implement scroll tracking on my blog for a couple of months now without having to modify my blog’s source code. I have fairly basic knowledge of HTML, CSS, and JavaScript, but I’m certainly not an advanced developer capable of creating a solution. So, like all great researchers, I headed over to Google.com to see what I could find.

Enter Rob Flaherty’s Track Scroll Depth Plugin

I came across Rob’s “Tracking Scroll Depth with jQuery and Google Analytics”ย blog post. Rob developed a jQuery plugin to track the percentage of the page a visitors scrolls. It sends this information as events to measure baseline (0%), 25%, 50%, 75%, and 100% scroll depth. This is exactly what I need! ย See the code here, on the project page:ย https://github.com/robflaherty/jquery-scrolldepth/blob/master/jquery.scrolldepth.js

But, this method requires that you modify your source code and upload the script to your site. I had some trouble doing this (*sad face*, *embarrassed face*), so I searched for a similar solution to use dataLayer pushes so I could send events using Google Tag Manager.

With the support for GTM in Rob’s latest update, I can now use his script + GTM to track all of these scroll depth events.

Steps to Track Scroll Depth

Requirements:

  1. Site uses Google Analytics (Classic and/or Universal Analytics)
  2. Site implements GA through Google Tag Manager
  3. Knowledge of GA + GTM
  4. Ability to read and follow directions ๐Ÿ™‚

Step 1: Create Custom HTML Tag Using the Scroll Depth Plugin

Within the GTM container for my site, I will need to create a new “Custom HTML Tag” and add the code you see in the scrolltracking.js file below:

scrolldepth.js

What this script will do, if you are using GTM, is make a dataLayer push for each scrolling event. Events within GTM are different from events with GA, so this won’t actually send any events to GA. We will need to build a separate event tracking tag to pull these events from the dataLayer and push them into GA as event tracking.

You will need to set a firing rule so that this script fires on gtm.dom, meaning it will fire once the DOM is ready. The custom HTML tag will look like this in GTM:

Scroll Tracking using GTM

Step 2: Create New Google Analytics Tag for Event Tracking

Now the script will fire and push an event to the dataLayer each time a user scrolls down the page. To push these dataLayer events to GA ย as events (a little confusing I know), I will need to create a new Google Analytics event tracking tag using the same UA number. It will look very similar to your current GA tag, but instead of the “Track Type” being set to Pageview, you will need to change it to Event Tracking.

Now you will need to set up the Event Category, Event Action, Event Label, and Event Value fields for the event. We will do this dynamically by creating four macros that will pull these values from the dataLayer. Each one of the fields will need its own macro. So, for Event Category, click on the + Lego looking button and select “New Macro”. It should look like this:

Event Category Macro

Creating a macro in GTM

 

Event Action Macro

Creating a macro for Event Action

 

 

Event Label Macro

Creating a macro for Event Label

 

Event Value Macro

Event Value macro

 

NOTE: Rob’s scroll depth plugin sets all events to NonInteraction = true, meaning they will not affect the site’s bounce rate. You can build a macro, similar to the Event Tracking Parameters macros, to set these events to NonInteraction = true, or you can merely select True for Non-Interaction Hit below the Event Tracking Parameters.

To not affect your bounce rate

 

You will also need to set the tag to fire on “event equals ScrollDistance”. Your final event tracking tag should look like this:

Scroll Distance Firing Rule

Step Three: Create Version and Publish in GTM

Now you’ve set up GTM to track scroll depth, feel free to test using GTM’s Debug mode, the GA Debugger extension, or your GA Real-Time Events report.

Let me know your thoughts, have you tried to implement something like this before? Having any trouble? Hit the comments! And don’t forget to check out Rob’s Scroll Depth plugin page atย https://github.com/robflaherty/jquery-scrolldepth.

 

Disclaimer: The scroll depth plugin is not my solution, so any questions related to it affecting your site should be directed to Rob Flaherty.

Comments
Harvey Specter
Posted at 8:18 am August 15, 2014
Ben
Reply
Author

I’m running into some funny behavior where this seems to be effecting the user counts. I’m using GTM, but I’m not sure if this is potentially just a general issue with scrolldepth.js

Early this month, I temporarily disabled scroll tracking and noticed a sharp drop in the number of users. Then yesterday, I reconfigured the tag and associated macros and firing rules (with scrolldepth.js v 0.6) and saw my users shoot back up. You can see the trend in the screenshot of one of my views here: http://i.imgur.com/x3PTiiE.png. At first I thought this may have been an issue with the value of nonInteraction, but I’ve confirmed that that value gets set to true.

    Harvey Specter
    Posted at 12:40 pm August 18, 2014
    cmism
    Reply
    Author

    I’m also running into this issue.

    Was their a solution to this?

    Thanks!

    Harvey Specter
    Posted at 6:56 am July 29, 2015
    Clara
    Reply
    Author

    Hello I just tried to implemented this solution in one page website to track users interactions in our website, however, I didn’t succeed. It is a wordpress template where I don’t see any specified (DOM) elements. In that case how I should proceed in order to see users scrolling behaviour.

Harvey Specter
Posted at 8:19 am August 15, 2014
Ben
Reply
Author

Also, FWIW, the original tag was configured by Infrotrust when we initially worked with them in December (I didn’t realize you worked for them until I read your about page).

    Harvey Specter
    Posted at 10:05 am August 18, 2014
    Andy Gibson
    Reply
    Author

    Hey Ben, thanks for reaching out. Since you already have an email chain open with Amin and I, we can continue chatting via email.

Harvey Specter
Posted at 8:37 am August 16, 2014
Vimlesh Maurya
Reply
Author

Thank you very much for sharing it. I used it in one of my clients website and it is working perfectly.

    Harvey Specter
    Posted at 10:06 am August 18, 2014
    Andy Gibson
    Reply
    Author

    Vimlesh,

    Awesome, thanks for the comment!

Harvey Specter
Posted at 6:41 pm August 25, 2014
Sophie
Reply
Author

Hey, thanks for the step by step, very helpful for the clueless like myself

Unfortunately I’m still having trouble getting this to work

Was this image http://i1.wp.com/andygibson.us/wp-content/uploads/2013/10/Screen-Shot-2013-10-24-at-9.25.28-PM.png?resize=506%2C275 completely optional or was that a necessary part of the setup? I didn’t come across that screen when following your instructions.

Looking through debug mode, I can see in the summary the ScrollTiming+ScrollDistance fire at each interval, however it’s not triggering a real time event in analytics.

Any help would be much much appreciated for what to potentially look into!

Harvey Specter
Posted at 7:32 pm August 25, 2014
Sophie
Reply
Author

Fixed it. Didn’t realise that creating a rule makes it like a global module – I was reusing the gtm.dom rule without realising. Thank you!

Harvey Specter
Posted at 9:28 am August 26, 2014
Andy Gibson
Reply
Author

Hey Sophie,

Thanks for reading the blog and glad you got everything to work!

    Harvey Specter
    Posted at 9:20 am September 5, 2014
    Aklen
    Reply
    Author

    Can you help me using ScrollTiming and ScrollDistance work together ? Should I set any timer event for this ?
    Thanks in Advace

Harvey Specter
Posted at 2:51 pm September 6, 2014
philamery
Reply
Author

hi Andy,

I’ve just switched from regular tracking to GTM
I followed all the steps described in your post and looks that everything is working just fine

still, I got a bit confused with the additional WordPress plugin Riveted which I deactivated prior the switch;
now in real-time Event tracking, Riveted still gets listed and showing data which led me asking you if this is normal or there’s something I’m missing (it looks like, by implementing ScrollDepth track through GTM, it also gives me data Rivete plugin did)

if I’m wrong and there’s need for further tweaks, where or what steps should I follow to setup the additional two trackings (Rivete, Screentime) in GTM? – shall I reactivate the Rivete WordPress plugin?

Harvey Specter
Posted at 12:24 pm September 7, 2014
Vimlesh Maurya
Reply
Author

Hi Andy, I used this set up and it is working fine with my website, but there is one problem that it is tracking visitors who are not scrolling and if I set non interaction = false then bounce rate becomes zero. Please help me to solve this problem.

Harvey Specter
Posted at 5:09 pm September 15, 2014
Rodrigo Peixoto
Reply
Author

Hello, I’m having the same problem as the user above, after I follow all the steps above, the bounce was from 20% to 2%, how to solve this?

    Harvey Specter
    Posted at 3:41 pm September 19, 2014
    Andy Gibson
    Reply
    Author

    For everyone having issues with the bounce rate, you can use this tag which makes the baseline event a non-interaction event and if people do not scroll, it will not affect the bounce rate: https://www.dropbox.com/s/asoqv44dz32aift/scrolltracking2.js?dl=0

    For any other issues, please reach out to the creator of the scroll depth plugin, as this is not my solution.

Harvey Specter
Posted at 8:42 am October 1, 2014
Janis
Reply
Author

I’ve done all steps except this “TRACK TYPE” window:
http://andygibson.us/wp-content/uploads/2013/10/Screen-Shot-2013-10-24-at-9.25.28-PM.png

I can’t figure out where to find/open it.

Please help ๐Ÿ™‚

    Harvey Specter
    Posted at 11:14 am October 1, 2014
    Andy Gibson
    Reply
    Author

    You have to create a Google Analytics or Universal Analytics tag inside GTM – and then you’ll see the “Track Type” option in that tag.

Harvey Specter
Posted at 5:23 am October 6, 2014
Ziyu
Reply
Author

Hi, I recently wrote a small library for scroll tracking. It does not depend on jQuery and has a set of api to add tracking elements. Hope it will help tracking some sites that do not have jQuery. https://github.com/oddui/scrolltracker

Harvey Specter
Posted at 12:28 pm October 29, 2014
Chris
Reply
Author

Hello, Andy Gibson. I there an updated version of instructions for version scrolldepth.js v 0.6 . I tried copying the updated version of the pluging into my custom HTML tag in GTM, then I followed the step you outlined about. But it’s not working. Any advice?

    Harvey Specter
    Posted at 7:31 pm October 30, 2014
    Andy Gibson
    Reply
    Author

    Hey Chris,

    Do you have jQuery installed on the site? The plugin using jQuery.

Harvey Specter
Posted at 9:20 am November 3, 2014
JP
Reply
Author

HI,

I followed all steps and when previewing the solution in debug mode I see the events being fired (25%, 50%, 75% etc).
However, after publishing I can’t seem to find it in Analytics. Where are the results displayed?

    Harvey Specter
    Posted at 11:36 am November 3, 2014
    Andy Gibson
    Reply
    Author

    In Google Analytics, go to Behavior > Events > Top Events

Harvey Specter
Posted at 3:36 pm November 19, 2014
Dominic Hurst
Reply
Author

Hi Andy. Will look into this in more detail, but had a question about using scroll as an event and thus impact on bounce rate. We do have content rich page and so people reading then would be micro conversion. But am sure not all that scroll actually read

    Harvey Specter
    Posted at 8:23 pm November 20, 2014
    Andy Gibson
    Reply
    Author

    You can choose to make events “Non Interaction”, meaning they won’t affect the bounce rate. This is a setting within GTM.

    https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide#non-interaction

      Harvey Specter
      Posted at 4:36 pm November 21, 2014
      Dominic Hurst
      Reply
      Author

      All set up Andy in test environment. Next week will see for sure it working in live

      Harvey Specter
      Posted at 6:47 am February 16, 2015
      Dominic Hurst
      Reply
      Author

      Hi Andy. All live with this, noted some behaviour though. In real time scroll depth only appears on Events (last 30) and not active users – under the events link. Equally if you assign it as a goal it it only appears on Goal hits (last 30) and not active users. Not a major problem though

Harvey Specter
Posted at 5:19 pm December 19, 2014
Drew
Reply
Author

Hi,

Rob has updated the script in v0.7.1 to now make the baseline event always non-interaction. Just thought I would mention this change here

This should make it easy to only send an interaction event should scrolling actually occur ๐Ÿ™‚

Harvey Specter
Posted at 5:39 pm December 19, 2014
Drew
Reply
Author

But…ย can’t get the new version (0.7.1) working in GTM yet for some reason

Harvey Specter
Posted at 2:27 am December 30, 2014
Peiwen
Reply
Author

Hi , thanks a lot, I just followed your lead, but sadly something went wrong.
I did everything as you told, but the debugger mode told me that event equals ScrollDistance is not firing.
can u give me some help?

Harvey Specter
Posted at 3:31 pm January 16, 2015
luismqueral
Reply
Author

Thank’s so much for this Andy. Just a tip: you might want to consider updating the tutorial for GTM v2 that will soon replace GTM. The UI and terminology in the new version of Tag Manager is quite different from it’s predecessor.

Thanks!

    Harvey Specter
    Posted at 12:59 pm January 24, 2015
    Andy Gibson
    Reply
    Author

    Hey Luis,

    Agreed, I will definitely create a new post for v2 of the GTM UI.

Harvey Specter
Posted at 1:25 pm February 3, 2015
Julien
Reply
Author

Thanks for this Andy. Just implemented it and it worked wonder. I only made one change: I changed the event action macro from “EventAction” to “URL Path” which shows me the scroll depth on a page by page basis.

Harvey Specter
Posted at 4:32 pm February 5, 2015
Hannah
Reply
Author

Hey Andy,

Thanks for this info.! I seem to be getting a lot of data for “baseline” – any way I can figure out what this represents?

Cheers

Hannah

    Harvey Specter
    Posted at 6:42 pm February 5, 2015
    Andy Gibson
    Reply
    Author

    Hey Hannah,

    Baseline fires on page load. It’s basically 0%.

Harvey Specter
Posted at 10:20 am February 10, 2015
uryah
Reply
Author

Hi Andy your tutorial was great, just wondering if you ever tried to setup, Robs RivetedTiming script in GTM. I tried (kinda using your template for setting up scroll depth) got close but i am missing something, in GA “events” the eventlaction & eventlabel are showing “percentage” & Baseline|25%|50% and so on. Any help would be most welcomed

    Harvey Specter
    Posted at 7:06 pm February 17, 2015
    Andy Gibson
    Reply
    Author

    Hey Uryah,

    No, I haven’t tried the RivetedTiming script in GTM. Sorry!

Harvey Specter
Posted at 5:56 pm April 9, 2015
Gong
Reply
Author

Hi Andy,

Thank you very much for your post. I have tried it but it doesn’t show any Event Label except “Baseline” Do you have any idea why that might happen?

Thank you

Harvey Specter
Posted at 11:47 pm April 9, 2015
Lindsey
Reply
Author

Hi Andy,

Great post, thanks. I have implemented this for a client in the container draft (v.1 GTM) but the only event I can see coming through is the Baseline event. I haven’t made any changes to the script (I have v0.4.1). The script fires on gtm.dom (I also tried the built-in All Pages rule). The UA event fires on {{event}} equals ScrollDistance.

Do you have any ideas? I thought maybe the minimum height was set too high as they are short pages but it’s set to 0.

Cheers in advance.

    Harvey Specter
    Posted at 7:50 pm April 21, 2015
    Andy Gibson
    Reply
    Author

    Hey Lindsey, thanks for the kind words. I would recommend reaching out to Rob Flaherty if you are having issues with his script. I merely created a guide to implementing it in GTM ๐Ÿ™‚

Harvey Specter
Posted at 10:58 am April 22, 2015
Mike
Reply
Author

Hi Andy,

I was wondering when you think you might updated this for GTM V2?

Thanks

Harvey Specter
Posted at 7:23 am May 20, 2015
jemsie
Reply
Author

I followed step by step instruction but the the whole code was getting pasted in the bottom of the website.how do i correct it

    Harvey Specter
    Posted at 10:20 am May 21, 2015
    Andy Gibson
    Reply
    Author

    That’s happening because the Custom HTML tag script isn’t wrapped intags. The code you copy and paste should start with

      Harvey Specter
      Posted at 5:46 am May 22, 2015
      jemsie
      Reply
      Author

      Now that problem has gone..but still its not working.The GA tag created for this purpose is also not getting fired.what could be the prblm.how do I know that my website has jquery plugin installed or not.How to install jquery plugin

        Harvey Specter
        Posted at 12:44 pm July 15, 2015
        Andy Gibson
        Reply
        Author

        There are a few ways to check if your site has jQuery, just open up your Developer Tools Console and type in “$.fn.jquery” and hit Enter. It’ll return the version of jQuery your site is using OR it’ll throw an error, meaning you don’t have jQuery on your site.

Harvey Specter
Posted at 6:32 am May 28, 2015
Tim
Reply
Author

Hi,

Thanks for the guide. Once setup, in addition to the Scroll Depth event, I am also seeing a lot of “undefined” events?

Thanks
Tim

Harvey Specter
Posted at 12:17 pm June 11, 2015
Jax
Reply
Author

Is there also a good solution without the GTM?

Harvey Specter
Posted at 10:53 am July 9, 2015
Rogier
Reply
Author

Thank you for a clear tutorial!
It’s working. And I like the scroll insights it’s providing.

Harvey Specter
Posted at 12:18 pm July 9, 2015
Kiera
Reply
Author

I’d love to get this up and running in GTM v2 as well. I’ve got most of these steps recreated there, but am running into a couple of issues. I had to remove the Event = ‘ScrollDistance’ trigger completely to get the event to fire at all. After removing that, an event registers on page load in Google Analytics, but the Category and Action are both ‘undefined’, and the Label is ‘(not set)’; it also does not trigger additional events when scrolling down the page (so I’m not sure it’s firing the js at all).

I’m betting there are just a few configuration changes that need to be made, but I’m new to GTM and am not sure where to start. Any suggestions would be appreciated!

    Harvey Specter
    Posted at 12:31 pm July 9, 2015
    Kiera
    Reply
    Author

    Also, just realized I had to remove the Event = ‘gtm.dom’ trigger for the Custom HTML Tag (with scrolldepth.js) to actually load on the page. Removing that trigger did not correct the undefined/(not set) issue tho.

Harvey Specter
Posted at 12:31 pm July 15, 2015
uday
Reply
Author

Hi,

Getting the error..Uncaught ReferenceError: jQuery is not defined…. sometimes and the events donot fire when this happens.. This is happening randomly on the same page error is being thrown sometimes and sometimes it works fine…

    Harvey Specter
    Posted at 12:38 pm July 15, 2015
    Andy Gibson
    Reply
    Author

    I believe you’re getting the error because the Custom HTML tag (which uses jQuery) is loading in some instances before the actual jQuery library. Try delaying the Custom HTML tag to “On DOM Load” (gtm.dom) or “On Window Load” (gtm.load)

    https://support.google.com/tagmanager/answer/6103657?hl=en

      Harvey Specter
      Posted at 1:58 pm July 15, 2015
      Uday
      Reply
      Author

      Hi Andy,
      Thanks for your reply….
      I tried both gtm.dom and gtm.load..it is not working with gtm.dom but
      it is working perfectly with gtm.load trigger….

        Harvey Specter
        Posted at 1:59 pm July 15, 2015
        Andy Gibson
        Reply
        Author

        Glad it’s working for you!

Harvey Specter
Posted at 4:07 am July 16, 2015
Mads
Reply
Author

Amazing! Works like a charm ๐Ÿ™‚

Thanks for the step-by-step. Slightly different workflow in the new GTM, but i figured it out ๐Ÿ™‚

Br. Mads

Harvey Specter
Posted at 6:26 am July 16, 2015
Nicolas Colombres
Reply
Author

Hello Andy,

This the older version of GTM. This works for 2.0? Can I try it out with GTM 2.0?

Thanks Andy ๐Ÿ™‚

Harvey Specter
Posted at 8:04 am October 12, 2015
Michael
Reply
Author

Thanks a lot Andy. Your step by step example walked me through all settings ( little common sense effort needed to complete the task with slightly different UI in google tag manager 2015 ). it works.

Notes for other beginners with GTM like me :

1. don’t include jquery.scrolldepth.min.js in your page – because it is already loaded through the GTM custom HTML tag as shown on this page by Andy. if you load both of them, then the events will fire multiple times (twice/double time). I came to this tutorial from scrolldepth lib page and it wasn’t obvious to me.

2. if you want the ScrollTiming event to reach your GA, then you need to define new tag with GA for it, the same way you did for ScrollDistance event. (GTM fire the ScrollTiming, but there is no GA tag to listen for this event – use GTM preview mode to see this happen).

Harvey Specter
Posted at 6:15 am January 19, 2016
Fed
Reply
Author

Hello Andy,

It works nice, I can see the percentage of scrolls in Universal Analytics.
But can not track the specific elements on the page. For example

1. Element added in the custom html tag:

var defaults = {
minHeight: 0,
elements: [‘article-top’],
percentage: true,
userTiming: true,
pixelDepth: true,
nonInteraction: true,
gaGlobal: false,
gtmOverride: false
};

2. Variable created

function () {
if ({{eventLabel}} === ‘article-top’) return 1;
return 0
}

What else should be done?

    Harvey Specter
    Posted at 9:15 am January 25, 2016
    Andy Gibson
    Reply
    Author

    Hey Fed,

    What are you trying to do with the variable you’re creating?

Harvey Specter
Posted at 8:34 am February 5, 2016
Kris
Reply
Author

This is great. Thanks for the great resource. How does GA track these events? For example: if a user scrolls all the way down the page and all 5 labels are fired (baseline, 25%, 50%, etc), does GA track that visit as has having all 5 unique event labels or just event with the label100%?

Thanks,

    Harvey Specter
    Posted at 10:24 am February 5, 2016
    Andy Gibson
    Reply
    Author

    The script will actually fire an event for each level of the page you see, so the baseline event gets sent on page load, then 25%, 50%, etc.

Harvey Specter
Posted at 7:26 pm February 16, 2016
John
Reply
Author

Andy,

Thanks for putting this together. It helps a lot when being a non-coder and implementing important measurement from a marketing perspective.

To give feedback for others on how things have changed since GTM moved to version 2:

– When choosing your event, you no longer have to put: event equals ScrollDistance.

– Now it’s just event name: ScrollDistance.

If you’re using the 2nd version of the jquery script Andy made, the event name is actually “GAscroll” This caught me up for a while because I want to remove the baseline from my scroll rate but was having an issue.

Finally, if using WordPress, the plugin “jQuery UI Widgets” helps you integrate the jQuery library nicely and it’s free.

Appreciate your work and hope this was helpful for someone else.

Harvey Specter
Posted at 9:47 pm February 16, 2016
John Belcher
Reply
Author

Andy,

Thanks for the work you’ve done on this. I mentioned you on my blog and gave a few insights on common missteps people may run into (most notably that version 2 of the js uses the event name “GAscroll” rather than “ScrollDistance.”

http://enduringmarketing.com/project/the-data-hiding-behind-your-bounce-rate/

Let me know your thoughts.

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>