Building an Online Activity Tracker in JavaScript
Capture and analyze user interactions for better UX
Are you looking to gain insights into how users interact with your website or web application? Having a comprehension of user conduct is significant for enhancing the overall experience and using data-oriented judgments. In this blog post, we'll walk you through the implementation of a user activity tracker in JavaScript, allowing you to monitor user interactions and gather valuable data.
Introduction
Understanding user behavior is essential for improving user experience and making data-driven decisions. To achieve this, there are many third party tracking application like Google Analytics which collect lots of analytics data and analysis. But today, we'll build our own user online activity tracker in JavaScript that captures various user interactions, such as clicks, mouse movements, and key presses, and sends this data to a server for analysis.
Implementation
Let's look at step by step guide to build our own online activity tracker from scratch.
- Initialization: We'll initialize our tracking function name as
Tracker
which firstly checks if the document has focus.
OnlineTracker() {
if (!document.hasFocus()) {
return
}
}
Here, if you want to go one step further and track activity of only your logged in users, then you can check whether user is logged in.
- Event Listeners: The tracker will listen to several user events like
click
,mousemove
,keydown
,touchstart
, andtouchend
. These events allow us to capture various user interactions.
const events = ["click", "mousemove", "keydown", "touchstart", "touchend"]
You can listen for other set of events if you would like to track other events also.
- Data Storage: Before sending data to server, we'll use browser's
localStorage
to store tracked data temporarily. For data storage, initially user's online activity data will be stored inactivityLog
object. It will record information such as the current page URL, timestamp, log of user events like clicks count, etc. Then it is stored inlocalStorage
.
activityLog.page = window.location.pathname
activityLog.page_full_url = window.location.href
activityLogString = JSON.stringify(activityLog, null, 2)
localStorage.setItem("activityLog", activityLogString)
- Activity Log Reset: We'll add a
reset
function to clear the stored activity logs. This function will be called when the tracker initializes or after a certain inactive threshold is reached.
async function reset() {
localStorage.removeItem("activityLog")
clickCount = 0
activityLog = setActivityLog()
}
- Data Synchronization: Then, we'll add a
syncData
function to periodically sends the tracked activity log to the server for analysis. It will also check if the user has been inactive for an extended period and resets the activity log if necessary.
function syncData() {
// check if not inactive until the limit
if (inactiveThresholdCount < INACTIVE_THRESHOLD_LIMIT) {
saveActivityLog(localStorage.getItem("activityLog"))
.then(reset())
}
}
- Previous Activity Retrieval: Before sending data to server, a function
getPreviousActivity
will be added to retrieve the previous activity log fromlocalStorage
when the page loads. This ensures that we continue tracking user activity even after a page refresh.
function getPreviousActivity() {
const previousString = localStorage.getItem("activityLog")
if (previousString && previousString.trim() !== "") {
activityLog = JSON.parse(previousString.trim())
clickCount = activityLog.events.clicks.count
}
}
- Sending Data to the Server: Finally, the tracked user's online data will be sent to the server. This is done through
saveActivityLog
function. It will calculate the duration of the user's session and include it in the data payload. Here, we'll usefetch
API but you can use HTTP request library of your choice.
async function saveActivityLog(activityLogString) {
const requestData = (activityLogString && activityLogString.length) ? JSON.parse(activityLogString) : activityLog
requestData.duration = parseInt((new Date() - new Date(requestData.startTime)) / 1000) || 0
fetch.post("<URL>", requestData)
.then(res => {})
.catch(err => {
console.log(err)
})
inactiveThresholdCount++
}
Full code
import { cloneDeep } from "lodash"
const SYNC_INTERVAL = 1000 * 60 * 10 // decide interval at which you want to sync data to server
const INACTIVE_THRESHOLD_LIMIT = 1 // set the threshold which will be used to check user's inactivity period
export default {
OnlineTracker() {
if (!document.hasFocus()) {
return
}
const events = ["click", "mousemove", "keydown", "touchstart", "touchend"]
let inactiveThresholdCount = 0
let clickCount = 0
const activityLogStructure = {
page: window.location.pathname,
page_full_url: window.location.href,
events: {
clicks: {
count: 0,
events: [],
},
},
startTime: new Date(),
}
// set new activity object in case of new or after reset
const setActivityLog = () => {
const object = cloneDeep(activityLogStructure)
object.startTime = new Date()
return object
}
let activityLog = setActivityLog()
let activityLogString
async function saveActivityLog(activityLogString) {
const requestData = (activityLogString && activityLogString.length) ? JSON.parse(activityLogString) : activityLog
requestData.duration = parseInt((new Date() - new Date(requestData.startTime)) / 1000) || 0
fetch("<URL>", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(requestData),
})
.then(res => {})
.catch(err => {
console.log(err)
})
inactiveThresholdCount++
}
async function reset() {
localStorage.removeItem("activityLog")
clickCount = 0
activityLog = setActivityLog()
}
function syncData() {
// check if not inactive until the limit
if (inactiveThresholdCount < INACTIVE_THRESHOLD_LIMIT) {
saveActivityLog(localStorage.getItem("activityLog"))
.then(reset())
}
}
function getPreviousActivity() {
const previousString = localStorage.getItem("activityLog")
if (previousString && previousString.trim() !== "") {
activityLog = JSON.parse(previousString.trim())
clickCount = activityLog.events.clicks.count
}
}
setInterval(function() {
// send data on regular interval
syncData()
}, SYNC_INTERVAL)
document.addEventListener("DOMContentLoaded", function() {
// sync url and previous data (if exist) on DOM load
getPreviousActivity()
activityLog.page = window.location.pathname
activityLog.page_full_url = window.location.href
activityLogString = JSON.stringify(activityLog, null, 2)
localStorage.setItem("activityLog", activityLogString)
syncData()
// listen for each event
events.forEach(function(e) {
document.addEventListener(e, function(evt) {
getPreviousActivity()
// if events not detected until threshold - consider user as inactive and renew time after event track started
if (inactiveThresholdCount >= INACTIVE_THRESHOLD_LIMIT) {
activityLog.startTime = new Date()
}
inactiveThresholdCount = 0
if (e === "click") {
activityLog.events.clicks.count = ++clickCount
const eventData = {
position: {
x: evt.x,
y: evt.y,
},
element: {
node: evt.target.nodeName,
id: evt.target.id,
className: evt.target.className,
},
text: evt.target.innerText || evt.target.value,
pageUrl: window.location.href,
}
activityLog.events.clicks.events.push(eventData)
}
activityLogString = JSON.stringify(activityLog, null, 2)
// save events in local storage
localStorage.setItem("activityLog", activityLogString)
})
})
})
},
}
Conclusion
In this blog post, we've introduced a JavaScript-based online user's activity tracker that captures user interactions and sends the data to a server for analysis. This tool can be invaluable for gaining insights into user behavior, identifying pain points in your web application, and making informed improvements.
By implementing an online user's activity tracker, you can enhance the user experience, optimize your website's performance, and ultimately achieve better engagement with your users. Remember to handle user data responsibly and in compliance with relevant privacy regulations.