REST API
People
Identified visitors on one of the current team's sites — a "site user" is created the moment your app calls identify() for a visitor (see Tracking & events). A site is addressed by {siteKey} (UUID or domain). All endpoints require Authorization: Bearer {token}.
These endpoints return real visitor data — identifier, name, avatar, and behavioral history — for the authenticated team's own visitors only. A site user always belongs to exactly one site; a foreign site user id returns 404, never another team's data.
Both endpoints accept the shared date range and filter query parameters. The date range scopes differently on each: on the list it selects who to return (people last seen in the window); on the profile it scopes the range-bound metrics and timeline, not which person is returned.
List site users
GET /api/sites/{siteKey}/stats/users
Paginated, identified site users last seen inside the resolved date range, ordered by last_seen_at descending. This is a paginated endpoint — it returns the standard data / meta / links envelope (see Conventions).
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
range |
string | No | Preset date range. See Date ranges. |
from |
string | No | Custom range start, Y-m-d. Requires to. |
to |
string | No | Custom range end, Y-m-d. Requires from. |
per_page |
int | No | Page size, 1–100. Default 25. |
Plus the shared filter keys, which narrow the behavioral metrics (pageviews, sessions, revenue, etc.) computed for each returned person.
Response — each item in data:
| Field | Type | Description |
|---|---|---|
id |
string (uuid) | Site user id. |
identifier |
string | The identifier passed to identify(). |
name |
string | null | Display name, if set. |
display_name |
string | Nickname derived from name/identifier for UI display. |
avatar |
string | null | Custom avatar value, if set. |
avatar_url |
string | Resolved avatar URL (custom, or generated from the identifier). |
first_seen_at |
string (ISO 8601) | When this person was first tracked. |
last_seen_at |
string (ISO 8601) | When this person was last tracked. |
country |
string | Country of their most recent event in range. |
device |
string | Device type of their most recent event in range. |
os |
string | OS of their most recent event in range. |
browser |
string | Browser of their most recent event in range. |
source |
string | Last non-empty traffic source in range. |
referrer_domain |
string | Last non-empty referrer domain in range. |
pageviews |
int | Pageview count in range. |
sessions |
int | Distinct session count in range. |
spent |
int (cents) | Alias of revenue (kept for backward compatibility). |
revenue |
int (cents) | Verified payment revenue attributed to this person in range. |
recurring_revenue |
int (cents) | The portion of revenue flagged recurring. |
activity_days |
bool[7] | Whether this person was active on each of the trailing 7 days. |
tracked |
bool | Whether this person has any linked tracker visitor (false for a contact known only from a payment). |
Status: 200 OK.
curl "https://clickbase.so/api/sites/example.com/stats/users?range=last_30_days&per_page=50" \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
const params = new URLSearchParams({ range: 'last_30_days', per_page: '50' });
await fetch(`https://clickbase.so/api/sites/example.com/stats/users?${params}`, {
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
});
import requests
requests.get(
'https://clickbase.so/api/sites/example.com/stats/users',
params={'range': 'last_30_days', 'per_page': 50},
headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
)
{
"data": [
{
"id": "1f0a...",
"identifier": "user_42",
"name": "Jane Doe",
"display_name": "Jane Doe",
"avatar": null,
"avatar_url": "https://clickbase.so/avatars/....svg",
"first_seen_at": "2026-06-01T09:12:00.000000Z",
"last_seen_at": "2026-07-15T14:03:00.000000Z",
"country": "US",
"device": "desktop",
"os": "macOS",
"browser": "Chrome",
"source": "Google",
"referrer_domain": "google.com",
"pageviews": 42,
"sessions": 6,
"spent": 4900,
"revenue": 4900,
"recurring_revenue": 4900,
"activity_days": [false, true, false, false, true, false, false],
"tracked": true
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": null },
"meta": { "current_page": 1, "per_page": 50, "total": 1, "last_page": 1 }
}
Get a site user's profile
GET /api/sites/{siteKey}/stats/users/{siteUser}
A single visitor's profile: identity, range-scoped metrics, up to 8 device/browser session summaries, a ~26-week activity heatmap, and a 100-event timeline (newest first). Scoped to the team's own site — a {siteUser} id belonging to another site (or another team) returns 404.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
siteKey |
string | Yes | Site UUID or domain. |
siteUser |
string | Yes | Site user id. Must belong to siteKey's site, or 404. |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
range |
string | No | Preset date range scoping metrics/sessions/activity_heatmap/timeline. |
from |
string | No | Custom range start, Y-m-d. Requires to. |
to |
string | No | Custom range end, Y-m-d. Requires from. |
Plus the shared filter keys.
Response
| Field | Type | Description |
|---|---|---|
id |
string (uuid) | Site user id. |
identifier |
string | The identifier passed to identify(). |
name |
string | null | Display name, if set. |
display_name |
string | Nickname derived from name/identifier. |
avatar |
string | null | Custom avatar value, if set. |
avatar_url |
string | Resolved avatar URL. |
custom |
object | Custom traits passed via identify(). |
first_seen_at |
string (ISO 8601) | When this person was first tracked. |
last_seen_at |
string (ISO 8601) | When this person was last tracked. |
country |
string | Country of their most recent event in range. |
device |
string | Device type of their most recent event in range. |
os |
string | OS of their most recent event in range. |
browser |
string | Browser of their most recent event in range. |
source |
string | Last non-empty traffic source in range. |
referrer_domain |
string | Last non-empty referrer domain in range. |
metrics.pageviews |
int | Pageview count in range. |
metrics.sessions |
int | Distinct session count in range. |
metrics.spent |
int (cents) | Alias of metrics.revenue. |
metrics.revenue |
int (cents) | Verified payment revenue attributed to this person in range. |
metrics.recurring_revenue |
int (cents) | The portion of metrics.revenue flagged recurring. |
metrics.duration_seconds |
int | Average session duration (first-to-last pageview span) in range. |
sessions |
array | Up to 8 device/browser groupings, ordered by event count desc. Each: label (string), device (string), browser (string), os (string), events (int). |
tracked |
bool | Whether this person has any linked tracker visitor. |
activity_heatmap |
bool[182] | Daily activity flags for the trailing ~26 weeks, oldest first. |
timeline |
array | Up to 100 recent events, newest first. Each: timestamp (string), event_type (string), event_name (string), path (string), title (string), url (string), browser (string), os (string), device (string), country (string), referrer (string), referrer_domain (string), source (string), hostname (string), properties (object, string values), label (string, human-readable summary), kind (string: pageview, event, or found). |
Status: 200 OK. 404 Not Found when siteUser does not belong to siteKey's site.
curl "https://clickbase.so/api/sites/example.com/stats/users/1f0a1b2c-..." \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"
await fetch('https://clickbase.so/api/sites/example.com/stats/users/1f0a1b2c-...', {
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
});
import requests
requests.get(
'https://clickbase.so/api/sites/example.com/stats/users/1f0a1b2c-...',
headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
)