Analytics
Every figure in the dashboard comes from one query catalogue, and the API exposes it as it is: you name a metric set, a dimension and a few numbers, and UsherStats writes the query. There is no SQL to send and nothing to escape. The dashboard reads through these same routes.
All of them need the analytics:read scope. A site in another workspace, or outside a token's site restriction, is
404.
| Route | Scope |
|---|---|
GET /v1/stats/catalogue | analytics:read |
GET /v1/sites/{id}/stats | analytics:read |
POST /v1/sites/{id}/stats/query | analytics:read |
POST /v1/sites/{id}/stats/batch | analytics:read |
GET /v1/sites/{id}/summary | analytics:read |
GET /v1/sites/{id}/top/{dimension} | analytics:read |
POST /v1/sites/{id}/internal-link | sites:write |
The examples assume $US_TOKEN holds a token with account:admin. First, a site to read:
curl https://api.usherstats.com/v1/sites \
-H "Authorization: Bearer $US_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Field notes", "hostnames": ["fieldnotes.example"]}'The catalogue
Four metric sets: pageviews (confirmed pageviews in a browser), sessions, requests (everything your server or
proxy answered, crawlers included) and events. Each lists its lanes (human, bot, internal), the dimensions
it can be broken down by, the filters it takes and the counts it can sort by.
curl https://api.usherstats.com/v1/stats/catalogue \
-H "Authorization: Bearer $US_TOKEN"One query
A spec is metrics and by, plus any of:
lane:human(People),bot(Crawlers) orinternal(your own team). Each metric set has a default.days(calendar days ending today;1is today so far, default7), orfromandto(YYYY-MM-DD).compare:trueaddsprevious, the period before (a single day is compared with the same weekday a week earlier), or says why it cannot be compared yet.where: filters, such as{"source": "google"}. In a query string,where.source=google.sort: which count a table is ranked by, such assessionsorpageviews.
Analytics Engine keeps 90 days; past that, UsherStats answers from the daily rollups each site keeps for as long as the account exists. Hourly series and page-to-page pairs are not rolled up, so they answer only within 90 days.
curl "https://api.usherstats.com/v1/sites/$SITE_ID/stats?metrics=pageviews&by=source&days=30&sort=sessions" \
-H "Authorization: Bearer $US_TOKEN"The same as JSON (the form an agent's tool call takes):
curl https://api.usherstats.com/v1/sites/$SITE_ID/stats/query \
-H "Authorization: Bearer $US_TOKEN" \
-H "Content-Type: application/json" \
-d '{"metrics": "requests", "by": "bot", "lane": "bot", "days": 7, "compare": true}'A name that is not on the catalogue's lists is 400, and field says which:
curl "https://api.usherstats.com/v1/sites/$SITE_ID/stats?metrics=pageviews&by=blob3" \
-H "Authorization: Bearer $US_TOKEN"Many queries at once
Up to 40 named specs in one call. A spec that is refused answers {"error": {"status": 400, "title": ...}} under
its name; the others still answer.
curl https://api.usherstats.com/v1/sites/$SITE_ID/stats/batch \
-H "Authorization: Bearer $US_TOKEN" \
-H "Content-Type: application/json" \
-d '{"queries": {"byDay": {"metrics": "pageviews", "by": "day", "days": 30}, "crawlers": {"metrics": "requests", "by": "category"}}}'The People summary
The People boxes as numbers: sessions, pageviews, from search, average session, bounce rate, single-page visits and
pages per session, each with the previous period's figure and the change. A change carries a tone: good or bad
where one direction is better (a lower bounce rate is better), flat when nothing moved.
curl "https://api.usherstats.com/v1/sites/$SITE_ID/summary?days=7" \
-H "Authorization: Bearer $US_TOKEN"Top tables
source, medium, referrer, campaign, page, page_type, country and device count People sessions (where
each began) or, with count=pageviews, pageviews. bot, category, kind, network, path, status, cache and
decision count requests; event counts events.
curl "https://api.usherstats.com/v1/sites/$SITE_ID/top/page?days=30&count=pageviews&limit=20" \
-H "Authorization: Bearer $US_TOKEN"curl "https://api.usherstats.com/v1/sites/$SITE_ID/top/bot?days=7" \
-H "Authorization: Bearer $US_TOKEN"Marking your own browser
Your team's visits belong in Internal, not People. Tools mark themselves with a signed header; a browser is marked
by opening a link on your site's own first-party path (/_us/, which the Worker SDK and the first-party proxy set
up). The link works for ten minutes, once per browser you open it in, and the mark lasts 90 days. POST /v1/sites/{id}/internal-link/rotate replaces the site's internal key, so every
browser marked before stops counting as yours (mark them again).
The link is made only for a hostname the site has verified (its TXT record, see sites) or serves in proxy mode: it sets a cookie on that domain. Verify it first:
curl -X POST https://api.usherstats.com/v1/sites/$SITE_ID/hostnames/fieldnotes.example/verify \
-H "Authorization: Bearer $US_TOKEN"curl https://api.usherstats.com/v1/sites/$SITE_ID/internal-link \
-H "Authorization: Bearer $US_TOKEN" \
-H "Content-Type: application/json" \
-d '{"hostname": "fieldnotes.example"}'See also goals and experiments, bot protection, search and export.