Build a Visitor Counter with JavaScript & Node.js

OpenJavaScript 0

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.