Analytics with vanilla JS: page view duration
Tags: javascript, webdev, agile, analytics
Published: 2019-12-04 19:22:45


Third post in series: [**Analytics with vanilla JS**](http://zigabrencic.com/pages/analytics_series.html)

Page view duration is essential in determining whether our users read the content of our article or not.

To determine the time of user page visit, we need to detect two events:

- page view start time: `t_page_opened`
- page view end time: `t_page_closed`

## Request page, close page

We first cover the case of page view duration, which is the easiest to measure.

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

Let's say the user clicks a link or types the address of our web page to the web browser. The user will land on our web page. The page files will be sent over from the server that hosts the web site.

In this case, when the page is loaded, we can detect `onload` Java Script event and determine that as the start of page visit with:

```
window.onload = function () {
    t_page_opened = new Date();
};
```

Now let's say that the user leaves the web page by closing the browser tab or browser window. We can detect that via `beforeunload` event by adding the event listener:

```
window.addEventListener("beforeunload", leftWebSite);
```

`leftWebSite` function then get's the time stamp when user left the page:

```
function leftWebSite() {
    const t_page_closed = new Date();

    const data = JSON.stringify({
        "page_opened": t_page_opened,
        "page_closed": t_page_closed
    });
    post_data(data, "define_URL");
}
```

and sends the `t_page_opened` and `t_page_closed` to the a prediefined `URL` with `post_data` function:

```
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);
}
```

**Job done, right? Far from it.**

If we want to have a proper estimate of the read times, we need to be really careful about potential corner cases for page opening and page closing.

Wait? Page view start and page view end should be determinable in a few lines of code. Not quite. 

## User leaves the web site

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

What if the user left the page via a link, history forward or history back button, lost internet connection, refreshed the web page. In those cases, `beforeunload` won't get consistently triggered (from browser to browser). 

Let's list the cases we need to cover. When the user leaves the page via:

- Browser tab/window closing: detected via `beforeunload`. Solved.
- internal or external link: detectable via `onclick` event
- internet connection lost:
    - connection reestablished during page view: no issue
    - user revisits a page in the future: fetch view data from user browser `localStorage` if the user didn't clean it
    - the user never comes back to our site: data lost
- page refresh: can be detected with the help of `localStorage`
- page left via history back, forward button: using `pagehide` event, since page `JS` won't be re-loaded and `beforeunload` event won't be triggered.

Keep in mind that the solutions that use `localStorage` won't work if the user:

- disabled the use of local storage,
- uses incognito browser mode.


## User opens the web site

To detect if the user opened the web site is slightly easier. There are just three cases to handle:

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

We already handled the first case with `onload`. To handle the page left via history back, the forward button, we again use `pagehide` event.

## Tackling edge cases

In the upcoming articles we'll cover the code needed for:

- *detecting: page refresh, history button clicks, internal-external links*
- *detection of incognito mode*
- *detection of internet connection loss*

But even after we handle all of those cases, we won't ensure the correct estimate of reading time. What if the user opens the web page, leaves it open and goes to the toilet. Or scrolls through the article really fast. Well, we could monitor page scrolls. This way, we could eliminate a few more edge cases that could corrupt our read time estimates and analysis. Stay tuned.