Skip to main content

Base URL and authentication

Takes Authorization: Bearer <YOUR_API_KEY> (details) and the stats:read permission. These two endpoints exist so you can check our work. Every other number in this API depends on what the bot filter removed and on which conversions we could tie back to a browsing session. Without these, our figures are unfalsifiable.

GET /v1/detection/quality

What automated traffic we removed before it reached your analytics, and what we let through and flagged.

Parameters

With neither date, the window is the last 7 days. The range may not span more than 366 days. timezone is not accepted: these are UTC calendar day totals.

Response fields

Each by_class row carries ua_class (the coarse class we assigned, such as search_crawler or ai_training_crawler), request_count, and dropped.

The two counts are separate on purpose

dropped and passthrough are not two halves of one number you should add up and call “filtered”. Only dropped requests were filtered out. Passthrough requests, mostly AI training crawlers such as CCBot, reached the pipeline and are surfaced here for transparency. The one rate you can defend is:
Requests against requests. We do not return that rate as a field, because naming one invites the wrong one. Everything on this endpoint is a request count. Comparing any of these figures against a session or visitor count from another endpoint gives a percentage with a different denominator on each side. It will look plausible and mean nothing.

GET /v1/detection/coverage

How much of your revenue we could tie back to a browsing session, and by what method.
Same parameters and same window rules as /quality.

match_method is the point of this endpoint

The empty bucket is not an error and it is not filtered out of coverage. On most sites it is the largest single row, and making it visible is the reason this endpoint exists. totals.unmatched_revenue_usd_cents is the same figure summarised. Raising coverage is a change to your checkout, not to our detection. Passing the session id through as payment metadata is the highest leverage single step.

source_kind here includes a value the traffic endpoints do not have

source_kind on this endpoint can be ai, non_ai, unmatched, or "" for older rows. unmatched exists only on revenue: it means no session was found. GET /v1/breakdowns/source-kinds returns ai, non_ai and unknown, and cannot return unmatched. The two endpoints describe overlapping populations along different axes, so reconciling them by addition gives a wrong number. There is one more trap here worth stating plainly. A small number of older rows carry source_kind: "unmatched" while match_method is set, meaning a session was found and the revenue is genuinely attributed. Split matched from unmatched on match_method, never on source_kind. Our own totals do exactly that.

Revenue here is US dollars

revenue_usd_cents is US cents and there is no revenue_display field, whatever your reporting currency. Our rule is to convert at the rate of the day money was earned, and this endpoint reports one total for the whole window rather than a figure per day. There is no honest rate for that total, so we return the stored currency and label it rather than invent one.

Errors

Next

  • Breakdowns for the traffic these figures qualify
  • AI crawlers for crawler traffic, which is a separate population from visitors