Analytics with vanilla JS: page views
Tags: javascript, webdev, agile, analytics
Published: 2019-11-29 18:46:01

**How to get basic page view statistics?**


Second article in the series Analytics with Vanilla JS. Motivation [here](http://zigabrencic.com/posts/2019-11-08.html).

Today we'll look into the impelentation of vanila JS analytics tool that analyses page views.

For the sake of example we need some simple HTML code for our tracker (file `example_page.html`). You can add anything you want to the HTML file:

```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/page_view_tracker.js"></script>
</head>
<body>
    <a href="https://www.google.com" class="external">Leave page by going to Google</a>
</body>
</html>
```

The rest of the code will be in `page_view_tracker.js`. First, let's define the function that will allow us to `POST` all the gathered data as a string to a specific URL:

```
function post_data(data, url) {
    let xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            console.log(xhr.responseText);
        }
    };
    xhr.send(data);
}
```

data in the string is in JSON format. The server you'll be sending data to can be whatever you prefer: `node.js`, `Django`, `flask`, ... There's even an option to post into Google Docs spreadsheets if you want to avoid the backend. 

Data is posted with the following command:

```
post_data(JSON.stringify(data), "http://0.0.0.0:5000/analytics");
```

where we defined data object as:

```
const data = {
    "current_page_name": current_page_name
};
```

Now let's add the rest of the data.

## Tracking

**Number of views per page**: this one is easy. Every time a user visits our website, the `post_data` function will be triggered, so we need to add `current_page_name` to our data object. It's defined with:

```
let current_page_name = window.location.href;
```

In principle, we could get the URL of the current page from the request on the backend by I prefer to have all the data in the `JSON` object.

**User origin:** We want to know from what website the user came from. This information is important because it allows us to track sources of our web site traffic. Are we getting:
- direct traffic (users entering the URL to browser), 
- traffic via referrals (links to our site),
or 
- via organic search (user finds us via a Search engine like Google, Bing, Baidu ...). 

In all browsers except the Internet Explorer, the following will give us the source from which user came:

```
let page_source = document.referrer;
```

If traffic is dirrect or user used Internet Explorer `page_source` will be empty so we set:

```
if (page_source === "") {
    // could be direct traffic or Internet explorer
    page_source = "empty";
}
```

Now we can detect what web browser the user has with something like [this](https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser), but that doesn't help us to determine the source from which the user came. If you know a workaround, please let me know how to get user origin in IE. 

**Device screen**: We want to know what devices the majority of our users are using. We get device screen size via:

```
let screen_width = window.screen.width;
let screen_height = window.screen.height;
```

and screen size that we can draw on with:

```
let screen_available_width = window.screen.availWidth;
let screen_available_height = window.screen.availHeight;
```

**Browser type, language, time zone**: To get the browser type we do:

```
let browser_type = navigator.userAgent;
```

the language:

```
let language = navigator.language;
```

and the time zone:

```
let time_zone_offset = Intl.DateTimeFormat().resolvedOptions().timeZone;
```

**Tracking parameters**: You can enhance your analytics if you publish URL-s with added parameters. For example, you can use the Urchin Tracking Module or UTM, a format used by Google to track your unique URLs:

```
http://www.example.com/?utm_source=JohnDoe&utm_medium=mail
```

By adding parameters to links you share, you can segment the traffic way better during the analysis process. For example: What was published by you, what was shared by others, social media source, ...

**Page performance:** We want to know how long does it take for our web page to load. For that, we need to understand a bit about web browser events:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/q0rznsi9erg9rtr1qafp.png)

- 1.) First, the browser sends the request to the server to get page files.
- 2.) Page files are sent to our device.
- 3.) Then the browser needs to render the web page.
- 4.) Once the web page is rendered, `onload`/`load` event is triggered.
- 5.) The user views the page.
- 6.) The `onload`/`onunload` event happens when the user closes the web page.

The page loading and rendering should happen in a matter of ms. If it doesn't, our user either has a really crapy internet, or we are sending over to many files. Either way, it's good to track that. According to [Mozilla docs](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_timing_API) we can obtain the data about page loading from:

```
let performance_data = window.performance.timing;
```

Then get:

```
let page_load_time = performance_data.loadEventEnd - performance_data.navigationStart;
let request_response_time = performance_data.responseEnd - performance_data.requestStart;
let render_time = performance_data.domComplete - performance_data.domLoading;
```

We need to trigger page performance monitoring code after the page is loaded. Full code snipet for page perfromance:

```
window.addEventListener("load", function () {
    let performance_data = window.performance.timing;

    // calculate request response time: network latency
    let request_response_time = ...

    // calculate page render time
    let render_time = ...


    // page load time: wait until load event is finished with setTimeout
    setTimeout(function () {
        let page_load_time = ...

        // Post data to the server
        ...
    }, 0);
});
```

`setTimeOut` is needed because we need to wait for the `load` event to finish before we can measure the page load time.

## Stay tuned

The **full code** can be found on my blog at [page views](zigabrencic.com/examples/page_views/docs.html). There you'll find the `HTML, JS, python` files you need to run the whole thing.

If you have any ideas what else we could track or how let me know in the comment section below.

I'm not a very proficient `JavaScript` developer, so there is probably a better way to do some of the parts. Any comments and solutions are welcome. Stay tuned for more. Next week we'll look into page view duration tracking. Why an entire article for that? Well, there are a few edge cases with web page closing that can complicate things.