Tracking Rage Clicks Using Google Tag Manager and Google Analytics

Tracking rage clicks using google tag manager and google analytics

Visitors rage clicking on certain elements on your website is a good indicator of a UX error. For example, people may click on a blue text that is not a link or on an image that has no click functionality.

Detecting and fixing such usability issues is crucial, and luckily the detection part is doable using Google Tag Manager and Google Analytics.

Rage click is a situation where, in a short period of time, a website user clicks multiple times on a specific element. I.e. in two seconds, a visitor clicks three times on an image.

Without further ado, let’s see how tracking rage clicks works in Google Tag Manager.

Step 1 – Create a new Tag that detects rage clicks

Google Tag Manager - detect rage click
Google Tag Manager – detect rage click

This tag is responsible for detecting rage clicks and pushing a custom event rage_click into the data layer.

There are a few variables that you can play with to make it best fit your use case:

no_of_clicks – after how many clicks do we consider it a rage click. Default is 3.

time – in what time period should the clicks happen. Default is 2 seconds.

radius – in what radius should the clicks happen. Default is 100px.

The following variables are pushed into the data layer when a rage click is detected:

eventrage_click

rc_element – selector of the element on which the clicks happened

rc_count – the number of clicks

rc_max_distance – maximum distance between the clicks

rc_time_diff – period from first to last click

PS! You don’t have to send all of them to GA, pick the ones you think make the most sense.

Full code snippet. – Requires jQuery to be loaded on the page.

if ( typeof(jQuery) === 'function' ) {
    jQuery(document).ready(function($) {
        jQuery.fn.extend({
            getPath: function() {
                var path, node = this;
                while (node.length) {
                    var realNode = node[0],
                        name = realNode.localName;
                    if (!name) break;
                    name = name.toLowerCase();
                    var parent = node.parent();
                    var sameTagSiblings = parent.children(name);
                    if (sameTagSiblings.length > 1) {
                        var allSiblings = parent.children();
                        var index = allSiblings.index(realNode) + 1;
                        if (index > 1) {
                            name += ':nth-child(' + index + ')';
                        }
                    }
                    path = name + (path ? '>' + path : '');
                    node = parent;
                }
                return path;
            }
        });
        // Number of rage clicks
        var no_of_clicks = 3;
        //Time interval - 3 for 3 secs, 4 for secs and likewise
        var time = 2;
        var click_events = [];
        //internal variables
        var possible_click = 3;
        var radius = 100;
        function detectXClicks(count, interval) {
            var last = click_events.length - 1;
            var time_diff = (click_events[last].time.getTime() - click_events[last - count + 1].time.getTime()) / 1000;
            //returns false if it event period is longer than 5 sec
            if (time_diff > interval) return null;
            //check click distance
            var max_distance = 0;
            for (i = last - count + 1; i < last; i++) {
                for (j = i + 1; j <= last; j++) {
                    var distance = Math.round(Math.sqrt(Math.pow(click_events[i].event.clientX - click_events[j].event.clientX, 2) + Math.pow(click_events[i].event.clientY - click_events[j].event.clientY, 2)));
                    if (distance > max_distance) max_distance = distance;
                    if (distance > radius) return null;
                }
            }
            var result = {
                count: count,
                max_distance: max_distance,
                time_diff: time_diff
            }
            return result;
        }
        function removeUsedClickPoints(count) {
            click_events.splice(click_events.length - count, count);
        }
        $("body").click(function(event) {
            click_events.push({
                event: event,
                time: new Date()
            });
            //remain only required number of click events and remove left of them.
            if (click_events.length > possible_click) {
                click_events.splice(0, click_events.length - possible_click);
            }
            //detect 3 click in 5 sec
            if (click_events.length >= 3) {
                var result = detectXClicks(no_of_clicks, time);
                if (result != null) {
                    var path = $(event.target).getPath();
                    //console.log('Rage Click: ' + JSON.stringify(result));
                    dataLayer.push({
                        'event': 'rage_click',
                        'rc_element': path,
                        'rc_count': result.count,
                        'rc_max_distance': result.max_distance,
                        'rc_time_diff': result.time_diff
                    });
                    removeUsedClickPoints(3);
                }
            }
        });
    });
}

Step 2 – Create a new Trigger

The snippet from the previous step is pushing the rage_click event into the data layer every time a rage click is detected. Now we need to create a trigger that listens to that event.

Google Tag Manager - rage click trigger
Google Tag Manager – rage click trigger

Step 3 – Send an event to Google Analytics

Awesome, now let’s create a new tag that is responsible for sending the custom event to Google Analytics.

Send rage click to Google Analytics
Send rage click to Google Analytics

You can play around with the event parameters, especially with the event label to best match your needs but the recommended values are as seen in the screenshot above.

Before publishing your changes, don’t forget to enter the preview mode in Google Tag Manager and test the setup yourself. Go ahead and do a few rage clicks and see if an event is getting sent to Google Analytics. Also, check the event parameters and see if they match your expectations.

Step 4 – Using this data

Okay, so you have configured everything correctly, tested it and it works fine. Now, how do you put this data into use?

First, go into Google Analytics and find your rage click events. If you did as described in this post, you find them by clicking on Overview under Behavior –> Events, then find the “Rage Click” event category.

