POST /functions/v1/export-user-analytics
Returns a single JSON document with report-style analytics for every domain on your account — both domains you own and domains shared with you. Unlike the dashboard charts and PDF report, which group smaller crawlers into “Other” and “Other social”, this endpoint breaks traffic out into each individual bot.
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. The Export all
(JSON) button in the Analytics dashboard is
available on all plans.
Request
| Header | Required | Description |
|---|
Authorization | Yes | Bearer hado_sk_your_key_here |
Content-Type | Yes | application/json |
Body Parameters
| Parameter | Type | Required | Description |
|---|
period | string | No | Reporting window: 1d, 7d, 30d, 90d, or 365d. Defaults to 30d. Applies to every domain in the response. |
The export always covers every domain your account can access — there is no per-domain parameter.
Example Request
curl -X POST https://api.hadoseo.com/functions/v1/export-user-analytics \
-H "Authorization: Bearer hado_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"period": "30d"
}'
Response
Success (200)
{
"generatedAt": "2026-06-29T12:00:00.000Z",
"period": "30d",
"userId": "00000000-0000-0000-0000-000000000000",
"domainCount": 1,
"domains": [
{
"domain": "example.com",
"domainId": "11111111-1111-1111-1111-111111111111",
"role": "owner",
"summary": {
"totalCrawls": 1840,
"prerenders": 412,
"cachedViews": 1520,
"cacheMisses": 320,
"cacheHitRate": 82.6
},
"botTotals": {
"googlebot": 920,
"googleextendedbot": 14,
"bingbot": 210,
"openaibot": 88,
"anthropicbot": 31,
"perplexitybot": 12,
"twitterbot": 40,
"facebookbot": 35,
"linkedinbot": 22,
"slackbot": 9,
"discordbot": 4,
"whatsappbot": 6,
"telegrambot": 3,
"pinterestbot": 2,
"snapchatbot": 0,
"redditbot": 5,
"metabot": 7,
"quorabot": 1,
"social_other": 8,
"applebot": 18,
"amazonbot": 11,
"baidubot": 6,
"yandexbot": 9,
"duckduckbot": 4,
"bytespiderbot": 25
},
"botSeries": [
{ "date": "2026-06-28", "googlebot": 41, "bingbot": 9, "openaibot": 3, "bytespiderbot": 1 }
],
"topPages": [
{
"url": "https://example.com/blog/launch",
"seoScore": 92,
"seoIssuesCount": 1,
"botTotal": 134
}
],
"seo": {
"good": 120,
"needsWork": 18,
"poor": 4,
"unknown": 9,
"totalPages": 151,
"totalIssues": 47
}
}
]
}
Each botSeries entry contains a count for every bot listed in
botTotals. The example above is trimmed to a few bots for brevity; the
actual response includes all of them, with 0 where there was no traffic.
Fields
| Field | Type | Description |
|---|
generatedAt | string | ISO 8601 timestamp of when the export was produced. |
period | string | The period applied: 1d, 7d, 30d, 90d, or 365d. |
userId | string | The account that owns the API key. |
domainCount | number | Number of domains included. |
domains[].domain | string | The domain name. |
domains[].domainId | string | The domain’s unique ID. |
domains[].role | string | Access level for this domain: owner, manager, or viewer. |
domains[].summary | object | Period totals: totalCrawls, prerenders, cachedViews, cacheMisses, cacheHitRate. |
domains[].botTotals | object | Total visits per individual bot for the period. |
domains[].botSeries | array | Per-day breakdown; each entry has a date plus a count for every bot. |
domains[].topPages | array | Top pages by bot traffic: url, seoScore, seoIssuesCount, botTotal. |
domains[].seo | object | SEO health bucket counts (good, needsWork, poor, unknown) plus totalPages and totalIssues. |
Granular bot breakdown
Every bot is reported as its own field. The bots that the dashboard and PDF report fold into “Other” and “Other social” each appear individually here:
| Bucket in reports | Individual bots in botTotals / botSeries |
|---|
| Other social | slackbot, discordbot, whatsappbot, telegrambot, pinterestbot, snapchatbot, redditbot, metabot, quorabot, social_other |
| Other | applebot, amazonbot, baidubot, yandexbot, duckduckbot, bytespiderbot |
The named bots already shown in reports are also present individually: googlebot, googleextendedbot, bingbot, openaibot, anthropicbot, perplexitybot, twitterbot, facebookbot, and linkedinbot.
social_other is a catch-all for social crawlers that can’t be identified
individually. It’s reported as its own field rather than merged into another bot.
Error Responses
| Status | Body | Description |
|---|
| 400 | { "error": "invalid_request" } | Invalid period value |
| 401 | { "error": "invalid_api_key" } | API key is missing, invalid, or revoked |
| 403 | { "error": "plan_upgrade_required" } | Programmatic export requires the Pro plan or above |
| 429 | { "error": "rate_limit_exceeded", "usage": 300, "limit": 300 } | Monthly or per-minute rate limit exceeded |
When you receive a 429, the usage and limit fields tell you where you stand against your monthly quota. Per-minute limits (60 req/min) reset automatically after 60 seconds. See Authentication for plan limits.
Examples
JavaScript / Node.js
const response = await fetch(
"https://api.hadoseo.com/functions/v1/export-user-analytics",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.HADOSEO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ period: "30d" }),
},
);
const report = await response.json();
for (const domain of report.domains) {
console.log(domain.domain, domain.botTotals);
}
Prefer a one-off download? The Analytics dashboard has
an Export all (JSON) button that produces the same document for the
selected period without needing an API key — and it’s available on every plan.