Skip to main content
Beta. This endpoint is new and its response shape may still change. It is the page-level companion to Export Crawl Analytics: same authentication and time windows, but broken down by page instead of aggregated per domain.
Returns the pages of one domain ranked by bot crawl volume. Each page carries its verified / declared / unknown tier split, a per-bot breakdown, crawl recency, and (by default) a bucketed time series. Because a domain can have thousands of crawled paths, this endpoint is single-domain and cursor-paginated — it does not have an account-wide mode.
To see what HTML the bots were actually served for one of these pages, pass its path as the url of Export Page Snapshots.
Always call this endpoint from a server-side environment (backend API, serverless function, build script, etc.). Never include your API key in client-side code — it will be visible to anyone inspecting your frontend.
Programmatic (API key) access requires the Pro plan and above — requests from Starter accounts return 403 plan_upgrade_required.
Page-level crawl data begins on 2026-07-09 (legacyCutover). Windows that start earlier are automatically clamped to that date (the response echoes your original start as requestedStartDate); windows that end before it return 400 invalid_request.

Request

Headers

Body Parameters

Window rules (same as the other export endpoints): period and startDate/endDate are mutually exclusive, dates must be real YYYY-MM-DD calendar dates, neither may be in the future, startDate ≤ endDate, and the span is capped at 365 days.

Only counting pages in your sitemap

Bots request all sorts of paths — stale links from years ago, one-off query-string variants, URLs that were never yours. By default those all appear here, because they really were crawled. When you’re auditing coverage of the pages you actually publish, set sitemapOnly: true:
A page counts as “in your sitemap” only if it came from your sitemap and is still in it — the same test the sitemap sync itself uses. That excludes:
  • URLs that have dropped out of your sitemap since they were last synced — they stop counting from the moment the sync notices,
  • URLs discovered by crawling or queued manually, which Hado SEO tracks but which were never in your sitemap,
  • any crawled path Hado SEO has no record of at all.
pageCount reflects the filtered set, so it’s the number of sitemap pages with crawls — not your total crawled paths. overflow is omitted entirely, because that synthetic bucket is by definition not a sitemap URL.
Unlike series and include, sitemapOnly is carried by the cursor. It changes which rows exist, so every page of a paged result must use the same setting — you can’t switch it midway through.

Example Request

First page:
Next page — just the cursor:
Only GPTBot crawls of the blog, ranked by verified volume:

Response

Success (200)

Fields

Buckets are anchored to your window, not the calendar. With week granularity, buckets advance in 7-day steps from startDate, so the first and last bucket may be partial — check bucketStart/bucketEnd rather than assuming full weeks. Aggregates (total, tiers, bots) are always exact window sums regardless of granularity.
Recency and servedFrom describe the window you asked for. With a tier or botId filter applied, they only reflect matching crawls — so under tier: "declared", lastVerifiedAt is always null. The overflow bucket carries neither.
The cursor pins the resolved window, so paging through results at midnight won’t shift the data between pages — page 2 always matches the window page 1 was computed from.

Error Responses

Examples

Paging through every crawled page

Each API request counts against your monthly quota, so prefer a larger pageSize (up to 500) over many small pages when exporting a whole domain — and set series: false if you only need the aggregates.