I recently worked on a project to monitor the content consumption of consumers on a website. The goal was to track the time spent reading content by category, tag, etc. for each consumer profile (which may or may not be anonymous). The thought was at the end of every pageview, I would take the article title, URL, category, tags, and time spent reading the article and push it (via a dataLayer.push and Google Tag Manager) to a Customer Data Platform (CDP) for later use in marketing channels such as website personalization and email.
For example, like this:
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'post_title': 'What is fiat money',
'post_url': 'https://example.com',
'post_category': 'finance',
'post_tags': ['currency','commodities'],
'user': 1029091,
'time_spent_on_page': 32
});
It sounds ideal and in theory should work fine. Until you realize JavaScript has some very large gaps. Browser inconsistencies, accounting for minimizing the browser, accounting for tab changes, etc.
The JavaScript code to measure the time spent on a webpage is below. The code accounts for minimizing the browser window and switching tabs, although support across all browsers is sketchy. The code is highly unreliable. So much so that for my use case, it simply won’t work and I had to abort the project. Ultimately, if we want to reliably store time spent on a webpage, we’re going to need to use server side code and store the time spent metric in a database. I explain the issues with this code after the snippet.
let isActive = true;
let startTime;
let totalTime = 0;
// function to start tracking time
function startTrackingTime() {
isActive = true;
startTime = Date.now();
trackTime();
}
// function to stop tracking time
function stopTrackingTime() {
isActive = false;
totalTime += Date.now() - startTime;
}
// function to track time
function trackTime() {
if (isActive) {
totalTime += Date.now() - startTime;
startTime = Date.now();
}
}
// start tracking time on page load
startTrackingTime();
// track time when user switches tabs
document.addEventListener("visibilitychange", function() {
if (document.visibilityState === 'hidden') {
stopTrackingTime();
} else {
startTrackingTime();
}
});
// track time when user minimizes window
window.addEventListener("blur", function() {
stopTrackingTime();
});
window.addEventListener("focus", function() {
startTrackingTime();
});
// get total time spent on page
window.setInterval(function() {
trackTime();
console.log("Total time spent on page: " + totalTime / 1000 + " seconds");
}, 1000);
// track time when user closes the window
window.addEventListener("beforeunload", function() {
stopTrackingTime();
console.log("Total time spent on page: " + totalTime / 1000 + " seconds");
});
There are a few reasons why the beforeunload
event listener may not always work reliably:
beforeunload
event differently, so your code may work as expected in some browsers but not in others.beforeunload
event is triggered just before the browser unloads the page, which means that there may not be enough time to execute all the code that you want to run. In particular, some browsers may ignore the event.returnValue
property and close the window before your code has a chance to run.To work around these issues, you may want to consider using other methods to track the time spent on the page, such as sending periodic heartbeats to the server using AJAX or WebSocket requests. You can then calculate the total time spent on the page on the server side and store it in a database or session variable.
Another option is to use a third-party service or library that tracks user behavior on your website, such as Google Analytics or Hotjar. These services provide more sophisticated tracking and analysis capabilities than you could achieve with simple JavaScript code.