Stats API
Read your analytics over HTTP. The same numbers the dashboard draws, as JSON, for a scheduled job, a warehouse load, or a report you assemble yourself.
Everything documented here is read-only. Queries return counts and rates; nothing you send changes your data or your settings. The API does have a write surface, for managing sites and keys, and it needs permissions this documentation's endpoints never ask for. The OpenAPI spec is the reference for it.
Base URL
Every path below is relative to it. Requests and responses are JSON.
Authentication
Each request carries a bearer key, created in the dashboard under Settings → API:
A request without a valid key is rejected with 401. See Authentication for creating keys, choosing their permissions, limiting one to a single site, and expiry.
Server-side only
An stbl_ key is a secret. Anyone holding it can read every site the key covers, so it belongs on a server, in a scheduled job, or in a local script, never in browser JavaScript where every visitor can read it.
The API enforces this: /api/v1 sends no CORS headers, so a cross-origin browser request cannot read the response. There is no browser-based flow in v1.
Endpoints
| Method | Path | Returns |
|---|---|---|
GET | /sites | The sites this key can read |
POST | /query | One analytics query: totals, a time series, or a breakdown |
GET | /current-visitors | Visitors active in the last five minutes |
GET | /props | Custom property keys a site has recorded |
GET | /funnels | Saved funnels for a site |
POST | /funnels/{id}/report | One saved funnel, step by step |
GET | /subscription | The account's plan state, in one line |
POST /query carries most of the surface. Metrics, dimensions, filters and date ranges all live there, and the other endpoints are narrower reads around it. Full grammar: Query reference.
First request
Start by discovering what the key can see:
{
"sites": [
{
"site_id": 3093477,
"name": "https://example.com/",
"timezone": "Europe/Amsterdam",
"stats_start_date": "2026-04-07",
"created_at": "2026-02-21T12:52:54Z"
}
]
}
Take site_id from there and ask a question:
curl -s -X POST https://statable.com/api/v1/query \
-H "Authorization: Bearer stbl_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"site_id": 3093477,
"metrics": ["visitors", "pageviews"],
"date_range": "7d"
}'
Dates and time buckets follow the site's own timezone, the one reported by /sites and set under Site settings → General.
Machine-readable spec
An OpenAPI 3.1 description of the API is served at:
It needs no key. Import it into Postman or Insomnia by URL, feed it to a client generator, or open it in an editor. Where prose and spec disagree, the spec is the contract.
Not in v1
Named so the boundaries are unambiguous:
- One site per query. No cross-site aggregation.
- One dimension per query at most.
- No bulk export. There is no CSV or archive download.
- Saved funnels only.
POST /funnels/{id}/reportruns a funnel that already exists; it takes an id, not a definition. - No cursor pagination. Breakdowns page with
limitandoffset.
Next steps
- Authentication: create a key, scope it, rotate it
- Query reference: metrics, dimensions, filters, date ranges
- Endpoints: sites, realtime, properties, funnels
- Rate limits: how many requests you get
- Errors: what each failure means
Ready to take control of your web analytics? Try Statable free for 30 days. No credit card required, full feature access, built for GDPR. Start your free trial or view a live demo.