How visitors are counted
Every number on every screen rests on one definition. This page is that definition.
The visitor id
Section titled “The visitor id”When a hit arrives, the collector computes:
sha256( UTC-day | rotating-salt | client-IP | user-agent | site-public-key )and keeps the first 16 bytes, hex-encoded — a 32-character string. That string is written to the event and the session. The IP address is never stored.
Four consequences follow directly from the inputs:
| Input | Consequence |
|---|---|
| UTC day | The id changes at midnight UTC. The same person tomorrow is a different visitor. |
| Rotating salt | Even with the same day, IP and user agent, yesterday’s hash cannot be recomputed. |
| Client IP | A person on Wi-Fi and then on mobile data is two visitors. A shared office NAT can make many people one visitor. |
| User agent | A browser update, or switching from Safari to Chrome, produces a new visitor. |
| Site key | The same person on two of your sites is two unrelated ids. |
What “unique visitors” means
Section titled “What “unique visitors” means”Unique visitors on any screen is count(distinct visitor_id) over the
events in the current slice. Read it as distinct browser-days, and it is
accurate. Read it as people, and it drifts:
- Over- counts anyone who changed network or browser mid-period.
- Over- counts one person across two days as two.
- Under- counts several people behind one office NAT with the same browser.
Over a single day, it is a close approximation of distinct devices. Over thirty days, it is much nearer to “browser-days” than to “people” — a visitor who comes back every day for a month contributes thirty.
Visits (sessions)
Section titled “Visits (sessions)”A visit is a run of activity by one visitor with no gap longer than 30 minutes. When a hit arrives, the collector looks for a session for the same site and visitor whose last activity was inside 30 minutes; if it finds one it extends it, otherwise it opens a new one.
A visit carries a rollup:
| Field | How it moves |
|---|---|
pageviews |
+1 per pageview hit |
events |
+1 per hit of any type |
duration_ms |
+= the d on each hit, and each flushed duration |
entry_path |
the path of the first hit, never changed |
exit_path |
rewritten on every hit |
is_bounce |
true while pageviews <= 1 |
revenue_cents |
+= the amount of each revenue event in the site currency |
Because the visitor id rotates at midnight UTC, a visit that starts at 23:50 and continues at 00:10 becomes two visits by two visitors. Everything else — bounce rate, time on page — is computed per visit and is unaffected.
Bounce rate
Section titled “Bounce rate”bounce rate = visits with pageviews <= 1 / visitsCustom events, outbound clicks and revenue events do not clear the bounce flag. A one-page visit where somebody signed up is still a one-page visit. If what you want is “visits that did nothing”, filter Sessions with Bounced and not Converted.
When a filter is applied, bounce rate is computed over the sessions the filtered events belong to — which is what makes “bounce rate for /pricing” mean “visits that touched /pricing”, not “visits whose only page was /pricing”.
Time on page and average visit
Section titled “Time on page and average visit”Two numbers, from the same source.
Time on page is attached to a pageview. It arrives either as the gap
measured when the next pageview is sent, or as a duration hit flushed when
the tab is hidden. A duration hit is bookkeeping, not an event: the collector
adds the milliseconds to the pageview they belong to and to the open session,
and never writes a row.
Average visit is sum(session.duration_ms) / visits.
Neither can see time after the last signal. A visitor who reads one page for
ten minutes and closes the tab contributes ten minutes only if the
visibility flush arrived — which it does in every current browser, but not if
the device was killed, the tab crashed, or sendBeacon was blocked by CSP.
A flushed duration is clamped to 0–30 minutes, because a longer gap is a new visit by definition.
Views per visit
Section titled “Views per visit”views per visit = pageviews / visitsCounted over the filtered slice, so it answers “how many pages did the visits that touched this filter see in total”, not “how many of these pages”.
Revenue per visitor
Section titled “Revenue per visitor”On the Revenue screen:
Per visitor = revenue / unique visitors in rangeCustomers = distinct visitor ids that reported an amount in rangePer visitor uses the same filtered visitor count the rest of the screen shows, so a country filter narrows numerator and denominator together. A customer is a visitor id, which in the default mode is a browser-day: the same person buying on two days is two customers.
Where the daily id shows on each screen
Section titled “Where the daily id shows on each screen”| Screen | Effect |
|---|---|
| Overview | Visitors over a long range are browser-days. A 30-day total is not 30-day uniques. |
| Sessions | “Returning” means earlier the same day. The visitor profile only ever shows today’s visits. |
| Journeys | A flow is drawn inside visits, so it is unaffected. |
| Funnels | Steps must happen on the same UTC day. The “Same day” window is the widest one offered, and it is honest. |
| Retention | Visitor-mode retention is near zero past D0 by construction. Use identified mode. |
| Revenue | Customers are visitor ids, so over a long range they are paying browser-days. A revenue event is credited to the visit it fired in, never to an earlier day. |