# What the tracker sends (request payload)

> The exact POST request the tracker sends to /api/event, every field in its JSON payload, and what is never sent: no cookies, identifiers or fingerprints.

Every hit is one `POST` to `{origin}/api/event`:

- `Content-Type: text/plain`, so browsers don't send a CORS preflight,
- `credentials: 'omit'`: no cookies are sent or accepted,
- `keepalive: true`, so hits survive page navigation. `navigator.sendBeacon`
  is the fallback when `fetch` throws.

The server answers **202 Accepted** with an empty body, whether or not the
hit is later kept, so the response never tells a script anything about
your settings.

## Retries

If the server answers with an error (any `4xx` or `5xx` status, including
`429` when a rate limit is hit), the tracker sends the same hit again:

- up to 5 more times, after 1 second, 10 seconds, then 60 seconds for
  each of the last three,
- oldest hit first, one at a time,
- from a queue of at most 20 hits that lives in memory only. Nothing is
  written to the device, so hits still waiting are lost when the page is
  closed or reloaded.

A request that never gets an answer (the visitor is offline, or a content
blocker stops it) isn't retried.

A retried hit is recorded with the time it arrives, which can be a few
minutes after it happened. In rare cases the server has already recorded
a hit before the error reaches the browser, and the retry counts it a
second time.

## Body

```json
{
  "s": "pa_7Q2K9XH3AB",
  "t": "pageview",
  "u": "https://example.com/pricing?utm_source=newsletter",
  "r": "https://www.google.com/",
  "l": "en-US",
  "w": 1440,
  "i": 0,
  "p": { "plan": "pro" }
}
```

| Key | Long name | Sent with | Meaning |
|---|---|---|---|
| `s` | `site` | all | Site id |
| `t` | `type` | all | `pageview`, `event`, `engagement`, `vital` or `click` |
| `u` | `url` | all | Page URL after exclusions, masks and query parameter stripping |
| `r` | `referrer` | when present | `document.referrer`, or a URL on your own site for SPA navigations |
| `l` | `language` | all | `navigator.language` |
| `w` | `screen_width` | all | `screen.width` in CSS pixels (stored as a size bucket) |
| `i` | `interacted` | all | `1` once a real input was seen on the page, `0` before. See [Interaction flag](#interaction-flag) |
| `n` | `name` | event, vital | Event name, or the Web Vital (`LCP`, `INP`, `CLS`, `FCP`, `TTFB`) |
| `p` | `props` | pageview, event | Properties |
| `e` | `engaged_ms` | engagement | Visible time on the page in milliseconds |
| `sd` | `scroll_depth` | engagement | Maximum scroll depth, 0 to 100 |
| `v` | `value` | vital | The Web Vital value |
| `c` | `selector` | click | Short CSS selector of the clicked element |
| `h` | `hash_mode` | when on | `1` if the fragment is part of the path |
| `d` | `dnt` | when on | `1` if Do Not Track is on |
| `g` | `gpc` | when on | `1` if Global Privacy Control is on |

The server also accepts `rv`/`revenue` and `cu`/`currency` at the top
level, but the tracker puts them in `p`.

Anything larger than 32 KB is ignored.

## Interaction flag

Some bots run a real browser, load a page and leave without touching it.
To tell them from people, every hit says whether the tracker has seen a
real input on the page:

- `i` is `0` until the first pointer press or move, key press, touch or
  wheel turn, and `1` from then on.
- At that first input the tracker sends one `engagement` hit straight
  away, so the visit is marked even if the hit sent when the page closes
  is lost.
- Scrolling alone doesn't count, and neither does input a script
  generates. Both are things a bot can do without a person.

It is a yes or no. Nothing about the input is sent: not what it was, not
where the pointer was, not which key, not when. Visits are then reported
as input seen, none or unknown, see
[Visits with no input seen](/docs/server-side/bots#visits-with-no-input-seen).

## What isn't sent

No cookies, no stored identifiers, no user id, no screen height or color
depth, no installed fonts or plugins, no canvas or audio fingerprints, no
timezone, no mouse movement, no form contents.

The server receives the IP address and User-Agent because every HTTP
request carries them. They're used in memory and dropped. See
[How it works](/docs/privacy).
