Introduction
As the internet users increasing exponentially, It is very important for enterprises to know how a user interacts with their website so that they can improve user experience accordingly.
In this article, We will be going to talk about how to get time spent by users on a webpage using simple Javascript and Node.js. At first, We will try to understand the concept or working behind it then will implement it using code.
Working
Before deep dive into the code, Let's try to understand the working behind it with the help of the below flow chart.
Implementation
Let's get some hands dirty on code.
1) Create a project folder.
mkdir time-spent-by-user && cd time-spent-by-user
2) Initialize npm in the folder.
npm init -y
3) Install the required dependencies.
npm install --save express
npm install --save ejs
4) Create an "app.js" file & write some code in it.
//app.js
const express = require('express');
const ejs = require('ejs');
const bodyParser= require('body-parser');
const app = express()
const port = 80
app.set('view engine', 'ejs');
app.use(bodyParser.json());
var analytics = {};
// It will render home page
app.get('/', (req, res) => {
res.render('index');
})
// ------------------------
// It will render dashboard page
app.get('/dashboard', (req, res) => {
res.render('dashboard', {"analytics": analytics});
})
// ------------------------
// It will catch the data sent from "sendBeacon" method on home page
app.post('/updatetimespentonpage', bodyParser.text(), function(req,res){
var body = JSON.parse(req.body)
analytics[body["uid"]] = (analytics[body["uid"]]) ? (analytics[body["uid"]] + body["timeSpentOnPage"]) : (body["timeSpentOnPage"]);
res.send({"status": "done"});
});
app.listen(port, () => {
console.log(`App listening at http://localhost:${port}`)
})
5) Create a "views" folder.
mkdir views && cd views
6) Create an "index.ejs" file in the views folder & write some code in it.
<!--index.ejs-->
<html>
<head>
<title>Home page</title>
</head>
<body>
User Id: <span id="uid"></span> </br>
Time spent on this page: <span id="time-spent">0s</span>
</body>
<script type="text/javascript">
// Check if uid already exist in cookie.
if (!getCookie("uid")) {
// if not, then create a new uid and store it in cookie.
document.cookie = "uid=U" + (Date.now().toString(36)).toUpperCase() + "; expires=Thu, 18 Dec 2030 12:00:00 UTC; path=/";
}
// -------------------------------------------
document.getElementById('uid').innerHTML = getCookie("uid");
// This setInterval function increment the value of "timeSpent" variable each second.
var timeSpent = 0;
var timeSpentInterval = setInterval(
function() {
timeSpent++;
document.getElementById('time-spent').innerHTML = timeSpent + "s";
}, 1000);
// ---------------------------------------------
// The beforeunload event triggers right before unloading of the window has begun
window.addEventListener("beforeunload", function() {
// When user close or refresh the web page, sendBeacon method asynchronously sends a small amount of data over HTTP to a web server.
navigator.sendBeacon('http://localhost/updatetimespentonpage', JSON.stringify({
uid: getCookie("uid"),
timeSpentOnPage: timeSpent
}))
});
// ---------------------------------------------
// Method used to get cookie
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
// -----------------------------------
</script>
</html>
7) Create "dashboard.ejs" file & write some code in it.
<!--dashboard.ejs-->
<html>
<head>
<title>Dashboard</title>
<style type="text/css">
table, th, td {
border: 1px solid black;
border-collapse: collapse;
padding: 10px;
}
</style>
</head>
<body>
<h2>Dashboard</h2>
<table>
<tr>
<th>User Id</th>
<th>Time Spent</th>
</tr>
<%
var total_time_spent = 0
for(i in analytics)
{
%>
<tr>
<td><%= i %></td>
<td><%= analytics[i] %>s</td>
</tr>
<%
total_time_spent = total_time_spent + analytics[i];
}
%>
<tr>
<%
if(Object.keys(analytics).length>0){
%>
<th>Total Users: <%= Object.keys(analytics).length %></th>
<th>Avg Time Spent: <%= (total_time_spent/Object.keys(analytics).length).toFixed(2) %>s</th>
<%
}
else{
%>
<td>NA</td>
<td>NA</td>
<%
}
%>
</tr>
</table>
</body>
</html>
8) Execute the "app.js" file.
//if you are inside the views folder
cd ..
node app.js
9) Open a browser & point to http://localhost, It will show you "UID" & time spent by you on the webpage.
10) Now, Close the browser tab & point to http://localhost/dashboard
11) Here you can see the list of all the users with their corresponding time spent on the page.
Conclusion
When the user closes or refreshes the home page, It fires the "beforeunload" event & lets the "sendBeacon" method send the time spent data to the server asynchronously. The server catches the data & store it in a variable (You can use a traditional database as well).
sendBeacon is intended to be used for sending analytics data to a web server, & avoids some of the problems with legacy techniques for sending analytics, Such as the use of XMLHttpRequest, Read more here
Check out the github code if you'd like to get sample implementation.
For more updates, follow me on Twitter.
Top comments (7)
Nice one!!
Consider using visibilitychange instead of beforeunload. Seems to work better on mobile phones.
developer.mozilla.org/en-US/docs/W...
Couldn't you just saved the time when the user opened the page in the cookie, and then when he leave the page, just calculate the difference between the time when he left, and the time when he opened the page? This way you will get the exact time spent on the site without the overhead that setInterval applies.
Yeah, We can achieve it in this way also
Yes, beforeunload seems work in most mobile browsers but a combo of visibilityChange and beforeunload can be considered. Instead of building basic front end capture, you can straight away integrate the Timeonsite.js at client-side and NodeJs for saving the data to MongoDB. TimeOnSite JS for client-side capture natively across web and mobile browsers
Thanks for this useful article. Just the thing that I needed :)
Thanks for the great content
Thank you, it makes my day to hear that.
Some comments have been hidden by the post's author - find out more