> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wendung.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Pageviews and sessions

> What a pageview carries, how pageviews become sessions, how path normalization works, and what is never collected.

A pageview is an event named `$pageview` that the SDK records on every page load and, in single-page apps, on every client-side navigation. Automatic pageviews are off by default. `trackPageviews: true` enables full pageviews with granted consent. `trackPageviews: 'auto'` also enables aggregate pageviews while consent is pending. Pageviews use the SDK's queue and batching, but they are metered separately and feed the web analytics pages only. They do not appear in funnels, user journeys, or the Users page.

## What a pageview carries

With granted consent, the SDK sends the full page URL, the page title, the referrer, and the screen size. The ingest endpoint adds request-level context and splits the URL before storing it.

| Field | Where it comes from | Notes |
| - | - | - |
| Hostname | Page URL | Must match a registered site to appear in site reports. |
| Path | Page URL | Stored raw and as a normalized path (see below). |
| Query parameters | Page URL | Dropped unless the parameter is on the site's allowlist. `utm_*` parameters are always captured, as campaign fields. |
| Page title | `document.title` | |
| Referrer | `document.referrer` on the first pageview, the previous page URL on later ones | Also stored as referrer domain and channel type (direct, search, social, email, referral, internal). |
| Browser, OS, device type | `User-Agent` header | |
| Country, city | Request metadata at the edge | Coarse. The IP address itself is not stored. |
| Screen width and height | `window.screen` | |
| Anonymous ID | Generated by the SDK | A random ID kept in the visitor's browser storage so repeat visits count as one visitor. |
| Session ID | Generated by the SDK | See [sessions](#sessions). |

Requests whose `User-Agent` identifies a bot are stored with a bot flag and excluded from every report.

## Aggregate pageviews

With `trackPageviews: 'auto'` and pending consent, the SDK sends the page origin and pathname, an origin-only referrer, timestamps, and SDK version. It excludes query parameters, fragments, titles, screen dimensions, and visitor or session identifiers. Event and batch IDs deduplicate delivery; they do not identify visitors.

The SDK does not read or write browser storage in this state. Requests omit credentials and suppress the transport referrer. Ingest retains country and parsed browser, OS, and device type, but removes city and the full user-agent value from the queued analytics data. It creates no IP-based visitor identifier.

Aggregate pageviews contribute to pageview totals and breakdowns. They cannot count unique visitors, sessions, or repeat visitors. They also carry no campaign tags, even if the site's query parameter allowlist includes those fields.

Pathnames can still contain personal information. Query stripping does not remove names or record identifiers embedded in a path, and dashboard path normalization happens after transmission. Review the routes you track. The collection mode does not establish a consent exemption. See [consent setup and transitions](/guides/consent).

## Sessions

Visitor and session metrics cover consented traffic only. Aggregate pageviews do not enter these calculations.

There is one session ID per browser tab, kept in `sessionStorage`. A session ends after 30 minutes without activity or 24 hours after it started, whichever comes first. The pageviews that share a session ID are folded into one session row:

* **Entry page** and **exit page** are the first and last pageview in the session.
* **Session duration** is the time between the first and the last pageview. A session with one pageview has a duration of zero.
* **Bounce** means the session had exactly one pageview.
* **Views per session** is the consented pageview count divided by the session count over the selected range.

Unique visitors count distinct anonymous IDs in the range, so a visitor with three sessions on three days is one visitor and three sessions.

Session rows are rebuilt once an hour from the events received in the last 48 hours. Visitors and pageviews update as soon as an event lands; bounce rate, session duration, views per session, and entry and exit pages can trail them by up to an hour.

## Campaign parameters

For full pageviews, the ingest endpoint reads campaign tags from the page URL. Aggregate pageviews omit all query parameters and cannot carry these tags. Put the standard parameters on the links you share:

```
https://example.com/pricing?utm_source=newsletter&utm_medium=email&utm_campaign=spring_launch
```

| Parameter | Typical value | Where it shows |
| - | - | - |
| `utm_source` | `newsletter`, `google`, `producthunt` | Sources → Campaigns, UTM source tab |
| `utm_medium` | `email`, `cpc`, `social` | Sources → Campaigns, UTM medium tab |
| `utm_campaign` | `spring_launch` | Sources → Campaigns, Campaign tab |
| `utm_term`, `utm_content` | keyword, variant | Stored on the pageview; not broken down in the panels |

For full pageviews, these five are captured whether or not they are on the site's query parameter allowlist. A session takes its campaign fields from its first pageview, so a visitor who lands on a tagged link and then browses untagged pages counts once for that campaign. All five are filters on the site page.

## Path normalization

Paths with IDs in them fragment your reports: `/users/123` and `/users/456` are the same page to a human but two rows in a table. Both the raw path and a normalized path are stored, and the reports use the normalized one.

Two built-in rules run on every path segment:

| Segment looks like | Becomes |
| - | - |
| Digits only, or a 24-character hex string | `:id` |
| A UUID | `:uuid` |

You can add up to 20 custom rules per site. Each rule is a pattern and a replacement, tested against one path segment at a time. Rules run in order, the first matching rule wins, and a segment that matched a custom rule skips the built-in rules.

| Path | Rule | Normalized path |
| - | - | - |
| `/orders/8f2a1c/receipt` | `^[a-z0-9]{6}$` → `:order` | `/orders/:order/receipt` |
| `/docs/getting-started` | `^getting-started$` → `intro` | `/docs/intro` |
| `/users/123/settings` | none needed | `/users/:id/settings` |

Rules apply to pageviews collected after you save them. Existing data keeps the path it was stored with.

## What is not collected

* No cookies. The anonymous ID lives in the visitor's browser storage and is not readable by other sites. Browser storage still counts as storing information on the visitor's device, so where consent is required, start the SDK with `consent: 'pending'`. See the [consent guide](/guides/consent).
* No IP addresses in any stored row. The edge uses the IP to derive country and city and then discards it.
* Aggregate pageviews send no query parameters. Full pageviews send the URL to ingest, which retains only allowlisted parameters and `utm_*` fields. Those fields and pathnames can still contain personal information.
* Nothing from bots, which are filtered before reporting.

The [privacy policy](https://wendung.app/privacy) lists the same fields for your own privacy notice.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.