Docs menu · REST API

Docs › Developers

REST API

Everything the dashboard shows comes from the same public API. Authentication, periods and filters, errors, and every endpoint.

The dashboard has no private API: everything it shows comes from the public API at https://nvivio.com/v1. Whatever you see in the dashboard, your own tools can fetch too.

Authentication

Send an API key as a bearer token:

curl -H "Authorization: Bearer nv_…" "https://nvivio.com/v1/sites"
  • Keys belong to an organisation, with the scope read (the default) or admin. A read key cannot change anything.
  • You see the full key once; only its hash is stored.
  • Make and revoke keys in the user menu › API and AI assistants (/app/api), as owner or admin. Each connected AI assistant has its own key in the list.
  • Or through the API: POST /v1/orgs/{org}/keys with {"name": "Reporting", "scopes": ["read"]}, list them with GET, revoke with DELETE /v1/orgs/{org}/keys/{id}. Your organisation id is in GET /v1/me.

Managing a team is only possible as a signed-in person, never with an API key, so a leaked key cannot hand out access.

Try it without a key

The numbers of the live demo can be read without a key, so you can try the API right away:

curl "https://nvivio.com/v1/sites/acme.example/stats?period=30d&compare=previous"

This works for the demo’s numbers and visits only (stats, timeseries, breakdown, story, explain, insights, hours, ai, bots, sessions, realtime, goals, funnels and parts), read only, within a fair limit per visitor (status 429 with the code demo.too_many when you ask too much at once). The data is made up.

The site in a path

{site} in a path is the site code (NV-9Y5FVJQ) or the site’s domain (example.com). Without access to a site you get 404, not 403, so you do not learn that it exists.

Periods

period=today, yesterday, 24h, 7d (the default), 30d, month, lastmonth, year, 12mo or all, or from and to as ISO dates. Named periods follow the site’s time zone.

Filters

The filters from the dashboard’s address work unchanged: repeat f for each filter.

