How to keep track of online users with WebSockets

3 months ago

One of the major necessities with today's technologies is how to efficiently keep track of the online users. Many application features could be turned on/off depending on whether the user is online or offline.

Traditionally, the approach to solve this problem has been to implement some type of pinging mechanism on the client-side where the browser sends pings to the server ( in our case a WebSocket server ) when the user comes online. The browser will keep on sending pings in regular intervals to let the server know that the user is still online. Once the user logs off the server is notified yet again that the user is now offline. This method is flawed because it does not take into consideration several possibilities such as

  • when the user simply closes the browser tab
  • when the user loses the internet connection

To overcome this problem a purging mechanism ( on the server-side ) would be implemented that runs every few minutes to check if the last user's timestamp is older than a minute, and if it is removes the user from the online_users array and broadcasts the new list. In theory this should work but in practice this approach introduced gaps when the user might already be offline but the purging function has not yet run and thus the system still thinks that user is online.


Well, I believe there is a better solution out there and here is my implementation of it (the inspiration for this implementation came from a stackoverflow post here https://stackoverflow.com/a/52559338/2469475).

Step 1: Setting up the WebSockets server

let onlineUsers = [];

function addOnlineUser(ws){
    if (!onlineUsers.includes(ws.user_id)){
        onlineUsers.push(ws.user_id);

        app.publish(ws.channel, JSON.stringify({
            type: 'onlineUsers',
            body: {
                onlineUsers
            }
        }));
    }
}

function removeOnlineUser(ws){
    onlineUsers.find((user_id, index) => {
        if (user_id === ws.user_id){
            onlineUsers.splice(index, 1);

            app.publish(ws.channel, JSON.stringify({
                type: 'onlineUsers',
                body: {
                    onlineUsers
                }
            }));
        }
    });
}

Step 2: Setting up the client-side

let onlineUsers = [];

function getOnlineUsers(){
        return onlineUsers;
}

function isUserOnline(user_id){
        return _.includes(getOnlineUsers(), parseInt(user_id));
}

function setOnlineUsers(onlineUsers=[]){
        onlineUsers = onlineUsers;
}

function onWebsocketsMessage(message){
    if (message.type==='onlineUsers')
        setOnlineUsers(message.body.onlineUsers);
}

The secret sauce lies in the inherited behavior of the WebSockets. The client-side pings the server in an interval and the server responds with pongs. That also means that we can use that to know exactly who is online.

We have implemented this solution in our project ( Cogency Video ) that allows the online team members to request 1-1 video calls with one another and it has been working extremely well thus far :)

Loading resources, please wait...