Docs/REST API
REST API
Read the analytics of every site in your account from your own scripts, dashboards or spreadsheets.
Authentication
Create a key in Settings → API keys. It is shown once; only a hash is stored, so a lost key is revoked and replaced, never recovered. Send it as a bearer token:
curl https://kipstats.com/api/v1/sites \
-H "Authorization: Bearer ks_your_api_key"A key reads every site of the account that created it. Revoking it takes effect immediately.
Base URL and format
https://kipstats.com/api/v1 — JSON in, JSON out, all dates in UTC. A machine-readable description lives at /api/v1/openapi.json (OpenAPI 3.1).
Rate limits
1000 requests per hour per key. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). Over the limit the API answers 429 with a Retry-After header.
Errors
{
"statusCode": 404,
"statusMessage": "Site not found"
}| Status | Meaning |
|---|---|
400 | A parameter is malformed — the message says which. |
401 | Missing, invalid or revoked key. |
404 | That site does not belong to this account. |
429 | Rate limit exceeded. |
Common parameters
| Parameter | Values |
|---|---|
period | today, 24h, 7d (default), 30d, 90d, month, 12mo |
from / to | YYYY-MM-DD (whole days, UTC) or ISO 8601. Overrides period. 400 days max. |
limit | 1 to 100 (breakdowns), default 10 |
country, browser, device, referrer, page | Filters. page matches entry pages containing the string. |
traffic | humans (interaction proven), bots (declared robots), all (default) |
The {site} segment accepts whichever identifier you have at hand: the domain (example.com), the tracking ID (kp_1a2b3c4d) or the internal ID.
Endpoints
| Endpoint | Returns |
|---|---|
GET /sites | Every site of the account. |
GET /sites/{site}/stats | Visitors, pageviews, sessions, bounce rate, average duration. compare=previous adds the previous period and the % change. |
GET /sites/{site}/timeseries | The same over time. Hourly up to 2 days, daily beyond. event=signup returns that event's series instead. |
GET /sites/{site}/breakdown/{dimension} | Top values of a dimension (below). |
GET /sites/{site}/friction | Rage clicks, dead clicks, JS errors and abandoned form fields, ranked. |
GET /sites/{site}/realtime | Visitors active in the last 5 minutes. |
Dimensions: pages, exit-pages, referrers, channels, countries, browsers, os, devices, events, utm_source, utm_medium, utm_campaign, utm_term, utm_content.
Filters apply to session-based dimensions. pages and events are counted from their own tables and ignore them — the numbers are right, they are just not filtered.
Examples
# last 30 days, compared to the 30 before
curl -H "Authorization: Bearer $KIPSTATS_API_KEY" \
"https://kipstats.com/api/v1/sites/example.com/stats?period=30d&compare=previous"
# top pages of a custom range
curl -H "Authorization: Bearer $KIPSTATS_API_KEY" \
"https://kipstats.com/api/v1/sites/example.com/breakdown/pages?from=2026-08-01&to=2026-08-31&limit=25"
# humans only, from France
curl -H "Authorization: Bearer $KIPSTATS_API_KEY" \
"https://kipstats.com/api/v1/sites/example.com/stats?traffic=humans&country=FR"Response shapes
{
"site": "example.com",
"period": { "from": "2026-08-17T09:12:03.000Z", "to": "2026-09-16T09:12:03.000Z" },
"data": {
"visitors": 4821,
"pageviews": 11934,
"sessions": 6210,
"bounceRate": 47,
"avgDuration": 96
},
"previous": {
"period": { "from": "2026-07-18T09:12:02.999Z", "to": "2026-08-17T09:12:02.999Z" },
"data": { "visitors": 4410, "pageviews": 10802, "sessions": 5730, "bounceRate": 51, "avgDuration": 88 }
},
"change": { "visitors": 9, "pageviews": 10, "sessions": 8, "bounceRate": -8, "avgDuration": 9 }
}{
"site": "example.com",
"period": { "from": "…", "to": "…" },
"dimension": "channels",
"total": 6210,
"data": [
{ "channel": "Search", "sessions": 3120, "percent": 50.2 },
{ "channel": "Direct", "sessions": 1890, "percent": 30.4 },
{ "channel": "AI assistants", "sessions": 640, "percent": 10.3 }
],
"aiAssistants": [
{ "source": "ChatGPT", "sessions": 402 },
{ "source": "Perplexity", "sessions": 238 }
]
}{
"site": "example.com",
"period": { "from": "…", "to": "…" },
"data": {
"rageClicks": [
{ "path": "/checkout", "element": "Pay now", "sel": "button.pay", "count": 34 }
],
"deadClicks": [
{ "path": "/pricing", "element": "Compare plans", "sel": "span.link", "count": 12 }
],
"jsErrors": [
{ "message": "Cannot read properties of null", "src": "/_next/static/chunk.js:1", "path": "/checkout", "count": 8 }
],
"formAbandons": [
{ "path": "/signup", "form": "form#register", "field": "company_vat", "count": 21 }
],
"totals": { "rageClicks": 4, "deadClicks": 9, "jsErrors": 2, "formAbandons": 6 }
}
}Writing
This API reads. To record a fact from your server — a payment, a webhook — use the ingest endpoint with the site's own key: server-side events.