# Page View (https://webmetic.de/docs/en/api/datenmodell/page-view)

A page view is one page of your website that a visit loaded. For example, someone from Bergquell Mineralbrunnen reaches your pricing page from LinkedIn and then opens two more pages. The session then has three page views.

Page views have no ID of their own and sit in the `user_data` list of their [session](https://webmetic.de/docs/en/api/datenmodell/session), in the order they were recorded.

## Counting rules [#counting-rules]

The tracking code reports a page view every time a page loads. These rules apply:

- **Reload**: When someone loads the same URL again, no new page view is created.
- **Back to a page**: Webmetic only merges identical URLs that follow each other directly. The sequence A, B, A gives three page views.
- **Single-page apps**: Every URL change through the browser's History API counts as a page view. If only the part after `#` changes, that doesn't count as a page view.

## Measured values [#measured-values]

- **`timestamp`**: The moment the Webmetic server received the page view, not the browser's clock. The API returns it in UTC without a suffix, webhooks with `Z`. For details, see [Date ranges and time zones](https://webmetic.de/docs/en/api/zeitraeume-und-zeitzonen).
- **`scroll_depth`**: The deepest mark the visit passed on the page: 0, 25, 50, 75, or 90. Webmetic has no finer steps and no value of 100. Every page view starts at 0.
- **`time_spent`**: The seconds until the next page view in the same session. On the last page, Webmetic counts until the last interaction, for example a download. If there was no interaction, Webmetic takes the active time from `engagement_time`. If `engagement_time` is missing too, Webmetic uses an estimate of a few seconds. Scrolling doesn't count as an interaction.
- **`engagement_time`**: The active time in seconds, measured in the browser. Active means the tab is visible and there was mouse, keyboard, scroll, or touch activity in the last 60 seconds. The browser sends the value when someone leaves the page, switches tabs, or moves to the next view in a single-page app.
- **`document_location`** and **`document_title`**: Webmetic stores the URL and title in full and shortens nothing. The URL includes the query string and the `#` part.

Recommended: use `engagement_time` as the duration of a page, because it measures active time. The dashboard uses it too and only falls back to `time_spent` when it's missing.

## Fields [#fields]

| Field | Type | Example | Description |
| --- | --- | --- | --- |
| `session_id` | `string` | `"01M4WQFX6YM2X5V8T4N6R1C0DZ"` | The session of the page view, 26 characters. Only in `/session_user_data`. |
| `timestamp` | `string` | `"2026-10-14T08:12:05.214000"` | When the server received the page view, ISO 8601 in UTC. |
| `document_location` | `string` | `"https://your-website.com/pricing?utm_source=linkedin&utm_medium=social&utm_campaign=messe-2026"` | The full URL of the page. |
| `document_title` | `string` | `"Pricing"` | The page title at load time, `""` if the page has none. |
| `scroll_depth` | `integer` | `75` | The deepest mark reached: 0, 25, 50, 75, or 90. |
| `referrer` | `string` | `"https://www.linkedin.com/"` | Where the visit came from according to the browser, empty for direct visits. |
| `time_spent` | `number` | `95.0` | Seconds on the page. Estimated when Webmetic couldn't measure the time. |
| `engagement_time` | `integer` | `70` | Seconds of active time in the browser. |
| `user_events_count` | `integer` | `2` | The number of all interactions on the page. |
| `events` | `array` | see below | The recognized interactions. Missing when there were none. |
| `blurred` | `boolean` | `true` | Only on the Free plan for hidden companies. |

## Events [#events]

The `events` list holds the interactions Webmetic recognized on the page. Every event has `type` and `target`, plus `detail` and `meta`, which can also be `null` or missing.

| `type` | Trigger | `target` | `detail` | `meta` |
| --- | --- | --- | --- | --- |
| `form_start` | First focus on a form field | Form ID: `id`, else `name`, else a generated ID | `null` | `fieldCount`: visible fields |
| `form_submit` | A form is submitted | Form ID | The form's target URL without the query string | `fieldCount`, `fieldsInteracted`, `timeSpent` in seconds from the first field |
| `form_abandon` | A form was started but not submitted when the page was left | Form ID | `null` | `fieldsInteracted`, `timeSpent` |
| `download` | Click on a link to a file or with a `download` attribute | File name | The full URL of the link | `fileType`: file extension |
| `outbound_click` | Click on a link to another host name | Host name of the target | The full URL of the link | `linkText` or `null` |
| `contact_click` | Click on a `mailto:` or `tel:` link | `email` or `phone` | Path of the page | `null` |
| `site_search` | Search term in the URL or a search form is submitted | The search term as typed | `url_param` or `form_submit` | `param`: name of the URL parameter, else `null` |
| `video_start` | First start of a video | `html5`, `youtube`, or `vimeo` | URL of the video | `label` or `null` |
| `video_progress` | A video reaches 25, 50, 75, or 90% | as for `video_start` | URL of the video | `percent`, `label` |
| `print` | The page is printed | Page title at print time | `null` | `count`: how often printed, `scrollDepth`: scroll depth in percent |

A search term in the URL is read from the parameters `q`, `s`, `search`, `query`, `keyword`, `term`, and `suche`.

The API returns no form input, with one exception: for `site_search`, `target` holds the full search term. For `contact_click`, the email address and phone number are not included.

The tracking code only recognizes YouTube videos when the embed contains `enablejsapi=1`. Muted HTML5 videos that start on autoplay don't count.

You can't send your own events. `user_events_count`, however, also counts interactions without their own type, for example audio. That's why it can be higher than the number of entries in `events`.

## Session and company [#session-and-company]

A page view has no `company_id`. Use its `session_id` to find its session in `/session`, which carries the `company_id`.

Webmetic reads UTM values and click IDs from the URL of the first page view and stores them on the session.

## Example [#example]

The example shows the first page view of the session from `/session_user_data`. In `/company-sessions` there is no `session_id`, because the page view already sits inside its session.

```json title="GET /session_user_data"
{
  "session_id": "01M4WQFX6YM2X5V8T4N6R1C0DZ",
  "timestamp": "2026-10-14T08:12:05.214000",
  "document_location": "https://your-website.com/pricing?utm_source=linkedin&utm_medium=social&utm_campaign=messe-2026",
  "document_title": "Pricing",
  "scroll_depth": 75,
  "referrer": "https://www.linkedin.com/",
  "time_spent": 95.0,
  "engagement_time": 70,
  "user_events_count": 2,
  "events": [
    {
      "type": "download",
      "target": "price-list.pdf",
      "detail": "https://your-website.com/media/price-list.pdf",
      "meta": { "fileType": "pdf" }
    },
    {
      "type": "form_start",
      "target": "quote-request",
      "detail": null,
      "meta": { "fieldCount": 6 }
    }
  ]
}
```

## Edge cases [#edge-cases]

- **Missing or `null`**: In `/session_user_data` and `/company-sessions`, a field is missing when Webmetic stored nothing for it. In the feeds and in webhooks, every field is present, `null` when it has no value.
- **Empty text**: `document_title`, `referrer`, and an event's `detail` and `meta` can be `""`, `null`, or missing. Treat all three cases the same.
- **Short pages**: If a page is less than 50 pixels taller than the window, `scroll_depth` stays at 0. The visit still saw the whole page.
- **No active time**: `engagement_time` is missing when the browser could no longer send the value, for example after it was closed.
- **Referrer in single-page apps**: Every page view carries the referrer of the first load, not the previous page.
- **Date range**: `from_date` and `to_date` filter by the start of the session. That's why `/session_user_data` returns every page view of such a session, including later ones.
- **Order**: The order of entries in `/session_user_data` is not fixed. Sort by `timestamp` yourself. For details, see [Pagination](https://webmetic.de/docs/en/api/paginierung).
- **Free plan**: For a hidden company, an entry in `/session_user_data` only contains `session_id`, `timestamp`, and `blurred: true`. In `/company-sessions` there is no `user_data`, and in the feeds the list is empty. For details, see [Plans](https://webmetic.de/docs/en/konto/plaene).
- **Opt-out**: The API does not return page views after an opt-out.

## Used by [#used-by]

- **Endpoints**: [`GET /session_user_data`](https://webmetic.de/docs/en/api/referenz/visitor-intelligence/session-user-data) returns one entry per page view, and `total` in `pagination` counts page views there. [`GET /company-sessions`](https://webmetic.de/docs/en/api/referenz/visitor-intelligence/company-sessions) returns the page views in `result[].sessions[].user_data[]`.
- **Visit types**: [`GET /intensive-visits`](https://webmetic.de/docs/en/api/referenz/visitor-intelligence/intensive-visits), [`GET /returning-visits`](https://webmetic.de/docs/en/api/referenz/visitor-intelligence/returning-visits), and [`GET /new-visits`](https://webmetic.de/docs/en/api/referenz/visitor-intelligence/new-visits) also return the page views in `result[].sessions[].user_data[]`. For details, see [Visit types](https://webmetic.de/docs/en/api/datenmodell/besuchsarten).
- **Webhooks**: All four events carry the page views in `data.visit.user_data`. If the body gets too large, Webmetic drops the oldest page views first and sets `data.truncated` to `true`. For details, see [Webhooks](https://webmetic.de/docs/en/api/webhooks).
- **AI assistant**: The [AI assistant](https://webmetic.de/docs/en/ki-assistent/tools-und-prompts) also retrieves page views. The tool `get_company_activity` shows the page views of a visit as text.
