Activity detector

Publicado el 19/10/2016 por by Abel Toledano, Senior Software Engineer

Sometimes, when you want to do some action in your page using JavaScript it’s very convenient to know whether the user is actually paying attention to your page at that moment, because, as you probably know, the JS in your page can be executing even when it is in background. For example, the user can be reading a different browser tab, or even using a different application and the browser doesn’t have the focus.

In Tuenti we have had to deal with this kind of problems in different situations. One clear example is the Tuenti chat: we want to notify the user about new messages playing a notification sound, but we don’t want to play it when the user is already paying attention to the conversation, we only want to play the notification sound when the page is in background to take the user’s attention.

To achieve this we listen to different browser events to determine whether the user is actually using Tuenti at that moment or not. These are some of the events we listen to:

focus and blur events in window:

When a user enters to your page, the browser fires a focus event in the window object. In the same way, when the user changes to a different tab or application, the browser fires a blur event.

Taking this into account, it’s pretty simple to determine whether the user is in your tab:

var inTab = true;

window.addEventListener('focus', function () {
  inTab = true;

window.addEventListener('blur', function () {
  inTab = false;

Pretty simple, isn’t it?

Well… it depends on what you really need. With this simple code you can know whether the user is in your tab, but what happens if the user is in your tab but he has left the computer and is in the bathroom?

So we don’t only need to know if the user is in our tab but also if he is using it. To solve this problem we could connect the laptop webcam and spy the user, but probably our users wouldn’t like that. So we can use a simpler (and more privacy respectful) solution:

Mouse and keyboard events

We can listen to DOM user interaction events to know if the user is actually using the page, and when we have not heard any event for a given time span (for example 30 seconds) we can assume the user is not active. Some events we can listen to are: click, mousemove, keydown, etc (for desktop devices), or touchstart, touchmove, etc. (for mobile devices).

So we can attach some event listeners to the document and toggle the inTab variable in the previous example to true. But, when we change it to false? when it has elapsed 30 seconds since the last event. This behavior can be implemented with a setTimeout, but we also need to reset that timeout (with a clearTimeout) when we hear a new event.

We can express this solution with a simple state machine:

state machine

Ok, beautiful, let’s implement it. You don’t need to do it! because we have already done it and opensourced a library that you can use: activity-detector:

How to use

First, install it.

We distribute the lib in npm, so you can install it with a simple command:

$ npm install --save activity-detector

Let’s see a basic example

// 1. import the lib:
import createActivityDetector from 'activity-detector';

// 2. create an activity-detector instance:
const activityDetector = createActivityDetector();

// 3. subscribe to events
activityDetector.on('idle', () => {
  console.log('The user is not interacting with the page');

activityDetector.on('active', () => {
  console.log('The user is using the page');

How this work? the library implements the algorithm we have presented in the previous state machine diagram. When you create an instance of activity-detector you can subscribe to the events active and idle. Those events will be triggered when the user becomes ACTIVE or INACTIVE respectively.

And that’s all. Now you can detect when your user is using your page or not.

Ok, but I don’t use npm neither ES6. Can I use activity-detector lib?

Of course, we have a production ready build (UMD format) that you can simply include in your page with a simple <script> tag, or require it with any module loader (like require.js). You can find it here.

For example:

    test activity detector

Advanced options

activity-detector supports different config options to customize its behavior if you have different needs. For example you can decide which user events should be considered, or defer the activity-detector initialization. For example:

const activityDetector = createActivityDetector({
    timeToIdle: 10000, // wait 10s of inactivity to consider the user is idle

You can see the different options reading the docs in the github repo:

If you like it and think it’s useful don’t forget to star it. And if you miss some feature or find a bug please open an issue or, even better, send us a pull request!