JavaScript Track User Activity On Webpage With Custom Script

Time Spent, Scrolling, Mouse Clicks, Mouse Movement, and Key Presses

In this post we create a custom JavaScript front-end script to track user activity on a webpage.

The tracking of course is not as sophisticated as Google Analytics. It surely is incomplete, may have bugs, and might miss edge cases. But it’s a starting point nonetheless.

Live Example

First, let’s see the real-time counters in the table below. Scroll, click (anywhere in the body, then on dummy button and link at the bottom), move mouse, and key press to see the values increment. Change tabs or windows to see timer stop and start. Sit idle for 10 seconds, and it will stop too.

Time Spent 00:00:00
Scrolling
Mouse Clicks
Button Clicks
Link Clicks
Mouse Movement
Key Presses

Dummy Link

The Implementation

Let us quickly discuss a few implementation details:

Initial Wait

When the page loads the timer starts automatically. The initial wait is 3 seconds, in which if there’s no activity, the timer stops.

Interval Wait

On every activity, we reset the start time. The interval wait is 10 seconds from the start time, after which, if there’s no activity recorded, we stop the timer.

10 seconds is a reasonable choice because if the user is not interacting with the screen in any way for more than 10 seconds, then they’re most likely not viewing the page. But it’s still an arbitrary value which you can change to more or less than 10 seconds.

Timer

Our calculations for timer are in milliseconds, which we convert to hh:mm:ss format with a helper method.

Timer Check Interval

We check and refresh the timer every second.

Screen Visibility

Every second we check if the screen is visible or not with Document.hidden check before doing any other calculation. So if you’re on another tab or window, the timer stops immediately.

Events To Track

We listen to mouseup, keydown, scroll and mousemove events. For Button and Link clicks, we check their event target nodeName to be “Button” or “A” respectively.

Using The Tracked Values

Since this implementation is for demonstration, we use the counter values for display only. In the code shared below, we do that by getting the elements by their ids and replacing their innerHtml with their counter values.

To create a complete custom analytics solution of your own, however, you’ll need to send these values to the backend and persist them in a database. You could use polling or sockets to transfer the data from front-end.

Additionally, you’ll also need to find the user’s country with a geolocation API, such as ipstack, and track a session with cookies.


The Code

<script>
  var INITIAL_WAIT = 3000;
  var INTERVAL_WAIT = 10000;
  var ONE_SECOND = 1000;

  var events = ["mouseup", "keydown", "scroll", "mousemove"];
  var startTime = Date.now();
  var endTime = startTime + INITIAL_WAIT;
  var totalTime = 0;
  var clickCount = 0;
  var buttonClickCount = 0;
  var linkClickCount = 0;
  var keypressCount = 0;
  var scrollCount = 0;
  var mouseMovementCount = 0;
  var linkClickCount = 0;

  setInterval(function () {
    if (!document.hidden && startTime <= endTime) {
      startTime = Date.now();
      totalTime += ONE_SECOND;
      document.getElementById("timer").innerHTML = formatTime(totalTime);
    }
  }, ONE_SECOND);

  document.addEventListener("DOMContentLoaded", function () {
    events.forEach(function (e) {
      document.addEventListener(e, function () {
        endTime = Date.now() + INTERVAL_WAIT;
        if (e === "mouseup") {
          clickCount++;
          document.getElementById("click").innerHTML = clickCount;
          if (event.target.nodeName === 'BUTTON') {
            buttonClickCount++;
            document.getElementById("button").innerHTML = buttonClickCount;
          }
          else if (event.target.nodeName === 'A') {
            linkClickCount++;
            document.getElementById("link").innerHTML = linkClickCount;
          }
        }
        else if (e === "keydown") {
          keypressCount++;
          document.getElementById("keypress").innerHTML = keypressCount;
        }
        else if (e === "scroll") {
          scrollCount++;
          document.getElementById("scroll").innerHTML = scrollCount;
        }
        else if (e === "mousemove") {
          mouseMovementCount++;
          document.getElementById("mouse").innerHTML = mouseMovementCount;
        }
      });
    });
  });

  function formatTime(ms) {
    var seconds = Math.floor(ms / 1000);
    seconds = seconds < 10 ? "0" + seconds : seconds;

    var minutes = Math.floor(ms / (1000 * 60));
    minutes = minutes < 10 ? "0" + minutes : minutes;

    var hours = Math.floor(ms / (1000 * 60 * 60));
    hours = hours < 10 ? "0" + hours : hours; 2

    return hours + ":" + minutes + ":" + seconds;
  }

</script>

See also