Rage click report in Google Analytics
Rage click report in Google Analytics

Click on the “Rage Click” event category and choose Event Action to see the elements on which the rage clicks happened.

Rage click event in Google Analytics

Since elements with the same selectors might be on different pages, it might be helpful to apply a secondary dimension “Page”.

Now, all you need to do is to pick one element, copy its selector and go to the page seen in the secondary dimension.

Next, open the Javascript console of your browser (press F12) and paste your selector in the following format:

jQuery('YOUR>SELECTOR>HERE');

Hover over the line that was returned in the console and it should highlight the element in the DOM.

Seeing the Rage Click element
Seeing the Rage Click element

If you prefer element class over the selector, you can change the event action in GTM from the rc_element to GTM’s built-in Click Class variable.


Great! That’s it, should you need any help with tracking rage clicks using Google Tag Manager and Google Analytics, post your questions in the comments below.

Should you need further help with your analytics setup, take a look at our services.

Cover photo by Emmanuel on Unsplash

32 thoughts on “Tracking Rage Clicks Using Google Tag Manager and Google Analytics

  1. Hi – I’m trying to set this up and have no experience at all. I’ve got to the part where you set up a tag to send it to google analytics however in the google analytics settings tab it says “select settings variable” and when you click into that, its got a box for a tracking ID – what do I put here as nothing is working and I have no idea where to find the tracking ID.

    1. the tracking ID = which GA account you are sending info to.
      You can find tracking ID at GA -> admin -> property -> tracking info -> tracking code
      A tracking ID looks like “UA-12345678-2”

  2. Pingback: Leverage Hotjar Surveys for Rage Click Custom Events - Portent - Digital Marketing Digest
  3. Pingback: Google Tag Manager Use Cases - 99 Ideas - Analytics Mania - Digital Marketing Digest
  4. Pingback: Google Tag Manager Use Cases - 99 Ideas - Weslly Silva
    1. From the VARIABLES tab, create a new data layer variable. Name the variable as DLV-rc_element and put “rc_element” (wihtout quotes) in the Data Layer Variable Name tab. Do the same for other unknown variables.

  5. Hi,
    Thanks for the details, it works well !
    We see the event action & page recorded in Google Analytics. However, we don’t understand your very last explanation, I mean how to identify the rage click element in the page with the console…
    From this for example : “html>body>div:nth-child(2)>div:nth-child(3)” or “html>body>div:nth-child(2)>div:nth-child(2)>div>div>div>div>div>div>div>ul>li>div:nth-child(2)>div>div>div>div>div>h1”

    1. Hi!
      If you’re using Google Chrome, open the developer tools, navigate to console tab and paste document.querySelector('YOUR SELECTOR'); in the input field and click enter. Then hover over the matched element to see which element it is.
      If you’re still having trouble figuring this out, I recommend asking your developer 🙂

  6. I don’t speak JS, so I haven’t got a clue what this means.
    I copied the JS from Github and when previewing GTM, I get following message: Error at line 1, character 3: Parse error. primary expression expected
    What am I doing wrong?

      1. Yes, still not working. There is jquery on the site.

        if ( typeof(jQuery) === ‘function’ ) {
        jQuery(document).ready(function($) {
        jQuery.fn.extend({

  7. Pingback: Webinar Recap: Clicks, Conversions and Crawls! Analysing Clickstream Data with Michelle Robbins - DeepCrawl
  8. Best tutorial I’ve seen in a while. Currently testing with different thresholds for rage click duration and radius. Thanks!

    1. Hello Sarah!

      I’m glad you liked this post. Should figure out the best settings, feel free to share them here with others 🙂

  9. Hej
    Is this idea still working? I have tried it several times and still with no positive effect. I have an idea, could you record a video step-by-step how you configured your GTM?

    1. Hello Dawid,

      Yes, it is working. We have the exact same setup live on different sites. We might do a video tutorial in the future but it is planned in a few months.

      Could you provide some screenshots of your setup so we could take a look? Feel free to send them over via email [email protected]

  10. Pingback: Data You Should Be Tracking Using Google Analytics Custom Events - Reflective Data
  11. Pingback: Daily Search Forum Recap: September 18, 2019 – AdvertisSEO
  12. Love the idea of this solution.

    The only issue I have with it is the element detail.
    When I have an element return of something like: ‘html>body>nav:nth-child(15)>div>div>div>div>span’
    It has no meaning in GA.

    I think it would be more beneficial to maybe utilise the Click Class variable within GTM, is this something that can be adapted in the code?

    Regards

    1. Hello Dino,

      Thank you for your feedback. It really depends, we actually like grabbing the selector and pasting it in the console like $(‘your-selector’) to immediately see the element.

      If you want the click class you can use GTM’s built-in variable as your event label.

      Silver

      1. Thanks for the response Silver,

        That makes sense, I think I was thinking more around a GA users that isn’t so savvy using dev tools in Chrome.

        I guess rage clicks are something that require interpretation to the wider audience.

        I’ll have a play about to see what works best for us.

        Many thanks
        Dino

        1. Sure and thank you for pointing this out, I’m going to add a few more details about this in the post.

Leave a Reply

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

Sign up for Reflective Data

5,000 sessions / month ×

Please enter your email

Submit

After submitting your email, we will send you the registration form.