Analytics For Website

Web analytics that show their working

Paste one script into your pages and this records every page load, then tells you where the traffic came from, which pages people read, what they clicked, and which hours of the week your visitors actually show up. Every figure links back to the events it was computed from, and every definition is written down.

The demo above is a real site on this installation with real traffic. No signup, nothing hidden.

Analytics for Website
–
page views today on the public demo site

What you get on every site

Each panel below exists in the product. The links open the public demo so you can see the real thing rather than a screenshot.

Traffic over time

Page views, unique visitors, sessions, average time on page and bounce rate, plotted by minute, hour, day, week, month, quarter or year, with any previous period overlaid for comparison.

See the graphs

Where visitors are and where they came from

A map of current visitors plus breakdowns by country, region, city, referring site, language, source, campaign and the exact pages they loaded.

See the map and tables

What people used the page for

Click heatmaps on a 24×24 grid, the elements visitors clicked most, and how far down the page they scrolled. Filter by page and by day.

See behaviour analytics

When your audience is awake

A 7×24 grid of visits by weekday and hour, in your own timezone, so you can tell a Tuesday-morning audience from a Sunday-evening one.

See the hourly grid

Goals and conversions

Define a goal as a page URL or a clicked element, then watch sessions, visitors and conversion rate against it over any period.

See goals

Campaigns

Traffic and conversions grouped by the campaign parameters your links carry, so you can tell which campaign produced a signup rather than a click.

See campaigns

How it works

Add the site

Give it a name and the address it will appear on. Each site gets its own tracking script and its own set of pages.

Paste one block

Add the snippet at the bottom of every page you want counted. It loads asynchronously and makes no third-party requests.

Read the numbers

Visits arrive within a second or two and appear in the live counter. The hourly and daily rollups are recomputed just after midnight.

What the words mean

Analytics products rarely agree on these, so here is exactly what each one counts here. The same list is on the dashboard itself.

View
One page load. Counted when the page is first seen. The "time on page" report a browser sends when a tab is hidden updates that same view rather than adding another, so reloading a page does count twice.
Session
One browser tab, tracked with a per-tab cookie. Navigation inside the tab stays in the same session. Because it is a tab and not a person, three open tabs count as three sessions, and "online now" is measured in sessions rather than visitors.
Visitor
A distinct long-lived cookie. Clearing cookies, switching browser or a private window each start a new visitor, so visitor counts are a floor, not a headcount.
Bounce rate
Share of sessions that produced a single view. A session that spans midnight is counted on the day it started.
Bots
Matched from the user agent string. Bot traffic is counted separately and can be excluded from any chart with the humans/bots filter.
Where the time comes from
The server timestamps each event when it receives it, not the visitor's clock. Charts are drawn in the timezone of whoever is looking at them.

Tracking snippet

This is the entire integration. Replace the host with the address this installation is reachable on and 41 with the id of your own site. Put it before the closing </body> tag on every page you want counted.

<script> (function () { var s = document.createElement('script'); s.async = true; s.src = 'https://your-host/track.js'; s.addEventListener('load', function () { addWebsiteId(41); }); var first = document.getElementsByTagName('script')[0]; first.parentNode.insertBefore(s, first); })(); </script>

The script is about 10 KB uncompressed, 3.4 KB over gzip, served with a one-hour cache header. It loads asynchronously and makes no third-party requests — the only network calls it makes are the beacons back to this host.

What the script sends

Everything below is sent by the snippet itself. Nothing is fetched from a third party and no cross-site identifier is read.

On every page load

One page view, sent immediately. It carries the page URL, the referring URL, viewport size, browser language, platform and user agent string, plus campaign values from utm_source, utm_medium and utm_campaign (or the shorter source, medium, campaign).

When the tab is hidden

A duration update carrying how long the page was actually visible. The server applies it to the page view already stored rather than creating a second one, so closing a tab never inflates the count.

Behavioural events

Clicks (with the element path, tag, id or class, up to four levels deep), scroll depth as a percentage, sampled cursor positions and viewport resizes. These are what the heatmaps and scroll figures are built from.

Identifiers

Two values are stored in the visitor's own browser and sent with each event. Neither is a third-party cookie and neither is shared between sites:

localStorage afw — a long-lived visitor id. This is what "unique visitors" counts.

sessionStorage afw_sid — a per-tab session id, discarded when the tab closes. This is what "online now" counts, which is why it measures tabs rather than people.

The server also receives the request IP and resolves it to a country, region and city at ingest; the stored row keeps that resolution, not the address.

Turning behaviour tracking off

Click maps, scroll depth and cursor sampling are the only part that watches interaction rather than page loads. Disable them before the script loads, either on the script tag:

<script data-behavior="off" src="https://your-host/track.js"></script>

or in your own code, which also lets you tune the sampling rate:

window.AFW_CONFIG = { behavior: false }; // or: { behavior: { moveSampleMs: 2000, flushIntervalMs: 5000, maxBatchSize: 50 } }

Page views, sessions and campaign attribution keep working; the behaviour panels simply stay empty.