?f=country:BE&f=referrer:google.com&f=path:~/blog/*&f=device:!mobile

~ makes the value a pattern with *, ! negates the filter. Besides the dimensions: goal:<name>, label:<name>, min_actions:<number> and part:<name>. The full list is in Filters, periods and links. Copy the part after ? from the dashboard’s address and paste it into an API call.

Language

Texts the API writes itself (the story of a period, the explanation of a change, insights and error messages) follow Accept-Language or ?lang=nl, in the 24 EU languages. Without either, the API answers in English.

Errors

Every error has an error (what is wrong), a fix (how to solve it) and a stable code to compare on:

{
  "error": "Not logged in.",
  "fix": "Send \"Authorization: Bearer <api-key>\"; you can create keys at https://nvivio.com/app/api.",
  "code": "auth.not_logged_in"
}

Status codes: 400, 401, 403, 404, 409, 422 and 429.

Example

curl -H "Authorization: Bearer nv_…" \
  "https://nvivio.com/v1/sites/example.com/stats?period=30d&compare=previous"
{
  "visitors": 1240,
  "sessions": 1485,
  "pageviews": 3920,
  "views_per_visit": 2.64,
  "bounce_rate": 41.6,
  "avg_duration_s": 145,
  "previous": { "visitors": 1107, "sessions": 1320, "pageviews": 3580, "views_per_visit": 2.71, "bounce_rate": 43.2, "avg_duration_s": 139 },
  "bots_filtered": 812,
  "period": { "from": "2026-09-24T00:00:00.000Z", "to": "2026-10-24T09:12:00.000Z" }
}

(The numbers are an example.)

Endpoints

Your account

Method and path What it does
GET /me You, your organisations, your weekly email setting and your Overview layout.
PATCH /me weekly_mail (true or false) and/or dashboard: {"panels": [...], "hide": [...]}, a plain list of panels, or null for the default.
GET /me/weekly-mail The weekly email as it would go out now: subject, html and text.

Panels: metrics, parts, insights, findings, sources, pages, location, tech, hours, goals, visit, ai, events, campaigns, languages and domains. Parts to hide: headline; metrics.visitors, metrics.sessions, metrics.pageviews, metrics.views_per_visit, metrics.bounce_rate, metrics.avg_duration_s, metrics.chart; and the tabs sources.channel|referrer|utm_campaign, pages.path|entry|exit, location.country|map|region|city, tech.device|browser|os and campaigns.utm_source|utm_medium|utm_campaign.

Sites

Method and path What it does
GET /sites Your sites.
GET /sites/live Who is online now, per site.
GET /sites/periods?days=30&ids=NV-…,NV-… Totals and a daily (or weekly) series per site, up to 24 sites per request. days: 7, 30, 90 or 365.
POST /sites Add a site: org_id and domains, optionally name and mode.
GET /sites/{site} One site and its settings.
PATCH /sites/{site} Change name, domains, mode (privacy or cookie), track_links, hash_routes, excluded_ips or timezone.
DELETE /sites/{site} Delete the site.
DELETE /sites/{site}/data Delete all visits, events, labels and bots of the site.
GET /sites/{site}/install snippet (the script line), early_calls and ai_prompt.
GET /sites/{site}/parts, PUT /sites/{site}/parts The parts of a site, and their numbers with ?period=.

Numbers

All take a period and filters.

Method and path What it does
GET /sites/{site}/stats The six key figures; compare=previous adds the previous period.
GET /sites/{site}/timeseries The figures per interval: hour, day, week or month.
GET /sites/{site}/breakdown The top values of one dimension with their share. limit (default 10, up to 500), search, goal=<name> for conversions, compare=previous.
GET /sites/{site}/story The sentence about the period.
GET /sites/{site}/explain Why the numbers changed; compare=previous or compare=week.
GET /sites/{site}/insights What Nvivio noticed: insights (each with kind, tone, title, text, facts, link and sometimes action) and action, the first thing to do.
GET /sites/{site}/hours Visitors per weekday and hour.
GET /sites/{site}/ai AI assistants and AI crawlers, see AI.
GET /sites/{site}/bots Bots by group, with the previous period.

Dimensions: channel, referrer, utm_source, utm_medium, utm_campaign, entry, path, exit, event, country, region, city, lang, device, browser, os and hostname.

Visits

Method and path What it does
GET /sites/{site}/sessions Visits, newest first. limit (default 50, up to 200) and cursor; the answer has next_cursor.
GET /sites/{site}/sessions/{id} One visit with every step.
GET /sites/{site}/realtime Who is online now (up to 100) and per_minute for the last 30 minutes.
GET /sites/{site}/realtime/minute?at=<ISO time> What happened in one minute (up to 50 events).
PUT /sites/{site}/visitors/{id}/label Set a visitor’s label and note.

Goals and funnels

Method and path What it does
GET /sites/{site}/goals, POST /sites/{site}/goals Goals with their results; add a goal.
DELETE /sites/{site}/goals/{id} Delete a goal.
GET /sites/{site}/funnels, POST /sites/{site}/funnels Funnels; add a funnel.
GET /sites/{site}/funnels/{id}, DELETE /sites/{site}/funnels/{id} One funnel with its steps; delete it.

Bots from your server

Method and path What it does
GET /sites/{site}/bot-key The connection’s status (bot_key) and the address your server sends to (bot_endpoint).
POST /sites/{site}/bot-key Make a new key (shown once).
DELETE /sites/{site}/bot-key Remove the connection.

See Forward bots from your server.

Team and keys

Signed-in people only, not API keys.

Method and path What it does
GET /orgs/{org}/team Members, invitations and site access.
PATCH /orgs/{org}/members/{user}, DELETE … Change a role; remove someone or leave.
POST /orgs/{org}/invitations, DELETE /orgs/{org}/invitations/{id} Invite with email, role and optionally sites; withdraw.
GET /sites/{site}/access, POST /sites/{site}/access Access to one site; invite for one site.
PATCH /sites/{site}/access/{user}, DELETE … Change or remove access to one site.
DELETE /sites/{site}/invitations/{id} Withdraw an invitation for one site.
GET /orgs/{org}/keys, POST /orgs/{org}/keys, DELETE /orgs/{org}/keys/{id} API keys (owners and admins).