API 參考
Analytics
Management API: GET /sites/{id}/analytics/overview, GET /sites/{id}/analytics/pages, GET /sites/{id}/analytics/bots, …
Analytics overview
/sites/{id}/analytics/overviewGet website traffic overview for the selected period (default 30 days, or a custom from/to date range in the website's timezone): totals, previous-period comparison, daily series, devices, top traffic sources, UTM campaigns, buttons, and countries. When the range starts before traffic source data became complete, dataCoverage explains how topSources and topUtm are affected. Errors: FORBIDDEN, VALIDATION, RATE_LIMITED (per-site analytics limit), ANALYTICS_BUSY.
Parameters
idstring · pathrequiredWebsite id. Get it from sites.list or from sites.create.
daysinteger · queryNumber of completed calendar days ending yesterday in the website's timezone (1 to 3650, defaults to 30; days=1 means yesterday; ignored when from and to are provided).
fromstring · queryStart calendar date (YYYY-MM-DD) in the website's timezone, inclusive. Must be paired with to.
tostring · queryEnd calendar date (YYYY-MM-DD) in the website's timezone, inclusive (up to yesterday in site timezone). Must be paired with from.
Response 200
daysintegerrequiredNumber of days in the selected range.
fromstringrequiredStart date (YYYY-MM-DD) in the website's timezone.
tostringrequiredEnd date (YYYY-MM-DD) in the website's timezone.
timezonestringrequiredIANA timezone used for day boundaries.
dataStatus"ok" | "no_traffic" | "pending_aggregation"requiredok when traffic data exists; no_traffic when the site had 0 visits in this range; pending_aggregation when filled from raw events before the nightly rollup.
totalsobjectrequiredtotals.pageviewsintegerrequiredTotal pageviews in the period.
totals.uniqueVisitorsintegerrequiredSum of daily unique visitors in the period.
totals.sessionsintegerrequiredTotal visitor sessions (30-minute idle boundary).
totals.clicksintegerrequiredTotal custom button clicks.
totals.formSubmitsintegerrequiredTotal non-spam form submissions.
totals.socialClicksintegerrequiredTotal external brand/social link clicks.
previousPeriodobjectrequiredTotals from the immediately preceding period of equal length.
previousPeriod.fromstringrequiredPrevious period start date (YYYY-MM-DD).
previousPeriod.tostringrequiredPrevious period end date (YYYY-MM-DD).
previousPeriod.totalsobjectrequiredpreviousPeriod.totals.pageviewsintegerrequiredTotal pageviews in the period.
previousPeriod.totals.uniqueVisitorsintegerrequiredSum of daily unique visitors in the period.
previousPeriod.totals.sessionsintegerrequiredTotal visitor sessions (30-minute idle boundary).
previousPeriod.totals.clicksintegerrequiredTotal custom button clicks.
previousPeriod.totals.formSubmitsintegerrequiredTotal non-spam form submissions.
previousPeriod.totals.socialClicksintegerrequiredTotal external brand/social link clicks.
trendsobjectrequiredtrends.pageviewsinteger | nullrequiredPercentage change vs. the previous period of equal length (null when previous period was 0).
trends.uniqueVisitorsinteger | nullrequiredPercentage change vs. the previous period of equal length.
trends.sessionsinteger | nullrequiredPercentage change vs. the previous period of equal length.
trends.clicksinteger | nullrequiredPercentage change vs. the previous period of equal length.
trends.formSubmitsinteger | nullrequiredPercentage change vs. the previous period of equal length.
trends.socialClicksinteger | nullrequiredPercentage change vs. the previous period of equal length.
dailyobject[]requiredDay-by-day series covering every day in [from, to].
daily[].datestringrequiredCalendar date (YYYY-MM-DD) in the website's timezone.
daily[].pageviewsintegerrequiredPageviews on this date.
daily[].uniqueVisitorsintegerrequiredUnique visitors on this date.
daily[].sessionsintegerrequiredVisitor sessions on this date.
daily[].clicksintegerrequiredButton clicks on this date.
daily[].formSubmitsintegerrequiredForm submissions on this date.
daily[].socialClicksintegerrequiredExternal link clicks on this date.
devicesobjectrequireddevices.mobileintegerrequiredUnique visitors on mobile devices.
devices.desktopintegerrequiredUnique visitors on desktop devices.
devices.tabletintegerrequiredUnique visitors on tablet devices.
topSourcesobject[]requiredTop entry traffic sources (google, direct, chatgpt, etc.).
topSources[].namestringrequiredChannel, button, link, or country identifier.
topSources[].valueintegerrequiredCount in the selected period.
topUtmobject[]requiredTop UTM campaigns or source/medium pairs.
topUtm[].namestringrequiredChannel, button, link, or country identifier.
topUtm[].valueintegerrequiredCount in the selected period.
topButtonsobject[]requiredTop clicked custom CTA buttons.
topButtons[].namestringrequiredChannel, button, link, or country identifier.
topButtons[].valueintegerrequiredCount in the selected period.
topCountriesobject[]requiredTop visitor countries (ISO 3166-1 alpha-2).
topCountries[].namestringrequiredChannel, button, link, or country identifier.
topCountries[].valueintegerrequiredCount in the selected period.
dataCoverageobjectPresent only when the selected range starts before trafficSourcesCompleteFrom; do not read the direct share of that earlier part as real traffic distribution.
dataCoverage.trafficSourcesCompleteFromstringrequiredLocal date (YYYY-MM-DD, website timezone) from which topSources and topUtm are fully recorded.
dataCoverage.notestringrequiredHow data before trafficSourcesCompleteFrom affects topSources and topUtm.
Errors
FORBIDDEN403VALIDATION400RATE_LIMITED429 · per-site analytics limitANALYTICS_BUSY429
MCP tool analytics_overview
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/analytics/overview?days=30" \
-H "Authorization: Bearer $KANORIO_TOKEN"{
"days": 30,
"from": "2026-09-23",
"to": "2026-10-22",
"timezone": "Asia/Taipei",
"dataStatus": "ok",
"totals": {
"pageviews": 4820,
"uniqueVisitors": 1940,
"sessions": 2310,
"clicks": 412,
"formSubmits": 38,
"socialClicks": 185
},
"previousPeriod": {
"from": "2026-08-24",
"to": "2026-09-22",
"totals": {
"pageviews": 4200,
"uniqueVisitors": 1750,
"sessions": 2050,
"clicks": 360,
"formSubmits": 32,
"socialClicks": 160
}
},
"trends": {
"pageviews": 15,
"uniqueVisitors": 11,
"sessions": 13,
"clicks": 14,
"formSubmits": 19,
"socialClicks": 16
},
"daily": [
{
"date": "2026-10-22",
"pageviews": 168,
"uniqueVisitors": 72,
"sessions": 84,
"clicks": 15,
"formSubmits": 2,
"socialClicks": 6
}
],
"devices": {
"mobile": 1320,
"desktop": 540,
"tablet": 80
},
"topSources": [
{
"name": "google",
"value": 980
},
{
"name": "instagram",
"value": 540
},
{
"name": "chatgpt",
"value": 112
}
],
"topUtm": [
{
"name": "october_special",
"value": 210
}
],
"topButtons": [
{
"name": "Order Now",
"value": 196
}
],
"topCountries": [
{
"name": "TW",
"value": 1620
},
{
"name": "US",
"value": 210
}
]
}Analytics pages
/sites/{id}/analytics/pagesGet per-page traffic, entry sessions, bounce rate, engagement duration, button clicks, form submissions, AI assistant referral entries, and cross-tool ids (websitePageId for pages.*, productId for products.*, postId for posts.*) for the selected period. Errors: FORBIDDEN, VALIDATION, RATE_LIMITED (per-site analytics limit), ANALYTICS_BUSY.
Parameters
idstring · pathrequiredWebsite id. Get it from sites.list or from sites.create.
daysinteger · queryNumber of completed calendar days ending yesterday in the website's timezone (1 to 3650, defaults to 30; days=1 means yesterday; ignored when from and to are provided).
fromstring · queryStart calendar date (YYYY-MM-DD) in the website's timezone, inclusive. Must be paired with to.
tostring · queryEnd calendar date (YYYY-MM-DD) in the website's timezone, inclusive (up to yesterday in site timezone). Must be paired with from.
Response 200
daysintegerrequiredNumber of days in the selected range.
fromstringrequiredStart date (YYYY-MM-DD) in the website's timezone.
tostringrequiredEnd date (YYYY-MM-DD) in the website's timezone.
timezonestringrequiredIANA timezone used for day boundaries.
pagesobject[]requiredpages[].pageIdstringrequiredAnalytics PageRef identifier (e.g. WebsitePage id, 'product:<productId>', 'blog-post:<postId>', or 'blog-index').
pages[].kindstringrequiredContent kind (page, blog-post, product, shop-index, etc.).
pages[].websitePageIdstring | nullrequiredCorresponding WebsitePage id for use with pages.get / pages.update / pages.replace_sections (null for dynamic blog posts or taxonomy pages).
pages[].productIdstring | nullrequiredCorresponding Product id for use with products.get / products.update when kind is 'product' (null otherwise).
pages[].postIdstring | nullrequiredCorresponding BlogPost id for use with posts.get / posts.update when kind is 'blog-post' (null otherwise).
pages[].pathstring | nullrequiredURL path snapshot.
pages[].titlestring | nullrequiredPage title snapshot.
pages[].pageviewsintegerrequiredTotal pageviews on this page.
pages[].uniqueVisitorsintegerrequiredSum of daily unique visitors on this page.
pages[].entrySessionsintegerrequiredSessions that started on this page.
pages[].bounceRateintegerrequiredBounce percentage (0 to 100).
pages[].avgEngagementSecintegerrequiredAverage foreground engagement time in seconds, weighted by daily pageviews.
pages[].ctaClicksintegerrequiredCustom CTA button clicks on this page.
pages[].formSubmitsintegerrequiredNon-spam form submissions on this page.
pages[].aiReferralEntriesintegerrequiredEntry sessions on this page attributed to AI assistants (ChatGPT, Perplexity, Claude, Gemini, Copilot).
Errors
FORBIDDEN403VALIDATION400RATE_LIMITED429 · per-site analytics limitANALYTICS_BUSY429
MCP tool analytics_pages
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/analytics/pages?days=30" \
-H "Authorization: Bearer $KANORIO_TOKEN"{
"days": 30,
"from": "2026-09-23",
"to": "2026-10-22",
"timezone": "Asia/Taipei",
"pages": [
{
"pageId": "pg_example456",
"kind": "page",
"websitePageId": "pg_example456",
"productId": null,
"postId": null,
"path": "/",
"title": "Home",
"pageviews": 2840,
"uniqueVisitors": 1420,
"entrySessions": 1280,
"bounceRate": 34,
"avgEngagementSec": 52,
"ctaClicks": 245,
"formSubmits": 22,
"aiReferralEntries": 36
}
]
}Analytics bots
/sites/{id}/analytics/botsGet AI crawler and search bot activity summary (GPTBot, ClaudeBot, PerplexityBot, Googlebot, etc.) for the selected period, with optional per-page intent breakdown (breakdown='page', up to 3650 days) or per-page × per-bot breakdown (breakdown='page_bot', retained for 90 days). Breakdown rows are paged: pass limit and cursor (nextCursor) while hasMore is true. Errors: FORBIDDEN, VALIDATION (details.reason: UNKNOWN_BOT or RANGE_BEFORE_RETENTION), RATE_LIMITED (per-site analytics limit), ANALYTICS_BUSY, INVALID_CURSOR.
Parameters
idstring · pathrequiredWebsite id. Get it from sites.list or from sites.create.
daysinteger · queryNumber of completed calendar days ending yesterday in the website's timezone (1 to 3650, defaults to 30; days=1 means yesterday; ignored when from and to are provided).
fromstring · queryStart calendar date (YYYY-MM-DD) in the website's timezone, inclusive. Must be paired with to.
tostring · queryEnd calendar date (YYYY-MM-DD) in the website's timezone, inclusive (up to yesterday in site timezone). Must be paired with from.
breakdown"none" | "page" | "page_bot" · queryOptional breakdown mode: 'none' (default, top bots only), 'page' (per-page intent rollup, up to 3650 days), or 'page_bot' (per-page × per-bot rollup, retained for 90 days).
pageRefstring · queryOptional PageRef filter when breakdown is 'page' or 'page_bot' (e.g. a page id, 'blog-post:<id>', 'product:<id>', or 'other').
botTokenstring · queryOptional bot token filter (must be one of the 35 registered tokens, e.g. GPTBot, ClaudeBot, PerplexityBot). Applies to totals, bots, and breakdown='page_bot'; breakdown='page' rows always sum all bots by intent.
limitinteger · queryMaximum number of items to return, 1–100. Defaults to 100.
cursorstring · queryOpaque cursor from the previous page's nextCursor. Omit for the first page.
Response 200
daysintegerrequiredNumber of days in the selected range.
fromstringrequiredStart date (YYYY-MM-DD) in the website's timezone.
tostringrequiredEnd date (YYYY-MM-DD) in the website's timezone.
timezonestringrequiredIANA timezone used for day boundaries.
totalsobjectrequiredtotals.totalHitsintegerrequiredTotal crawler hits in the period.
totals.blockedHitsintegerrequiredCrawler hits blocked by site rules.
totals.verifiedHitsintegerrequiredHits verified against official bot CIDR/ASN IP ranges.
totals.spoofedHitsintegerrequiredHits claiming a bot User-Agent that failed official CIDR/ASN IP verification.
botsobject[]requiredbots[].botTokenstringrequiredBot User-Agent token (e.g. GPTBot, ClaudeBot).
bots[].operatorstringrequiredOrganization operating the bot (e.g. OpenAI, Anthropic, Google).
bots[].intent"training" | "retrieval" | "search"requiredDeclared purpose of the crawler.
bots[].blockablebooleanrequiredWhether this crawler can be blocked via site rules.
bots[].totalHitsintegerrequiredTotal hits from this bot.
bots[].blockedHitsintegerrequiredBlocked hits from this bot.
bots[].verifiedHitsintegerrequiredVerified hits from this bot.
bots[].spoofedHitsintegerrequiredSpoofed hits claiming this bot token.
pageBreakdownobject[]pageBreakdown[].pageRefstringrequiredCanonical PageRef id (e.g. WebsitePage id, blog-post:<id>, product:<id>, or 'other').
pageBreakdown[].pathstring | nullrequiredCanonical page path (null when pageRef is 'other').
pageBreakdown[].titlestring | nullrequiredCanonical page title (null when pageRef is 'other').
pageBreakdown[].retrievalHitsintegerrequiredHits from AI search/retrieval crawlers.
pageBreakdown[].trainingHitsintegerrequiredHits from AI model training crawlers.
pageBreakdown[].searchHitsintegerrequiredHits from search engine indexing crawlers.
pageBreakdown[].blockedHitsintegerrequiredHits blocked with HTTP 403.
pageBreakdown[].spoofedHitsintegerrequiredHits that failed official CIDR/ASN verification.
pageBreakdown[].lastSeenAtstring | nullrequiredISO-8601 timestamp of the latest crawler hit on this page.
pageBotBreakdownobject[]pageBotBreakdown[].pageRefstringrequiredCanonical PageRef id (e.g. WebsitePage id, blog-post:<id>, product:<id>, or 'other').
pageBotBreakdown[].pathstring | nullrequiredCanonical page path (null when pageRef is 'other').
pageBotBreakdown[].titlestring | nullrequiredCanonical page title (null when pageRef is 'other').
pageBotBreakdown[].botTokenstringrequiredBot User-Agent token (e.g. GPTBot, ClaudeBot).
pageBotBreakdown[].operatorstringrequiredOrganization operating the bot.
pageBotBreakdown[].intent"training" | "retrieval" | "search"requiredDeclared purpose of the crawler.
pageBotBreakdown[].hitsintegerrequiredTotal hits from this bot on this page.
pageBotBreakdown[].blockedHitsintegerrequiredBlocked hits from this bot on this page.
pageBotBreakdown[].verifiedHitsintegerrequiredVerified hits from this bot on this page.
pageBotBreakdown[].spoofedHitsintegerrequiredSpoofed hits claiming this bot token on this page.
pageBotBreakdown[].lastSeenAtstring | nullrequiredISO-8601 timestamp of the latest hit from this bot on this page.
hasMorebooleanWith a breakdown: true when more breakdown rows exist.
nextCursorstring | nullWith a breakdown: cursor for the next breakdown page, or null on the last page.
Errors
FORBIDDEN403VALIDATION400 · details.reason: UNKNOWN_BOT or RANGE_BEFORE_RETENTIONRATE_LIMITED429 · per-site analytics limitANALYTICS_BUSY429INVALID_CURSOR400
MCP tool analytics_bots
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/analytics/bots?days=30" \
-H "Authorization: Bearer $KANORIO_TOKEN"{
"days": 30,
"from": "2026-09-23",
"to": "2026-10-22",
"timezone": "Asia/Taipei",
"totals": {
"totalHits": 640,
"blockedHits": 0,
"verifiedHits": 590,
"spoofedHits": 12
},
"bots": [
{
"botToken": "GPTBot",
"operator": "OpenAI",
"intent": "training",
"blockable": true,
"totalHits": 310,
"blockedHits": 0,
"verifiedHits": 302,
"spoofedHits": 2
}
]
}Analytics edge
/sites/{id}/analytics/edgeGet Cloudflare CDN & WAF edge traffic and security summary for the selected period: total requests, mitigated requests, static CDN cache hit rate (Worker SSR/ISR HTML and API routes are recorded as 'dynamic' at the outer CDN layer), saved bytes, edge 4xx/5xx responses (errors4xx includes HTTP 403 WAF/bot blocks and 404 scanner probes), cache status breakdown, top countries, and security actions. Errors: FORBIDDEN, HOSTED_ONLY, VALIDATION, RATE_LIMITED (per-site analytics limit), ANALYTICS_BUSY.
Parameters
idstring · pathrequiredWebsite id. Get it from sites.list or from sites.create.
daysinteger · queryNumber of completed calendar days ending yesterday in the website's timezone (1 to 3650, defaults to 30; days=1 means yesterday; ignored when from and to are provided).
fromstring · queryStart calendar date (YYYY-MM-DD) in the website's timezone, inclusive. Must be paired with to.
tostring · queryEnd calendar date (YYYY-MM-DD) in the website's timezone, inclusive (up to yesterday in site timezone). Must be paired with from.
Response 200
daysintegerrequiredNumber of days in the selected range.
fromstringrequiredStart date (YYYY-MM-DD) in the website's timezone.
tostringrequiredEnd date (YYYY-MM-DD) in the website's timezone.
timezonestringrequiredIANA timezone used for day boundaries.
summaryobjectrequiredsummary.totalRequestsintegerrequiredTotal edge requests received by Cloudflare.
summary.mitigatedRequestsintegerrequiredSuspicious or attack requests mitigated at the edge (WAF / bot rules).
summary.cachedRequestsintegerrequiredRequests served from outer Cloudflare CDN cache (hit, stale, revalidated).
summary.cachedBytesnumberrequiredBytes served from outer Cloudflare CDN cache.
summary.cacheHitRateintegerrequiredOuter Cloudflare CDN static cache hit percentage (0 to 100; Worker-rendered SSR/ISR HTML and API routes are recorded as 'dynamic' in cacheStatusBreakdown).
summary.errors4xxintegerrequiredEdge 4xx responses (includes HTTP 403 blocks/challenges from WAF & bot rules and 404 responses to scanner probes).
summary.errors5xxintegerrequiredEdge 5xx responses.
cacheStatusBreakdownobject[]Breakdown of Cloudflare edge cache statuses (dynamic, hit, miss, etc.).
cacheStatusBreakdown[].namestringrequiredChannel, button, link, or country identifier.
cacheStatusBreakdown[].valueintegerrequiredCount in the selected period.
topCountriesobject[]requiredTop request origin countries (ISO 3166-1 alpha-2).
topCountries[].namestringrequiredChannel, button, link, or country identifier.
topCountries[].valueintegerrequiredCount in the selected period.
securityActionsobject[]requiredMitigation actions taken by Cloudflare WAF (block, managed_challenge, etc.).
securityActions[].namestringrequiredChannel, button, link, or country identifier.
securityActions[].valueintegerrequiredCount in the selected period.
Errors
FORBIDDEN403HOSTED_ONLY409VALIDATION400RATE_LIMITED429 · per-site analytics limitANALYTICS_BUSY429
MCP tool analytics_edge
curl -X GET "https://app.kanorio.com/api/v1/sites/{id}/analytics/edge?days=30" \
-H "Authorization: Bearer $KANORIO_TOKEN"{
"days": 30,
"from": "2026-09-23",
"to": "2026-10-22",
"timezone": "Asia/Taipei",
"summary": {
"totalRequests": 28400,
"mitigatedRequests": 142,
"cachedRequests": 24100,
"cachedBytes": 512000000,
"cacheHitRate": 85,
"errors4xx": 34,
"errors5xx": 0
},
"cacheStatusBreakdown": [
{
"name": "hit",
"value": 24100
},
{
"name": "dynamic",
"value": 4300
}
],
"topCountries": [
{
"name": "TW",
"value": 22100
},
{
"name": "US",
"value": 3200
}
],
"securityActions": [
{
"name": "managed_challenge",
"value": 98
},
{
"name": "block",
"value": 44
}
]
}