# Live

Clicktag Live shows hits the moment the tracking script sends them, as a stream for one website or as a world map for every website you own, so you can check an install and watch visitors arrive without waiting for reports.

## Open the stream

Open a website and choose the **Live** tab. The stream starts with the last 5 minutes of hits, newest on top, then adds each new hit as it arrives, usually within a second.

Each row shows the time, the hit type (pageview, event, append or error), the page or event name, the device, browser and country, a short visitor id, and an **Entry** label when the pageview came from outside the site. Click a row to see the query string, referrer, operating system, event metadata and the city-level location.

Live needs a signed-in session: open it from the dashboard while you are logged in. API keys cannot open it.

## Check your own install

Open your website in another tab and turn on **Only my traffic**. The stream then keeps only the hits sent from the browser you are using, matched on your network address and browser. The 5 minutes of history loaded when the page opens are never marked as yours.

If nothing arrives, follow the [quickstart](https://clicktag.io/docs) to check the script tag.

## Pause, filter and search

**Pause** freezes the list so you can read it. New hits wait behind a **new** button that resumes the stream and jumps back to the top. The type menu and the search box filter what is on screen by path, event, referrer, visitor, country or event metadata without changing what arrives. The counter shows hits per minute.

## Workspace map

Choose **Live** in the sidebar, below **All websites**, to watch every website at once. Each hit with a location becomes a pulse in its website's colour and fades after 30 seconds. The globe turns slowly while nothing happens; drag it or use the arrow keys to look around. Small screens, reduced motion and browsers without WebGL get a flat map with the same pulses. Next to the map, **Latest hits** lists the newest 100 hits across all websites.

## What is kept

Nothing new. The stream and the map are not stored anywhere: they show hits your reports already count, and they disappear when you close the page. Locations are city-level estimates from the network edge, not GPS. Only the owner of a website can open its stream or see it on the map, and shared dashboards have no Live tab. Reports keep working exactly as before.

## Limits

- Live stays open in up to eight tabs per account. Opening a ninth disconnects the oldest, which shows a **Reconnect** button.
- The stream keeps the newest 500 hits on screen.
- A tab hidden for more than a minute disconnects, then catches up when you come back.

## API

The Live tab runs on three routes. Tickets and history take the owner's Firebase ID token only; a [management key](/docs/authentication#management-keys) gets `401 sign in required`.

- `POST /api/live/ticket` with `{ "site": "<hostname>" }`, or without `site` for every verified website you own, returns `{ ticket, expires_in, url }`. A ticket opens one stream and expires after 60 seconds, and an account can hold 32 unused tickets before `429 too many live tickets`. A site you do not own returns `404 unknown site`, an unverified one `403`.
- `GET /api/live/ws?ticket=<ticket>` is the WebSocket: connect to `wss://clicktag.io` followed by the returned `url`. The ticket is the only credential. A request that is not a WebSocket upgrade gets `426`, a malformed ticket `400`, and an unknown, expired or used ticket `403`.
- `GET /api/live/recent?site&since&limit` returns `{ since, until, hits }`: stored hits newer than `since`, newest first. `since` is unix milliseconds, 5 minutes ago by default and never more than 15 minutes back. `limit` defaults to 200 with `site` and 100 without, up to 500.

The socket sends JSON text messages:

- `{"t":"hello","scope":"site","site":"your-domain.example","since":1789520400000,"sockets":1}` once. `scope` is `all` with `site: null` for every website, and `sockets` counts the open streams on your account, this one included.
- `{"t":"hits","hits":[...],"dropped":0}` as hits arrive. The first hit goes out at once and anything in the next 50 ms follows together. When more than 200 hits wait, the oldest are skipped and `dropped` on the first message counts the ones this socket would have received; that message can have empty `hits`.
- `{"t":"bye","reason":"too_many_tabs"}` just before the server closes the oldest stream with code `4001`, when a ninth one opens.

Send `ping` to get `pong`; a message over 1024 bytes closes the socket with code `1009`. Each hit has `site`, `ts` (unix milliseconds), `type`, `id`, `orig`, `path`, `query`, `ref`, `event`, `meta`, `error`, `dur` and `scroll` (appends only, otherwise `null`), `country`, `device`, `browser`, `os`, `unique` (`1` for an entry), `visitor` (the first 8 characters of the daily visitor hash) and `me`. Hits on the socket also carry `loc` (`lat`, `lng`, `city`, `region`) when a location is known; hits from `recent` have `me: false` and no `loc`.

A data center that finds nobody watching a website stops sending its hits for 30 seconds, so the first half minute after you connect can miss a few. The dashboard asks `recent` again 35 seconds after `hello` to fill that gap. The full schemas are in the [OpenAPI file](/openapi.json).
