Build a Visitor Counter with JavaScript & Node.js
Last updated: November 22, 2022.
In this tutorial, we show you how to build a visitor counter that you can display to your users. The counter will count pageviews and visits independently of one another.
For this, some backend programming is required to keep a record of visitor and pageview counts. We’ll use Node.js to create a server that will do this for us without having to rely upon a third-party API.
Frontend
Let’s start with the HTML.
Below is some suggest markup for the frontend. The important part is the two <span>
elements which we will select by their ID with JavaScript to insert the counts:
<main id="container">
<div>
<span id="pageviews-count"></span>
<h4>Pageviews</h4>
</div>
<div>
<span id="visits-count"></span>
<h4>Visits</h4>
</div>
</main>
And here is some sample CSS so it looks a little better:
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
body {
display: flex;
justify-content: center;
align-items: center;
font-family: 'Roboto', sans-serif;
color: black;
}
#container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
text-align: center;
margin: 2rem;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
padding: 2px 16px;
}
#container > div {
padding: 1rem;
margin: 1rem;
width: 7rem;
}
#container span {
font-size: 2rem;
font-weight: bold;
}
#container h4 {
font-size: 1rem;
font-weight: normal;
margin: 0;
margin-top: 1rem;
}
With JavaScript on the frontend we distinguish between a new visit and pageview from a pageview only using sessionStorage
. Because its contents are cleared at the end of a user session (when a user closes the current tab) we can use it to check if it is a new session (visit).
The request we make to the server we will create is dynamic: if it is a new visit, type=visit-pageview
is sent as a URL parameter. For a pageview only type=pageview
.
const pageviewsCount = document.getElementById('pageviews-count');
const visitsCount = document.getElementById('visits-count');
if (sessionStorage.getItem('visit') === null) {
// New visit and pageview
updateCounter('type=visit-pageview');
} else {
// Pageview
updateCounter('type=pageview');
}
function updateCounter(type) {
fetch('http://127.0.0.1:3002/api?'+type) // Dynamic request with URL parameter
.then(res => res.json())
.then(data => {
pageviewsCount.textContent = data.pageviews; // Display pageviews to user
visitsCount.textContent = data.visits; // Display visits to user
})
}
sessionStorage.setItem('visit', 'x');
// 'visit' item persists in storage for the remainder of the user session
The backend
When the request come in to the server, a JSON file is updated to reflect the new visits and pageviews count. The response sent back to the user is the updated JSON data:
/* app.js */
const express = require('express');
const app = express();
const cors = require('cors');
const fs = require('fs');
app.use(cors()); // Prevents CORS error
app.get('/api', function(req, res) {
if (req.url === '/favicon.ico') {
res.end();
}
// Ends request for favicon without counting
const json = fs.readFileSync('count.json', 'utf-8');
const obj = JSON.parse(json);
// Reads count.json and converts to JS object
obj.pageviews = obj.pageviews+1;
if (req.query.type === 'visit-pageview') {
obj.visits = obj.visits+1;
}
// Updates pageviews and visits (conditional upon URL param value)
const newJSON = JSON.stringify(obj);
// Converts result to JSON
fs.writeFileSync('count.json', newJSON);
res.send(newJSON);
// Writes result to file and sends to user as JSON
})
app.listen(3002, () => {
console.log("Server running on port 3002");
})
Finally, we create count.json
with the two properties visits
and pageviews
and set starting values.
{
"pageviews": 665,
"visits":330
}
Now, run app.js
from the command line:
node app
Open index.html
and you will see the current count. Refresh and open in a new tab to see it update.