Skip to main content

Live

Live series

The last N minutes in minute buckets — what a live chart is drawn from.

GET/sites/{siteId}/realtime/series
Live series
curl --request GET \
  --url 'https://truestat.io/api/v1/sites/{siteId}/realtime/series' \
  --header 'Authorization: Bearer <token>'
{
  "data": [
    {
      "goals": 0,
      "views": 2,
      "minute": "2026-09-16 14:01:00",
      "bounces": 0,
      "indexing": 3,
      "sessions": 1,
      "training": 5,
      "visitors": 1,
      "answering": 0,
      "ai_referrals": 0,
      "new_visitors": 1,
      "crawler_views": 8,
      "revenue_cents": 0,
      "returning_visitors": 0,
      "avg_session_seconds": 34
    }
  ],
  "meta": {
    "minutes": 30,
    "site_id": "6fed8980-a119-4a9c-a4d4-53e448ef9f9e"
  }
}

Minute-by-minute activity for the recent past, humans and crawlers on the same rows.

Takes minutes rather than a window — see online now. Thirty by default, which is what the dashboard's live chart draws.

Quiet minutes have no row

This is the part that catches people out.

The query groups by minute, so a minute in which nothing happened is absent rather than returned as zeroes. Asking for 30 minutes on a quiet site returns however many minutes saw activity — nine, say — and they are not evenly spaced.

Plot those rows straight onto a chart and you get a lie: the quiet stretches compress to nothing and the traffic looks steadier than it was. Fill the gaps before drawing, with whatever your chart should show — a zero, a break in the line, an interpolation.

We do not fill them here on purpose. Doing so would mean returning rows the query never produced, and how a gap should be drawn is a decision for the chart rather than the transport.

There is no unit

Buckets are always one minute. A live chart that buckets by hour is not a live chart, and timeseries already buckets by anything larger.

It also needs no timezone handling, which /timeseries does: a minute starts at the same instant in every zone, so there is no boundary to get wrong.

Both sides, one timeline

The human fields exclude crawlers. crawler_views counts them and splits three ways — answering, indexing, training — for the same reason crawler series does: a fetch answering somebody now and a fetch harvesting pages for training are different events.

They share these rows because a live view draws both on one timeline.

ai_referrals sits among the crawler fields but counts people — those who arrived from an assistant's answer. It belongs with the human figures despite its neighbours.

What you can build with it

Everything the dashboard's live view shows: the visitor line, the new-versus- returning split, sessions and bounce, goals and revenue as they land, and the crawler layers underneath. It is one query per refresh rather than one per series.

Authorizations

Authorizationstringheaderrequired

An API key from Settings → API keys. Scopes available: analytics:read, sites:read, sites:write, settings:read, settings:write, goals:read, goals:write, funnels:read, funnels:write, notes:read, notes:write, alerts:read, alerts:write, team:read, team:write, revenue:read, revenue:write.

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Path parameters

siteIdstring (uuid)pathrequired
The site's id, from `GET /sites`. A site that is not yours and a site that does not exist both answer 403, so this cannot be used to discover other people's ids.

Query parameters

minutesintegerquery
How far back to look, in minutes. A visitor counts as present if they did something within it. Refused above 360 rather than clamped — past that the question is no longer 'who is here' and `/timeseries` answers it better.

Response

application/json

The answer.

dataunknown
See the example.
metaobject