Integrations · read-only JSON API
Web analytics API: every figure as JSON, read-only
The web analytics API in Skald serves the same JSON files the dashboard reads, to a script, a spreadsheet or another tool, with a token. Nothing is counted again, and nothing can be changed through it.
A web analytics API lets a program read a site's traffic figures without the dashboard. Skald's answers every figure as JSON at /traffic-api/v1/<site>/<file>, rewritten every 2 minutes, with each day's state first: a day that failed its checks has no figures, and a figure not recorded is null, never 0. One of the Skald integrations.
30-day free trial · no card · we set it up within one working day · free to self-host
$ curl -H "Authorization: Bearer <your-read-key>" \
https://stats.example.com/traffic-api/v1/example.com/overview
{"schema_version": 1, "site": "example.com",
"generated_at": "2026-10-08T07:16:02-04:00",
"days": [
{"day": "2026-10-05", "state": "withheld",
"problems": "the audit did not agree"},
{"day": "2026-10-06", "state": "ok",
"not_found_people": null, "server_errors": 0,
"visits": {"visits": 120, "views": 170}}]}
Sample answer, cut short. A withheld day has no figures; null is not recorded, 0 is none.
[01] the files
Analytics API endpoints, with the JSON they answer
Each file is one address. Pick one to see the call and a short piece of its answer. Every file starts with the same envelope: schema_version, generated_at, site, view and timezone.
pick a file
{"anchor": "2026-10-07", "first_day": "2026-09-01",
"days": [
{"day": "2026-10-05", "state": "withheld", "problems": "the audit did not agree"},
{"day": "2026-10-06", "state": "ok", "not_found_people": null, "server_errors": 0,
"visits": {"visits": 120, "views": 170, "one_page": 98, "median_seconds": 4}},
{"day": "2026-10-07", "state": "ok", "not_found_people": 9, "server_errors": 0,
"visits": {"visits": 140, "views": 190, "one_page": 118, "median_seconds": 3}}]}One entry per day for the last 180 days, oldest first. The 5th failed its check, so it has no figures. On the 6th, 404s were not recorded (null); server errors were counted and none were found (0).
{"stale": false, "state": "ok", "day": "2026-10-08",
"from": "2026-10-08T00:00:00-04:00", "until": "2026-10-08T13:00:16-04:00",
"requests": 14884, "groups": {"people": 3100}}Today so far, from the 2-minute snapshot. It is partial by nature: never add it to whole days. stale is true when the snapshot is not for today.
{"period": {"first": "2026-09-08", "last": "2026-10-07", "days": 30, "complete": true},
"pages": [
{"path": "/pricing/", "views": 640, "readers": 410, "visits": 455,
"entries": 212, "exits": 198, "exit_rate": 0.44,
"time_on_page_s": 38, "time_estimate": true,
"ai_asked": 57, "ai_training": 120, "search": 88, "change_pct": 12.5}]}Each page over the last 30 whole days. Time on page is an estimate and says so. exit_rate is null under 10 visits, and change_pct appears only when both periods are complete.
{"days": [
{"day": "2026-10-07", "state": "ok", "lines": 48210, "unparsed": 3,
"gaps": [], "verify": "ok",
"audit": {"state": "ok", "compared": 41, "problems": []}}]}Whether each day was read whole and passed both counts: the lines read, the lines no format could read, any gap of more than 10 minutes, and the second count's verdict.
{"enabled": true, "mail": true,
"open": [
{"id": "new_crawler-20261008130212-0", "cause": "new_crawler",
"subject": "ExampleAIBot", "severity": "low",
"title": "New crawler or assistant: ExampleAIBot",
"figure": 3, "threshold": 3, "opened_at": "2026-10-08T17:02:12Z"}],
"closed": []}Open alerts, newest first, and those closed in the last 30 days, each with its rule, figure and threshold.
Sample answers, cut short. The Connections page lists every file your site really has: visits, hourly, breakdowns, campaigns, bots, leads, conversions, funnels, health and more.
[02] read the state first
Withheld days and null values: read the day's state first
Every day carries a state. Check it before you use a figure. A withheld or missing day has no figures at all: leave it out of totals and say so, never count it as zero.
Not recorded is null, never 0. 0 means Skald counted and found none. Visits are an upper bound on people, and requests are never people.
| state | Figures? | What it means |
|---|---|---|
ok | Yes | A whole day that passed every check |
partial | Yes | Checked, but the logs did not cover the whole day. Never add it to whole days |
withheld | No | It failed a check. problems says why |
missing | No | Not collected |
before | No | Before your history starts |
[03] tokens
API tokens and scopes: read only what you need
An owner or admin makes a token on Settings › Team & access › Connections. It is shown once; Skald keeps only a fingerprint. It has no expiry: it works until it is revoked, or until the admin who made it leaves the team.
readReading figures: every figure the dashboard pages show, as JSON.
read_privateAlso the two files with visitor addresses, and one person's lookup. Each lookup is audit-logged.
mcpAn AI assistant through the MCP server. A read token alone cannot be used by an assistant.
ingestSending a site's log lines into Skald. It reads nothing.
[04] two ways in
The API addresses: with a token, or while signed in
Both ways show exactly the same files. A token is for a script. Signed in, your browser can take a quick look, and the address ending api/v1/ lists the files the page has.
<view> is a part of the site, such as us-english; leave it out for the whole site. The header must be exactly Authorization: Bearer followed by the token.
# with a token https://stats.example.com/traffic-api/v1/<site>/<file> https://stats.example.com/traffic-api/v1/<site>/<view>/<file> # signed in, in your browser https://stats.example.com/traffic/<site>/api/v1/<file> https://stats.example.com/traffic/<site>/api/v1/
$ curl -H "Authorization: Bearer <your-read-key>" \
https://stats.example.com/traffic-api/v1/example.com/us-english/pages
[05] answers
API errors, caching and rate limits
Answers are never cached. The files change every 2 minutes, so once every few minutes is plenty for a live screen, and once a day for a report. Skald sets no request limit of its own.
A field may be added without notice. One is never renamed or removed without a new schema_version.
| Status | When |
|---|---|
| 200 | The file |
| 401 | No token, a wrong or revoked one, a token for another site, a token without Reading figures, or a private file without Reading visitor addresses. error says which |
| 404 | The site, view or file does not exist: {"ok": false, "error": "no such file"} |
[06] what it does not do
What the Skald API does not do
It reads. That is the whole of it.
What it does not do
- It cannot write: no settings, no figures, no leads through the read API.
- It does not count again. A withheld day stays withheld; there is no figure to fetch for it.
- Most files hold the last 180 days. Two-range compare and one page's story answer only while signed in, not by token.
- On a server with one shared login, tokens are made on the server by whoever runs it, not on the page.
- Visits are at most this many people, never a count of people.
keep reading
More on web analytics API
questions
Web analytics API FAQ
Straight answers, including what Skald does not do.
Is the Skald API read-only?
Yes. It serves the same data files the dashboard reads. Nothing is counted again, and nothing can be changed through it: no setting, no figure, no lead.
How do I get a token for the Skald API?
An owner or admin opens Settings › Team & access › Connections and presses Set up on Read your figures (API). It makes a token for the site, shows it once, gives the address and a curl command, and tests it. Make a token by hand reads several sites or does several things.
Why is a figure null instead of 0?
Because Skald did not record it. 0 means Skald counted and found none; null means it was not recorded, for example on a day collected by an older version. In a spreadsheet keep null as an empty cell: turned into 0, it makes totals and averages wrong.
What does a withheld day mean in the API?
The day failed a check, so Skald shows no figures for it, and its problems field says why. Leave it out of totals and say so. A partial day has figures but did not cover the whole day: never add it to whole days or compare it with them.
How often do the API figures change, and is there a rate limit?
The files are rewritten every 2 minutes, and each says when in generated_at. Skald sets no request limit of its own, though whoever runs your server may add one. Asking more often than every 2 minutes gains nothing.
Can the API read visitor addresses?
Only with the Reading visitor addresses scope, which an admin ticks on purpose. It opens the two files that hold addresses, requests and ai_activity, and the person lookup. Each lookup goes to the audit log by its kind and a hash, never the value.
$ tail -f access.log | skald
See what AI does with your site. Free for 30 days.
No card. We set up hosted Skald for you within one working day, or you self-host it free. Every line of your log, sorted and added up.