Skip to main content
GET
List AI traffic daily rollups

Authorizations

Authorization
string
header
required

An agent key (rpk_...) created in Settings → API & MCP, sent as Authorization: Bearer rpk_.... Bearer only: a cookie session can never drive this API. An OAuth 2.1 access token obtained from the same host works identically and lands on the same ceiling.

Headers

X-Workspace-Id
string

Which workspace to read. Omit it and you get the account’s home workspace, which on an agency account is often not where the live businesses are. A workspace this credential cannot read is refused with 403 rather than quietly answered from the default.

Query Parameters

q
string

JSON filter object, for example {"needs_response":true}.

sort_by
string

Field to sort on.

limit
integer

Maximum rows to return.

skip
integer

Rows to skip, for paging.

Response

Matching AI traffic daily rollups.

id
string

Unique id.

site_id
string
location_id
string

Denormalized from the site so the business-scope clamp (lib/businessScope.js) is a single-field query, same reason VisibilityRun carries it.

date
string
crawler_hits
integer
verified_hits
integer

Hits whose source IP was inside the operator's published CIDR ranges (lib/aiCrawlerRanges.js). The IP itself is checked at ingest and discarded — it is never stored anywhere.

spoofed_hits
integer

Hits where we HAD the operator's ranges and the source IP was not in them — i.e. something wearing the crawler's user-agent. Distinct from unchecked (no IP reported, or the operator publishes no ranges), which is crawler_hits - verified_hits - spoofed_hits.

unique_agents
integer
by_agent
object

{ 'GPTBot': { hits, verified, spoofed, category, operator }, ... } — only user-agents lib/aiCrawlers.js could identify. Unclassified traffic is dropped, never bucketed as 'other'.

by_category
object

{ ai_answers, search_index, training, other_ai } hit counts. ai_answers is the closest thing to an impression; training is high-volume and least actionable.

top_paths
array

[{ path, hits }] capped at 25, descending. Capped because an unbounded path map on a large site is what would blow up the row size this schema exists to control.

paths_by_category
object

{ ai_answers: [{ path, hits }], search_index: [...], ... } — each category independently capped at 12, so a low-volume category still shows its own pages instead of being crowded out. Per CATEGORY and not per agent on purpose: 11 bots x 25 paths would be ~275 extra entries a row, four buckets x 12 is ~48. Page data can therefore narrow to a category but never to a single crawler.

referral_visits
integer
by_referrer
object

{ 'chatgpt.com': 8, ... } — humans who clicked through from an AI assistant. Only the browser beacon can see these.

referral_paths
array

[{ path, visits }] capped at 25, descending.