Cactal Analytics API
Read first-party traffic analytics for a website and export datasets as CSV.
Read first-party traffic analytics for a website and export datasets as CSV.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/cactal-ai:cactal-ai-analytics-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Cactal Ai Analytics API
version: 1.0.0
description: 'Operations tagged Analytics across 2 of this provider''s published API definitions: openapi.json, cactal-ai-openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.cactal.ai/v1
security:
- apiKey: []
tags:
- name: Analytics
description: Read first-party traffic analytics for a website and export datasets as CSV.
paths:
/websites/{websiteId}/analytics/query:
get:
operationId: websiteAnalytics.query.get
summary: Query analytics totals and breakdowns
description: 'Returns aggregate engagement totals — page views, distinct visitors, visits, bounces, and total time in seconds — for a date range, optionally broken down by one dimension. Use it to answer "how much traffic did the site get" and "what are the top pages/referrers/countries" style questions; use the timeseries endpoint when you need values over time instead. `startAt` and `endAt` are Unix epoch milliseconds; optional filter parameters (path, referrer, country, event, UTM fields, ...) narrow the data. Without `dimension` the response carries the totals alone. With `dimension` (e.g. `path` for top pages, `referrer` for top referrers, `country` for top countries) the response also carries `rows`: up to `limit` (default 25, max 1000) values of that dimension ranked by page views, each with its own engagement totals. Requires a plan that includes analytics (403 otherwise); all-zero totals until the website is published and has traffic.'
tags:
- Analytics
parameters:
- name: websiteId
in: path
required: true
schema:
type: string
minLength: 1
- name: startAt
in: query
required: true
schema:
type: integer
minimum: 0
maximum: 9007199254740991
- name: endAt
in: query
required: true
schema:
type: integer
minimum: 0
maximum: 9007199254740991
- name: path
in: query
required: false
schema:
type: string
- name: referrer
in: query
required: false
schema:
type: string
- name: title
in: query
required: false
schema:
type: string
- name: query
in: query
required: false
schema:
type: string
- name: browser
in: query
required: false
schema:
type: string
- name: os
in: query
required: false
schema:
type: string
- name: device
in: query
required: false
schema:
type: string
- name: country
in: query
required: false
schema:
type: string
- name: region
in: query
required: false
schema:
type: string
- name: city
in: query
required: false
schema:
type: string
- name: language
in: query
required: false
schema:
type: string
- name: hostname
in: query
required: false
schema:
type: string
- name: tag
in: query
required: false
schema:
type: string
- name: event
in: query
required: false
schema:
type: string
- name: distinctId
in: query
required: false
schema:
type: string
- name: utmSource
in: query
required: false
schema:
type: string
- name: utmMedium
in: query
required: false
schema:
type: string
- name: utmCampaign
in: query
required: false
schema:
type: string
- name: utmContent
in: query
required: false
schema:
type: string
- name: utmTerm
in: query
required: false
schema:
type: string
- name: segment
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: cohort
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: dimension
in: query
required: false
schema:
description: Break the range down by this dimension, e.g. `path` for top pages, `referrer` for top referrers, `country` for top countries. Omit for totals only.
type: string
enum:
- path
- entry
- exit
- title
- query
- referrer
- channel
- domain
- country
- region
- city
- browser
- os
- device
- language
- screen
- event
- hostname
- tag
- distinctId
- name: limit
in: query
required: false
schema:
default: 25
description: Maximum number of dimension rows to return (default 25, max 1000). Only used when `dimension` is set.
type: integer
minimum: 1
maximum: 1000
responses:
'200':
description: Engagement totals for the range, plus ranked `rows` when a `dimension` was requested.
content:
application/json:
schema:
type: object
properties:
pageviews:
type: number
description: Total page views.
visitors:
type: number
description: Distinct visitors.
visits:
type: number
description: Visits (sessions).
bounces:
type: number
description: Single-page visits.
totaltime:
type: number
description: Total time spent in seconds, summed across visits.
comparison:
description: Totals for the comparison period, present when the provider computes one.
type: object
properties:
pageviews:
type: number
description: Total page views.
visitors:
type: number
description: Distinct visitors.
visits:
type: number
description: Visits (sessions).
bounces:
type: number
description: Single-page visits.
totaltime:
type: number
description: Total time spent in seconds, summed across visits.
required:
- pageviews
- visitors
- visits
- bounces
- totaltime
additionalProperties: false
rows:
description: Values of the requested `dimension` ranked by page views, each with its own engagement totals. Present only when `dimension` is set.
type: array
items:
type: object
properties:
name:
type: string
description: Dimension value, e.g. the URL path, referrer domain, or country code.
pageviews:
type: number
description: Total page views.
visitors:
type: number
description: Distinct visitors.
visits:
type: number
description: Visits (sessions).
bounces:
type: number
description: Single-page visits.
totaltime:
type: number
description: Total time spent in seconds, summed across visits.
required:
- name
- pageviews
- visitors
- visits
- bounces
- totaltime
additionalProperties: false
required:
- pageviews
- visitors
- visits
- bounces
- totaltime
additionalProperties: false
'400':
description: Validation failed. The response `message` names the first invalid field.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'401':
description: Missing, invalid, expired, or revoked API key.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'403':
description: The authenticated principal lacks the required capability.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'404':
description: The resource does not exist or is outside the principal’s access scope.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'429':
description: Rate limit exceeded. Retry after the number of seconds in the `Retry-After` header.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
x-cactal-required-capability: websiteAnalytics.view
x-cactal-read-only: true
x-cactal-destructive: false
x-cactal-idempotent: true
servers:
- url: https://api.cactal.ai/v1
/websites/{websiteId}/analytics/timeseries:
get:
operationId: websiteAnalytics.timeseries.get
summary: Get an analytics time series
description: 'Returns one traffic time series bucketed by `unit` (`year`, `month`, `day`, `hour`, or `minute`). `series` selects which: `pageviews` returns parallel `pageviews` and `sessions` arrays with one point per time bucket (and accepts `compare` — `prev` or `yoy` — to request comparison data for the previous period or year), while `events` returns tracked custom-event counts as one `events` point per event name per time bucket. Only the requested series'' fields are present in the response. `startAt` and `endAt` are Unix epoch milliseconds; `timezone` is an IANA name (e.g. `America/New_York`) that controls bucket boundaries; optional filter parameters narrow the data. The series is capped to the most recent `maxPoints` time buckets (default 30, max 500); a `truncated` field reports when the cap was applied. Requires a plan that includes analytics (403 otherwise); empty until the website is published and has traffic.'
tags:
- Analytics
parameters:
- name: websiteId
in: path
required: true
schema:
type: string
minLength: 1
- name: startAt
in: query
required: true
schema:
type: integer
minimum: 0
maximum: 9007199254740991
- name: endAt
in: query
required: true
schema:
type: integer
minimum: 0
maximum: 9007199254740991
- name: path
in: query
required: false
schema:
type: string
- name: referrer
in: query
required: false
schema:
type: string
- name: title
in: query
required: false
schema:
type: string
- name: query
in: query
required: false
schema:
type: string
- name: browser
in: query
required: false
schema:
type: string
- name: os
in: query
required: false
schema:
type: string
- name: device
in: query
required: false
schema:
type: string
- name: country
in: query
required: false
schema:
type: string
- name: region
in: query
required: false
schema:
type: string
- name: city
in: query
required: false
schema:
type: string
- name: language
in: query
required: false
schema:
type: string
- name: hostname
in: query
required: false
schema:
type: string
- name: tag
in: query
required: false
schema:
type: string
- name: event
in: query
required: false
schema:
type: string
- name: distinctId
in: query
required: false
schema:
type: string
- name: utmSource
in: query
required: false
schema:
type: string
- name: utmMedium
in: query
required: false
schema:
type: string
- name: utmCampaign
in: query
required: false
schema:
type: string
- name: utmContent
in: query
required: false
schema:
type: string
- name: utmTerm
in: query
required: false
schema:
type: string
- name: segment
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: cohort
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: unit
in: query
required: true
schema:
type: string
enum:
- year
- month
- day
- hour
- minute
- name: timezone
in: query
required: false
schema:
type: string
minLength: 1
- name: maxPoints
in: query
required: false
schema:
default: 30
type: integer
minimum: 1
maximum: 500
- name: series
in: query
required: true
schema:
type: string
enum:
- pageviews
- events
description: 'Which time series to return: `pageviews` for page views and sessions per bucket, `events` for tracked custom-event counts per event name per bucket.'
- name: compare
in: query
required: false
schema:
description: 'Request comparison data alongside the primary series: `prev` for the previous period, `yoy` for the same range one year earlier. Only valid when `series` is `pageviews`.'
type: string
enum:
- prev
- yoy
responses:
'200':
description: 'The requested time series: `pageviews` and `sessions` per bucket, or `events` per event name per bucket.'
content:
application/json:
schema:
type: object
properties:
pageviews:
description: Page views per time bucket. Present only when `series` is `pageviews`.
type: array
items:
type: object
properties:
x:
type: string
description: Start of the time bucket.
y:
type: number
description: Count in the bucket.
required:
- x
- y
additionalProperties: false
sessions:
description: Distinct sessions per time bucket. Present only when `series` is `pageviews`.
type: array
items:
type: object
properties:
x:
type: string
description: Start of the time bucket.
y:
type: number
description: Count in the bucket.
required:
- x
- y
additionalProperties: false
events:
description: One point per event name per time bucket. Present only when `series` is `events`.
type: array
items:
type: object
properties:
x:
type: string
description: Event name.
t:
type: string
description: Start of the time bucket.
y:
type: number
description: Number of events in the bucket.
required:
- x
- t
- y
additionalProperties: false
truncated:
description: Present only when the series exceeded `maxPoints` and was capped to the most recent time buckets.
type: object
properties:
shown:
type: integer
description: Time buckets returned.
total:
type: integer
description: Time buckets the range produced.
hint:
type: string
description: How to retrieve the rest.
required:
- shown
- total
- hint
additionalProperties: false
additionalProperties: false
'400':
description: Validation failed. The response `message` names the first invalid field.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'401':
description: Missing, invalid, expired, or revoked API key.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'403':
description: The authenticated principal lacks the required capability.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'404':
description: The resource does not exist or is outside the principal’s access scope.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'429':
description: Rate limit exceeded. Retry after the number of seconds in the `Retry-After` header.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
x-cactal-required-capability: websiteAnalytics.view
x-cactal-read-only: true
x-cactal-destructive: false
x-cactal-idempotent: true
servers:
- url: https://api.cactal.ai/v1
/websites/{websiteId}/analytics/realtime:
get:
operationId: websiteAnalytics.realtime.get
summary: Get a realtime traffic snapshot
description: 'Returns a compact snapshot of traffic over Umami''s trailing 30-minute realtime window: total page views, distinct visitors, tracked custom events, and distinct countries, plus the snapshot timestamp. The visitor total is not directly comparable to the removed `active` endpoint''s five-minute count. Use it to see recent activity; use the query endpoint for historical ranges. Requires a plan that includes analytics (403 otherwise); all-zero totals until the website is published and has traffic.'
tags:
- Analytics
parameters:
- name: websiteId
in: path
required: true
schema:
type: string
minLength: 1
responses:
'200':
description: Traffic totals for the trailing 30-minute window.
content:
application/json:
schema:
type: object
properties:
views:
type: number
description: Page views in the trailing 30-minute window.
visitors:
type: number
description: Distinct visitors in the trailing 30-minute window.
events:
type: number
description: Tracked custom events in the trailing 30-minute window.
countries:
type: number
description: Distinct countries in the trailing 30-minute window.
timestamp:
type: string
description: Snapshot time as an ISO 8601 timestamp.
required:
- views
- visitors
- events
- countries
- timestamp
additionalProperties: false
'400':
description: Validation failed. The response `message` names the first invalid field.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'401':
description: Missing, invalid, expired, or revoked API key.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'403':
description: The authenticated principal lacks the required capability.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'404':
description: The resource does not exist or is outside the principal’s access scope.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
'429':
description: Rate limit exceeded. Retry after the number of seconds in the `Retry-After` header.
content:
application/json:
schema:
$ref: '#/components/schemas/ServiceError'
x-cactal-required-capability: websiteAnalytics.view
x-cactal-read-only: true
x-cactal-destructive: false
x-cactal-idempotent: true
servers:
- url: https://api.cactal.ai/v1
components:
schemas:
ServiceError:
type: object
required:
- kind
- message
description: Canonical error body returned by every non-2xx response. Extra fields carry error-specific details.
properties:
kind:
type: string
enum:
- validation
- unauthorized
- forbidden
- not_found
- conflict
- rate_limited
- internal
description: Stable, machine-readable error category.
message:
type: string
description: Human-readable explanation of the failure.
suggestion:
type: string
description: What to do next when the failure has a known fix; may name the exact operation to call.
validValues:
type: array
items:
type: string
description: The acceptable values for the failing field, when the set is closed.
additionalProperties: true
securitySchemes:
apiKey:
type: http
scheme: bearer
description: Cactal API key. Create one in the dashboard or via `POST /apiKeys`. The plaintext key is shown once at creation.
x-refined-from:
- openapi.json
- cactal-ai-openapi.json