AI
Traffic split
Every operator's share of your traffic, with people counted as one of them.
curl --request GET \
--url 'https://truestat.io/api/v1/sites/{siteId}/ai/split' \
--header 'Authorization: Bearer <token>'{
"data": [
{
"views": 3143,
"operator": "bytedance"
},
{
"views": 752,
"operator": "gpt"
},
{
"views": 518,
"operator": "human"
}
],
"meta": {
"range": {
"to": "2026-09-16T13:40:00.000Z",
"tz": "UTC",
"from": "2026-09-09T13:40:00.000Z",
"clamped": false
},
"site_id": "6fed8980-a119-4a9c-a4d4-53e448ef9f9e"
}
}How your traffic divides between the machines and the people — as one list,
with human among the rows.
human is a row, and that is the point
The response looks odd at first: bytedance, gpt, claude, and then
human sitting in the same list.
It is there because of the question this endpoint answers. "How much of what reached my site was a person" is a ratio, and a ratio needs both sides in the same response. Return only the crawlers and every percentage a caller computes is a crawler's share of the crawlers — a number that looks like an answer and is not.
That is not hypothetical. This report was once built on a query that filtered to crawler traffic, and the dashboard card showed each bot's share of the bots while presenting it as a share of the traffic. The human side was not small; it was absent.
Every operator comes back
limit and offset are ignored here. Everywhere else in the API a page cut
short is a shorter answer, and meta.page.has_more tells you to ask again.
In a ratio it is worse than that: a row dropped from the bottom does not
shorten the result, it silently changes every percentage above it. So the list
is complete and there is no meta.page on this endpoint.
There is no purpose here
Rows group by operator alone. That is what lets human sit among them — a
person has no crawl purpose, and inventing one for them would be the sort of
tidy schema that stops describing reality.
For the split by purpose — answering, indexing, training — call
crawlers, which groups by both. The two are
consistent: an operator's views here equals the sum of its rows there.
A worked example
{
"data": [
{ "operator": "bytedance", "views": 3143 },
{ "operator": "gpt", "views": 752 },
{ "operator": "human", "views": 518 }
]
}Bytedance alone fetched six times what every human visitor viewed. That is a common shape on a small site, and it is the number that explains why a page can feel busy in the logs and quiet in the analytics.
Crawler traffic is always counted here, whatever bots says. See
crawlers.
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: excludedexcludedincludedfilter_pathstringqueryfilter_path_patternstringqueryfilter_hostnamestringqueryfilter_entry_pathstringqueryfilter_exit_linkstringqueryfilter_file_downloadstringqueryfilter_goalstringqueryfilter_browserstringqueryfilter_osstringqueryfilter_devicestringqueryfilter_countrystringqueryfilter_regionstringqueryfilter_citystringqueryfilter_referrerstringqueryfilter_channelstringqueryfilter_utm_sourcestringqueryfilter_utm_mediumstringqueryfilter_utm_campaignstringqueryfilter_gad_campaign_idstringqueryfilter_utm_termstringqueryfilter_bot_kindstringqueryResponse
The answer.
dataunknownmetaobjecterrorobjecterrorobjecterrorobjecterrorobject