Product guides

How we count

Exactly what a visitor, a visit and a bounce mean here — and what these numbers do not include.

Why this page exists

Every analytics tool disagrees with every other one, and a tool that will not say how it counts is asking to be trusted rather than checked. This page is the definition, written so you can hold the numbers to it.

Where a rule has a limit, the limit is stated here too. A caveat you have to discover is worse than one you were told.

A day is a day where your site is

Days are bucketed in the timezone set for the site (Settings). “Today”, “Last 7 days” and every daily bar begin at midnight where you are, not at midnight UTC.

This matters more than it sounds. A site set to UTC while its readers are in California has its evening traffic counted on the following day — the bar you are reading is the wrong bar, by a consistent eight hours. Set the timezone before you compare anything.

Days that are 23 or 25 hours long because the clocks changed are counted as one day, not as 24 hours. A week is seven calendar days, not 168 hours.

A visitor

By default nothing is stored on the device — no cookie, no local storage, nothing to consent to. A visitor is identified by a hash of their IP address, their browser's user-agent string, the site id, and a secret salt that is replaced every day.

Because the salt changes daily, the same person browsing on two consecutive days is two visitors. That is the cost of not tracking anybody: a daily count is accurate, and a “unique visitors this month” figure is not a count of people and is not offered as one.

The IP address is sent to the database, hashed there, and never written down. It is not in the event row, not in an export, and not in the API.

A site can switch to cookie identity in Settings, where your own first-party cookie supplies the id instead. That is more accurate across days and it is a cookie, with everything that implies for consent — which is why it is off unless you choose it.

Calling identify() with your own customer id (see Identify) is the third option and the most accurate of the three, because it is your record of who someone is rather than our guess.

A visit

A visit — a session — is a run of activity from one visitor with no gap longer than 30 minutes. The gap is measured from the last event, so a long read does not end a visit and a tab left open overnight does not extend one.

A visit belongs to the day it started. A visit that begins at 23:50 and ends at 00:20 counts once, yesterday.

A bounce, and time on site

A bounce is a visit with one pageview or none. Bounce rate is bounced visits divided by all visits in the window.

Visit duration is the time between the first and last event of a visit, averaged across visits that lasted longer than zero seconds. Single-event visits have no duration to measure, so they are excluded from the average rather than counted as zero — including them would drag every site's average toward nothing and say more about how many people read one page than about how long anybody stayed.

This means time on site is measured to the last thing that fired, not to the moment the tab closed. Nobody can measure the latter; anyone claiming to is inferring it.

Events recorded from your server

An event sent through the API or a payment webhook has no browser behind it, so it joins to nobody: it counts as an event, and as revenue where it carries an amount, and adds no visitor and no visit.

If you pass your own customer id with it, it joins to that customer instead, and purchases by one buyer are one buyer.

Passing spx_visitor through your checkout metadata connects a payment back to the session that produced it, which is what lets revenue be attributed to a source. Without it the money is counted and the source is left unattributed rather than guessed at.

What is filtered out

Requests whose user-agent declares a bot, crawler, spider, preview fetcher, headless browser or scripted client are dropped before anything is recorded, as are requests that send no user-agent at all.

A request that claims to be an ordinary browser while sending none of the headers a browser always sends is dropped too. Both signals have to be missing, never just one — an older Safari and a privacy-focused build each omit one legitimately, and dropping a real visit is a worse mistake than counting a fake one.

This is the honest half of a hard problem. A crawler that announces itself is easy to drop; one that copies Chrome exactly is not detectable from a user-agent, and we do not claim to catch it. Read the figures as an upper bound.

AI crawlers are identified separately rather than discarded, because whether ChatGPT and Perplexity are reading your site is a thing you want to know. They are on their own tab and are not in your visitor counts.

You can exclude your own office or country in Settings; those requests are dropped at the door and never reach a chart.

What is never collected

Query strings. Only the path is kept, because session ids, email addresses and password-reset tokens live in query strings and storing them would make your analytics a liability rather than a service. UTM tags are read and then the rest is discarded.

The full referring URL. The referring origin and path are kept; anything after them is dropped for the same reason.

Anything from the device beyond what a browser sends to every server it talks to. No fingerprinting, no canvas, no font enumeration.

Event properties are capped in number and length, and nested objects are dropped rather than flattened.

Why this will not match Google Analytics

It will not match, and neither number is wrong. GA4 is removed by content blockers on a large share of traffic, samples large reports, and withholds rows under privacy thresholds. A first-party script is blocked differently and defines a session by different rules.

The useful check is not whether the two agree but whether their ratio holds steady. A stable ratio means both are working. A moving ratio means something changed, and that is worth looking into.

Connect Google on the Keywords tab and compare against Search Console, which counts impressions and clicks at Google rather than hits on your server — a different measurement of a different thing, and a good cross-check precisely because it does not share our failure modes.

How long data is kept

Each site has a retention window, shown in Settings. Windows longer than it cannot be selected, and a custom range reaching further back is clamped to it rather than quietly returning less than you asked for.

Exports and the API respect the same window and the same filters as the screen you are looking at.