Gets traffic analytics
Returns the traffic metrics of your account over a time window: requests by DataDome status, by origin and by threat, the responses DataDome returned, slider and device check outcomes, and contact form submissions. Metrics can be bucketed by time and split by root domain, domain, endpoint or AI agent.
Access. The endpoint is available to accounts on an Enterprise Bot Protect plan that have the Trend Reports feature. Any other account gets 403 with the error TREND_REPORTS_NOT_ENABLED, whatever the API key. The API key identifies one account, and every metric returned belongs to that account.
Authentication. Send the API key in the x-api-key header.
Rate limit. 5 requests per minute per API key. Above it the endpoint returns 429 with a Retry-After header. A request spends the budget once access is granted and before its parameters are checked: a 400 uses one request of the budget, a 403 does not.
Time window. from is included and to is excluded. Both are optional: without to the window ends now, and without from it starts 24 hours before to. from must be within the last 24 months and not in the future. A to in the future is treated as now. Send dates as ISO 8601 with seconds and an offset or Z, for example 2026-09-08T15:00:00Z. Fractional seconds are rejected. Every timestamp in the response has the same format, rendered in the requested timezone.
Realtime horizon. The horizon is the end of the latest hour covered by your trend reports, usually 48 to 72 hours before the request (now minus 48 hours, floored to the hour, when no recent report exists). Read it from meta.realtimeHorizon; do not compute it. Each window boundary is handled on its own. A boundary older than the horizon is snapped outward to the hour (from is floored, to is ceiled). A boundary at or after the horizon is kept to the second. The window actually served is returned in meta.from and meta.to. Label reports with those values, not with the requested ones.
Data sources and stability. Before the horizon, metrics come from hourly trend reports. From the horizon on, they come from raw traffic, to the second. Metrics after meta.realtimeHorizon are not final: slider and device check outcomes are added after the request is served, so the same query replayed later can return higher counts for the same bucket. Only data before the realtime horizon is stable. In the raw traffic part, requests absorbed by the Edge Circuit Breaker during a DDoS event are counted in requestsCount, requestsByOrigin.threats, requestsByThreat.ddos, requestsByDataDomeStatus.protectionEnabled and the block responses. They carry no domain, endpoint or AI agent, so they are left out of any query that filters or splits by root domain, domain or endpoint, and out of agentic scope.
Vocabulary: slider and block. slider is the CAPTCHA challenge DataDome serves (wire values block and invalidate_captcha). block is the hard block (wire value hard_block). allow covers authorize and tagged_authorize, and deviceCheck is the device check interstitial. sliderOutcomes.count comes from the slider outcome data, not from the responses, so it can differ from responsesBreakdown.slider.
Buckets and pagination. interval sets the time bucket (hour, day or month). Without it, the whole window is one bucket. splitBy adds one dimension per value, and each dimension multiplies the number of buckets. Day and month buckets follow the calendar of timezone. The first and last bucket are clamped to the window, so they can be shorter than interval. Buckets with no traffic are left out, so a window without traffic returns data: []. Buckets are ordered by time, then by the dimensions in the order given in splitBy. Pagination applies only with interval or splitBy. Otherwise the response holds at most one bucket and meta.hasMore is false. When meta.hasMore is true, send meta.nextCursor back as cursor with every other parameter unchanged (limit may change). A cursor expires after 1 hour. An expired cursor, or one sent with other parameters, is rejected with 400 INVALID_CURSOR. The last page has hasMore: false and no nextCursor.
Agentic traffic. Agentic scope is on when agenticOnly=true, when aiAgents is set, or when splitBy contains aiAgent. In agentic scope every metric counts AI agent traffic only, meta.query.agenticScope is true, and every bucket carries requestsByIntent. Its values never exceed requestsCount and can sum to less when a request's detected intent is not one of its keys. With splitBy=aiAgent, each bucket carries aiAgentUuid. A null value groups the traffic of agents that are not AI agents of your account.
Warnings. An endpoints or aiAgents value that is a valid UUID but matches nothing on your account does not fail the request. It is listed in meta.warnings, with the code UNKNOWN_ENDPOINT_UUID or UNKNOWN_AI_AGENT_UUID, and it matches no traffic. meta.warnings is absent when there is nothing to report. rootDomains and domains are not checked: a value that matches nothing returns no traffic and no warning.
Request
- Base URLhttps://customer-api.datadome.co
- URLhttps://customer-api.datadome.co/1.0/account/traffic-analytics
- AuthAPI key in header x-api-key
Query parameters
Start of the window, included. ISO 8601 date and time with seconds and an offset or Z, for example 2026-09-28T00:00:00Z. Fractional seconds are rejected. Must be within the last 24 months and not in the future. Defaults to to minus 24 hours. Floored to the hour when older than the realtime horizon.
End of the window, excluded. Same format as from, and strictly later than it. Defaults to now. A value in the future is treated as now. Ceiled to the hour when older than the realtime horizon.
Time bucket size. Without it, the metrics of the whole window are returned in one bucket, which is the way to poll a short recent window.
Canonical IANA time zone name, for example Europe/Paris; aliases such as US/Eastern are rejected. Places day and month bucket boundaries and renders every timestamp of the response. Hour buckets cover the same instants in any zone; only their labels change. The offset from UTC must be a whole number of hours over the whole window, so zones such as Asia/Kolkata are rejected with INVALID_TIMEZONE_OFFSET. A daylight saving change inside the window is accepted.
Comma-separated dimensions to split the metrics by, in addition to interval. Any combination of distinct values is accepted, and their order sets the order of the dimension fields and of the buckets. aiAgent turns agentic scope on.
[ "domain", "endpoint" ]
Comma-separated root domains to filter on. Values are not checked: one that matches nothing returns no traffic.
[ "example.com" ]
Comma-separated domains to filter on. Values are not checked: one that matches nothing returns no traffic.
[ "www.example.com", "api.example.com" ]
Comma-separated endpoint UUIDs to filter on. A value that is not a UUID is rejected with INVALID_ENDPOINT_UUID. A UUID that matches no endpoint of your account is reported in meta.warnings and matches no traffic.
[ "3f2b8c1e-7a4d-4e6f-9b2a-1c5d8e7f6a90" ]
Comma-separated AI agent UUIDs to filter on. Turns agentic scope on. A value that is not a UUID is rejected with INVALID_AI_AGENT_UUID. A UUID that matches no AI agent of your account is reported in meta.warnings and matches no traffic.
[ "0b7e4c2a-5d1f-4a8b-9c3e-6f2d1a0b9c8d" ]
Set to true to count agentic traffic only, across all AI agents. Only the exact value true turns it on; any other value is ignored, never rejected. Redundant when aiAgents is set or splitBy contains aiAgent.
Maximum number of buckets per page.
Opaque cursor of the next page, taken from meta.nextCursor of the previous response. Send every other parameter unchanged; only limit may change. Expires 1 hour after it was issued. Omit it for the first page.
Response
The metrics, one entry of data per bucket, and meta, which describes the window served, the query as understood and the pagination state.
Example response
{
"meta": {
"from": "2026-09-28T00:00:00Z",
"to": "2026-09-29T00:00:00Z",
"realtimeHorizon": "2026-10-05T12:00:00Z",
"timezone": "UTC",
"query": {
"splitBy": [],
"agenticScope": false
},
"hasMore": false
},
"data": [
{
"from": "2026-09-28T00:00:00Z",
"to": "2026-09-29T00:00:00Z",
"requestsCount": 27227,
"requestsByDataDomeStatus": {
"protectionEnabled": {
"count": 27225,
"threats": 10234
},
"protectionDisabled": {
"count": 2,
"threats": 2
}
},
"requestsByOrigin": {
"humans": {
"count": 15000,
"responsesBreakdown": {
"allow": 14200,
"deviceCheck": 700,
"redirect": 60,
"waitingRoom": 40
}
},
"threats": {
"count": 10234,
"responsesBreakdown": {
"allow": 34,
"slider": 3000,
"block": 6900,
"deviceCheck": 280,
"redirect": 12,
"waitingRoom": 8
}
},
"verifiedBots": {
"count": 1200,
"responsesBreakdown": {
"allow": 1100,
"slider": 50,
"block": 30,
"deviceCheck": 15,
"redirect": 3,
"waitingRoom": 2
}
},
"aiAgents": {
"count": 700,
"responsesBreakdown": {
"allow": 600,
"slider": 40,
"block": 45,
"deviceCheck": 10,
"redirect": 3,
"waitingRoom": 2
}
},
"custom": {
"count": 93,
"responsesBreakdown": {
"allow": 80,
"slider": 5,
"block": 3,
"deviceCheck": 3,
"redirect": 1,
"waitingRoom": 1
}
}
},
"requestsByThreat": {
"scraping": 1234,
"scalping": 32,
"spamming": 12,
"credentialStuffing": 43,
"fakeAccountCreation": 21,
"paymentFraud": 10,
"apiAbuse": 12,
"vulnerabilityScanning": 43,
"ddos": 2,
"agenticAbuse": 10
},
"responsesBreakdown": {
"allow": 16014,
"slider": 3095,
"block": 6978,
"deviceCheck": 1008,
"redirect": 79,
"waitingRoom": 53
},
"sliderOutcomes": {
"count": 3133,
"challengeNotLoaded": 200,
"failed": 400,
"ignored": 900,
"blocked": 300,
"passed": {
"count": 1333,
"visual": 1200,
"audio": 133
}
},
"deviceCheckOutcomes": {
"challengeNotLoaded": 90,
"allow": 850,
"block": 30,
"slider": {
"count": 38,
"challengeNotLoaded": 2,
"failed": 6,
"ignored": 10,
"blocked": 4,
"passed": {
"count": 16,
"visual": 14,
"audio": 2
}
}
},
"contactFormSubmissionsCount": 17
}
]
}Changes
No recorded changes to this operation across all 1 revision of this API.