Analytics
Channel quality
How each traffic source behaves once it arrives — not how much it sends.
curl --request GET \
--url 'https://truestat.io/api/v1/sites/{siteId}/channels' \
--header 'Authorization: Bearer <token>'{
"data": [
{
"channel": "Organic Search",
"sessions": 237,
"visitors": 205,
"bounce_rate": 81,
"return_rate": 13.5,
"avg_session_seconds": 44,
"avg_pages_per_session": 1.39
}
],
"meta": {
"page": {
"limit": 100,
"offset": 0,
"has_more": false
},
"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"
}
}What people from each source actually did: how long they stayed, how many pages they read, how many bounced, how many came back.
Volume is the less useful half
Breakdowns by channel
How much each source sent. Useful for "where does my traffic come from".
Channel quality
What they did after arriving. Useful for "which source is worth more effort".
A channel sending four hundred visitors who all leave immediately is worth less than one sending forty who read three pages each. A volume ranking puts those two in exactly the wrong order, which is why this report exists and why it is the one almost no analytics tool publishes.
Filters do not apply here
The shared filter_* parameters are accepted and ignored, deliberately.
The report's whole job is to compare channels. Narrow it to one and you
have a single row with nothing to compare against — a chart with one bar. When
you want a filtered view of one channel, use
breakdowns with dimension=channel.
Direct is a real row
Traffic with no referrer is labelled Direct rather than left blank. It is a
mixture: a bookmark, a typed address, a link opened from an app, a referrer
the browser stripped for privacy.
None of that is an error, so it gets a name. A blank label reads as a bug in your own code.
Rates are percentages
bounce_rate and return_rate are 0–100, not fractions. That is different
from ctr on the search endpoints, which is a
fraction because Google reports it that way.
The two are deliberately not made to match: silently rescaling one of them by a hundred is a bug waiting to land in somebody's chart. Read each field as the reference describes it.
What the numbers say together
{ "channel": "Organic Search", "visitors": 205, "sessions": 237,
"bounce_rate": 81, "return_rate": 13.5,
"avg_pages_per_session": 1.39, "avg_session_seconds": 44 }A high bounce rate with a short session is a mismatch between what the page promised and what it delivered. The same bounce rate with a long session usually is not — people found their answer on one page and left satisfied, which is a normal shape for documentation and tools.
Authorizations
AuthorizationstringheaderrequiredAn 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)pathrequiredQuery parameters
periodenum<string>querytodayyesterdaylast24hlast7dlast30dlast12mmonthyearallfromstring (date-time)querytostring (date-time)querytzstringquerydefault: UTCbotsenum<string>querydefault: excludedexcludedincludedlimitintegerquerydefault: 100offsetintegerquerydefault: 0Response
The answer.
dataunknownmetaobjecterrorobjecterrorobjecterrorobjecterrorobject