Skip to main content

Analytics

Engagement over time

Bounce rate and session length in buckets.

GET/sites/{siteId}/engagement
Engagement over time
curl --request GET \
  --url 'https://truestat.io/api/v1/sites/{siteId}/engagement' \
  --header 'Authorization: Bearer <token>'
{
  "data": [
    {
      "bucket": "2026-09-09 00:00:00",
      "sessions": 13,
      "bounce_rate": 53.8,
      "median_session_seconds": 69
    }
  ],
  "meta": {
    "range": {
      "to": "2026-09-16T00:00:00.000Z",
      "tz": "UTC",
      "from": "2026-09-09T00:00:00.000Z",
      "clamped": false
    },
    "site_id": "6fed8980-a119-4a9c-a4d4-53e448ef9f9e"
  }
}

How engaged visitors were, bucket by bucket.

Why this is not part of /timeseries

Timeseries scans events grouped by bucket. A bounce rate needs to know how many pages each session saw before anything can be grouped by time, and a session length needs the session's own boundaries. Neither is available in that scan.

Computing it from events anyway was tried, and the failure is worth knowing about if you are tempted to do the same with the raw endpoints: grouping events by session and taking last minus first gives a duration that spans whatever the session spans, so a visit crossing midnight reads as a day long. Measured against live data, that produced a median of four days for a bucket whose real answer was ninety seconds.

The session figure is a median

median_session_seconds, not an average, and the name says so.

Session length is heavily skewed. One tab left open overnight drags a mean into the hours, which is why analytics tools that report a mean session time report a number no real visit resembles. The median describes the middle visit, which is the one you can act on.

Sessions under five seconds are excluded — the same rule overview uses. That matters: its tile and this line have to agree, and a tile reading 3m 26s above a chart sitting at twelve hours is one of them wrong with no way for the reader to tell which.

Filters do not apply

The query reads sessions; filter_* describes event properties. The parameters are accepted and ignored rather than applied to the wrong table.

tz still resolves the window, but the buckets inside it are cut at UTC boundaries. For a daily chart on a site with a strongly local audience, that shifts where each day's edge falls.

bounce_rate is a percentage, 0–100 — the same scale as channel quality.

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

unitenum<string>query
Bucket size. Defaults to one chosen for the window.
options:minutehourdayweekmonth
periodenum<string>query
A named window, resolved in `tz`. Cannot be combined with `from`/`to` — a request carrying both is refused rather than guessed at.
options:todayyesterdaylast24hlast7dlast30dlast12mmonthyearall
fromstring (date-time)query
Start of the window, ISO 8601 with an offset. Must be given together with `to`.
tostring (date-time)query
End of the window. Must be given together with `from`.
tzstringquerydefault: UTC
IANA timezone for day boundaries. `period=today&tz=Europe/Istanbul` means the reader's today, not the server's. Defaults to UTC.
botsenum<string>querydefault: excluded
Whether crawler traffic is counted. Excluded by default — the `/ai/*` endpoints report it separately and always include it.
options:excludedincluded

Response

application/json

The answer.

dataunknown
See the example.
metaobject