For developers
Stats API
1 Quick start
- In Visitics open Organization → API and create a key; it is shown only once — keep it on your server.
- Send it in the Authorization header of every request.
- Ask for a section of the dashboard of one of your sites:
curl -H "Authorization: Bearer vtk_…" "https://www.getvisitics.com/api/v1/stats?site=example.com§ion=overview&days=30"The API returns aggregated numbers only — never IP addresses, fingerprints, form contents or chat transcripts. Locations carry the attribution of DB-IP (CC BY 4.0); keep it with the data.
2 Keys and permissions
A key belongs to an organization and reads, it never changes anything. When you create it, you choose its permissions, the sites it may read (all, or some) and whether it expires.
| Permission | Allows |
|---|---|
stats:read | The sites, the sections of the dashboard and the visitors right now. |
export:read | The tables of the sections as CSV or JSON. |
A key belongs on a server: the API does not answer browsers of other sites (no CORS). Never put a key into an address — it would stay in logs and histories. A key that leaked is revoked in one click and stops working at once.
3 Limits and caching
The plan decides the requests an hour of a key: Aura 600, Luna 3,000, Cosmos 10,000. Every answer tells how many are left:
| Header | Meaning |
|---|---|
RateLimit-Limit | Requests an hour of the plan. |
RateLimit-Remaining | Requests left in the current hour. |
RateLimit-Reset | Seconds until a request leaves the window. |
X-Request-Id | The request's ID — quote it when you write to support. |
ETag | Send it back in If-None-Match: the same answer comes as 304 Not Modified. |
Retry-After | Seconds to wait after a 429 answer. |
The numbers of today change through the day, the days before stay. Keep an answer for a minute at least, and ask with If-None-Match — an unchanged answer costs nothing to send.
4 Errors
An error comes as problem details (RFC 9457) with a machine code in code and the request's ID — quote it when you write to us.
{
"type": "https://www.getvisitics.com/developers/api/#error-site_not_found",
"title": "Site not found",
"status": 404,
"detail": "The key has no site example.org.",
"code": "site_not_found",
"request_id": "3f9c2a1b7d4e8f60"
}| code | HTTP | Meaning |
|---|---|---|
unauthorized | 401 | The Authorization header is missing, or the key is unknown, revoked or expired. |
insufficient_scope | 403 | The key exists but lacks the permission the request needs (stats:read, export:read). |
site_not_found | 404 | No such site, or the key may not read it (a key can be limited to some sites). |
not_found | 404 | No such endpoint. |
method_not_allowed | 405 | The API only reads: use GET (or HEAD). |
invalid_section | 400 | section is not one of the dashboard sections. |
invalid_key | 400 | key is not a table of the section (the problem lists the allowed ones). |
invalid_format | 400 | format is neither csv nor json. |
rate_limited | 429 | Over the plan's requests an hour; Retry-After says when to try again. |
over_limit | 402 | The organization was over its plan's pageviews two whole months: the data waits for a bigger plan, as in the dashboard. |
suspended | 423 | The organization is suspended (or being deleted): its data is not read through the API. |
5 Versions and changes
Version 1 only changes compatibly: new fields and new parameters may come, nothing is taken away or renamed. A field you do not know, ignore. An end of a version would be announced 12 months ahead with the Deprecation and Sunset headers and by e-mail to the owners of the keys.
6 GET /sites
The sites the key may read
{
"data": [
{
"domain": "example.com",
"name": "Example shop",
"timezone": "Europe/Bratislava",
"created_at": "2026-10-01T08:15:00Z"
}
]
}7 GET /sites/{domain}
One site
| Parameter | Type | Description |
|---|---|---|
domain required |
string |
{
"data": {
"domain": "example.com",
"name": "Example shop",
"timezone": "Europe/Bratislava",
"created_at": "2026-10-01T08:15:00Z"
}
}8 GET /stats
A section of the dashboard — The numbers of one section for a period, with the previous period of the same length for comparison (`kpi.prev`). The fields are those of the dashboard; new fields may be added.
| Parameter | Type | Description |
|---|---|---|
site required |
string | The site's domain as in the dashboard. |
section |
string: overview | behavior | sources | audience | conversions | funnels | ux | speed (overview) | A section of the dashboard. |
days |
integer (30) | The last N days including today in the site's time zone (the plan decides which periods are allowed; the longest one otherwise). Ignored with from and to. |
from |
string | The first day (YYYY-MM-DD), with to. Cut to the plan's history and to at most a year. |
to |
string | The last day (YYYY-MM-DD), with from; at most today. |
scope |
string (all) | A part of the site: all, or a group of pages defined in the dashboard (group:<name>). |
funnel |
integer | section=funnels: the funnel's ID from the dashboard. |
{
"site": {
"domain": "example.com",
"name": "Example shop"
},
"section": "overview",
"timezone": "Europe/Bratislava",
"range": {
"from": "2026-10-16",
"to": "2026-10-22",
"days": 7,
"prev_from": "2026-10-09",
"prev_to": "2026-10-15",
"today": "2026-10-22"
},
"kpi": {
"cur": {
"visitors": 342,
"views": 762,
"conversions": 14,
"bounce_rate": 0.17
},
"prev": {
"visitors": 370,
"views": 752,
"conversions": 16,
"bounce_rate": 0.18
}
},
"series": {
"dates": [
"2026-10-16",
"2026-10-17"
],
"total": [
58,
41
]
},
"pages": [
{
"path": "/products/",
"views": 183,
"visitors": 153
}
],
"sources": [
{
"source": "Google",
"channel": "search",
"visitors": 146
}
]
}9 GET /realtime
Visitors right now — Visitors in the last 5 minutes and the pages they are on.
| Parameter | Type | Description |
|---|---|---|
site required |
string | The site's domain as in the dashboard. |
{
"data": {
"visitors": 16,
"window_seconds": 300,
"pages": [
{
"path": "/products/",
"visitors": 5
}
]
}
}10 GET /export
A table of a section as CSV or JSON — The rows of one table — for spreadsheets and BI tools. Tables by section: overview: pages, sources, channels, countries; behavior: pages, entries, exits, search, not_found; sources: sources, referrers, campaigns, channels; audience: countries, regions, cities, langs; conversions: events, goal_sources, forms, outbound, downloads; funnels: funnel.steps, funnel.by_channel, funnel.by_device; ux: ux_pages, ux_elements, js_errors; speed: vitals_pages.
| Parameter | Type | Description |
|---|---|---|
site required |
string | The site's domain as in the dashboard. |
section |
string: overview | behavior | sources | audience | conversions | funnels | ux | speed (overview) | A section of the dashboard. |
key required |
string | The table. |
format |
string: csv | json (csv) | |
days |
integer (30) | The last N days including today in the site's time zone (the plan decides which periods are allowed; the longest one otherwise). Ignored with from and to. |
from |
string | The first day (YYYY-MM-DD), with to. Cut to the plan's history and to at most a year. |
to |
string | The last day (YYYY-MM-DD), with from; at most today. |
scope |
string (all) | A part of the site: all, or a group of pages defined in the dashboard (group:<name>). |
source,channel,visitors
Google,search,146