REST API

Sessions & journeys

Read a site's visitor sessions and their timelines, explore the paths visitors take (Sankey flow, journey funnel, path exploration), and read cohort retention. A site is addressed by {siteKey} (UUID or domain). All endpoints require Authorization: Bearer {token}.

These are reporting reads: they accept the same date-range inputs (range/from/to) and dashboard dimension filters (country, path, browser, …) documented in Conventions — read that page for the preset range values, the filter key allowlist, the response envelope, and the shared error codes. Only the pieces unique to sessions, journeys, and retention are documented below.

List sessions

GET /api/sites/{siteKey}/sessions

One row per visitor session — the HTTP twin of the web Sessions report. Paginated: keeps the standard data/meta/links envelope at a fixed page size of 25 (?page= only, no ?per_page=).

Path parameters

Parameter Type Required Description
siteKey string Yes Site UUID or domain.

Query parameters

Parameter Type Required Description
range string No Preset range. See Conventions. Default today.
from / to string No Custom range, Y-m-d. Takes precedence over range when both are valid.
country, path, … string / string[] No Dashboard dimension filters. See Conventions.
identified_only bool No Only include sessions with a known user_id (an identified visitor).
min_pageviews int No Only include sessions with at least this many pageviews. Default 0 (no floor).
min_events int No Only include sessions with at least this many custom events (pageviews and the automatic engagement beacon never count). Default 0.
min_duration int No Only include sessions lasting at least this many seconds. Default 0.
page int No Page number.

Each row is aggregated over the resolved range and filters — unlike the session timeline below, whose aggregate covers the whole session regardless of range/filters. A session whose only in-range activity is the automatic engagement beacon is excluded (not a real session).

Response — each item in data:

Field Type Description
session_id string (uuid) Session id.
visitor_id string (uuid) The visitor who owns this session.
user_id string Identified user id; empty string when anonymous.
site_user_id string (uuid) | null The resolved site user profile id, if any.
display_name string Same display name the People/Users list shows for this visitor.
avatar_url string Same avatar URL the People/Users list shows for this visitor.
is_identified bool Whether user_id is set.
started_at string (ISO 8601) Timestamp of the session's first in-range event.
ended_at string (ISO 8601) Timestamp of the session's last in-range event.
duration int Seconds between started_at and ended_at.
pageviews int Pageview count.
events int Custom event count (excludes pageviews and the engagement beacon).
entry_path string Path of the first pageview; empty string if the session has no pageview.
exit_path string Path of the last pageview; empty string if the session has no pageview.
country string Last-seen country.
region string Last-seen region.
city string Last-seen city.
language string Last-seen browser language.
browser string Last-seen browser name.
browser_version string Last-seen browser version.
os string Last-seen OS name.
os_version string Last-seen OS version.
device string Last-seen device type.
screen_width int Last-seen screen width in pixels.
screen_height int Last-seen screen height in pixels.
source string Attributed source at session entry.
channel string Attributed channel at session entry.
referrer_domain string Referring domain at session entry.

Status: 200 OK.

curl "https://clickbase.so/api/sites/example.com/sessions?range=last_7_days" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
await fetch('https://clickbase.so/api/sites/example.com/sessions?range=last_7_days', {
  headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
});
requests.get(
    'https://clickbase.so/api/sites/example.com/sessions',
    params={'range': 'last_7_days'},
    headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
)

Get a session timeline

GET /api/sites/{siteKey}/sessions/{sessionId}

One session's aggregate plus its paged chronological event timeline — the HTTP twin of the web Sessions expand-detail.

By design, the session aggregate here covers the WHOLE session, not just the resolved range/filters (there is no range/filters input on this endpoint) — different from the list row above, which is range/filter-scoped. The two can therefore report different numbers for the same session.

Path parameters

Parameter Type Required Description
siteKey string Yes Site UUID or domain.
sessionId string (uuid) Yes Session id.

Query parameters

Parameter Type Required Description
limit int No Events page size, 1–100. Default 100.
offset int No Events page offset. Default 0.

Response

Field Type Description
session object | null The session's aggregate — same fields as a list row plus utm_source, utm_medium, utm_campaign, utm_term, utm_content, referrer, and ip (always an empty string — not stored past ingest). null when the session id is unknown on this site.
events array This page of the session's chronological events (see below). Empty when session is null.
pagination object total (int, events in the whole session, excluding the engagement beacon), limit, offset, has_more (bool).

Each entry in events:

Field Type Description
timestamp string (ISO 8601) When the event happened.
event_type string pageview or event.
event_name string Custom event name; empty for a pageview.
path string Page path.
title string Page title.
url string Full page URL.
referrer string Referring URL for this event.
hostname string Hostname the event was recorded on.
properties object (string => string) Custom event property map.

Status: 200 OK (a null session still returns 200, not 404, unless the site itself is foreign to the team).

curl "https://clickbase.so/api/sites/example.com/sessions/{sessionId}?limit=50" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
await fetch(`https://clickbase.so/api/sites/example.com/sessions/${sessionId}?limit=50`, {
  headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
});
requests.get(
    f'https://clickbase.so/api/sites/example.com/sessions/{session_id}',
    params={'limit': 50},
    headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
)

Journey flow (Sankey)

POST /api/sites/{siteKey}/journey/flow

The top most-followed FULL visitor sequences, steps columns deep — feeds the dashboard's Sankey diagram. POST because the request carries a stepFilters payload, not because it writes anything.

IMPORTANT — filter transport. Dashboard dimension filters (country, path, …) ride the query string here, exactly like every other reporting read — never the request body. Sending a query, filters, or filter key in the JSON body is rejected with 422 Unprocessable Entity (a validation error naming that field) rather than being silently ignored, so a client mistake fails loudly instead of quietly returning unfiltered data.

Path parameters

Parameter Type Required Description
siteKey string Yes Site UUID or domain.

Body parameters

Parameter Type Required Description
steps int No Number of columns in the flow, 2–10. Default 4. (Not an array of step objects — see the funnel/next-steps endpoints below for that shape.)
limit int No Max number of journeys returned, 1–500. Default 50.
range / from / to string No Date range. See Conventions.
stepFilters object (string => string) No Per-column filter, keyed by 0-based step index (as a string, e.g. "0") to a pattern. A pattern containing * is a glob (* matches one path segment, ** matches many); otherwise it's a case-insensitive substring match. Each pattern max 2048 chars.
query / filters / filter Forbidden Rejected with 422 — see above. Use query-string filters instead.

Response

{
    "journeys": [
        {
            "path": [
                { "type": "pageview", "value": "/" },
                { "type": "pageview", "value": "/pricing" }
            ],
            "visitors": 42,
            "percentage": 12.5
        }
    ]
}
Field Type Description
journeys[].path array Ordered list of {type, value} steps, one per column. type is pageview or event; value is the path or event name.
journeys[].visitors int Visitors who followed this exact truncated sequence.
journeys[].percentage float visitors as a percentage of all visitors in the filtered/ranged population, rounded to 1 decimal.

Status: 200 OK (422 when a body filter key is sent, or steps/limit are out of bounds).

curl -X POST https://clickbase.so/api/sites/example.com/journey/flow \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"steps": 3, "range": "last_7_days"}'
await fetch('https://clickbase.so/api/sites/example.com/journey/flow', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
  body: JSON.stringify({ steps: 3, range: 'last_7_days' }),
});
requests.post(
    'https://clickbase.so/api/sites/example.com/journey/flow',
    json={'steps': 3, 'range': 'last_7_days'},
    headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
)

Journey funnel

POST /api/sites/{siteKey}/stats/journey/funnel

Cumulative per-step visitor counts across an ad hoc sequence of steps — the same funnel chart component the saved Funnels report uses, run over free-form steps instead of a saved funnel's goal list. Same query-string-only filter rule as Journey flow above: a query/filters/filter body key is rejected with 422.

Body parameters

Parameter Type Required Description
steps array Yes At least 2 entries: {type: "pageview" | "event", value: string}.
direction string Yes forward or backward.
range/from/to string No Date range. See Conventions.

Response

{
    "steps": [
        {
            "label": "/",
            "visitors": 100,
            "dropoff": 0,
            "dropoff_percentage": 0.0,
            "conversion_rate": 100.0,
            "conversion_rate_step": 100.0
        },
        {
            "label": "/pricing",
            "visitors": 40,
            "dropoff": 60,
            "dropoff_percentage": 60.0,
            "conversion_rate": 40.0,
            "conversion_rate_step": 40.0
        }
    ]
}
Field Type Description
steps[].label string The step's own input value.
steps[].visitors int Visitors who reached this step (cumulative — a subset of every prior step).
steps[].dropoff int Visitors lost versus the previous step (step 1 is always 0).
steps[].dropoff_percentage float dropoff as a percentage of the previous step's visitors.
steps[].conversion_rate float visitors as a percentage of step 1's visitors.
steps[].conversion_rate_step float visitors as a percentage of the previous step's visitors.

Status: 200 OK (422 when fewer than 2 steps, an unrecognized direction, or a body filter key).

curl -X POST https://clickbase.so/api/sites/example.com/stats/journey/funnel \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"direction": "forward", "steps": [{"type": "pageview", "value": "/"}, {"type": "pageview", "value": "/pricing"}]}'
await fetch('https://clickbase.so/api/sites/example.com/stats/journey/funnel', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
  body: JSON.stringify({
    direction: 'forward',
    steps: [
      { type: 'pageview', value: '/' },
      { type: 'pageview', value: '/pricing' },
    ],
  }),
});
requests.post(
    'https://clickbase.so/api/sites/example.com/stats/journey/funnel',
    json={
        'direction': 'forward',
        'steps': [
            {'type': 'pageview', 'value': '/'},
            {'type': 'pageview', 'value': '/pricing'},
        ],
    },
    headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
)

Journey path exploration

POST /api/sites/{siteKey}/stats/journey/next-steps

GA4-style "Path Exploration": the events that came immediately after (forward) or before (backward) a given step prefix, ranked by visitor count. Omit steps (or send an empty array) for the entry column — each visitor's first (forward) or last (backward) event in the range. Same query-string-only filter rule as the endpoints above: a query/filters/filter body key is rejected with 422.

Body parameters

Parameter Type Required Description
steps array No {type: "pageview" | "event", value: string} entries forming the prefix. Omit/empty for the entry column.
direction string Yes forward or backward.
search string No Case-insensitive substring match against the candidate label.
limit int No Max candidates returned, 1–200. Default 50.
range/from/to string No Date range. See Conventions.

Response — a flat JSON array (not wrapped in an object) of:

Field Type Description
type string pageview or event; end for the synthetic terminal bucket (see is_end).
value string The path or event name; empty for the terminal bucket.
label string Same as value (kept for parity with the request step shape); empty for the terminal bucket.
visitors int Visitors matching this candidate.
is_goal bool Whether this candidate exactly matches one of the site's goals (event goals by name, page goals by exact path — a scroll goal never flags a candidate).
is_end bool true for the synthetic bucket counting prefix-matching visitors whose journey stopped (forward) or started (backward) there, with no further neighbor in that direction.

Status: 200 OK (422 on an unrecognized direction or a body filter key).

curl -X POST https://clickbase.so/api/sites/example.com/stats/journey/next-steps \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"direction": "forward", "steps": [{"type": "pageview", "value": "/"}]}'
await fetch('https://clickbase.so/api/sites/example.com/stats/journey/next-steps', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
  body: JSON.stringify({ direction: 'forward', steps: [{ type: 'pageview', value: '/' }] }),
});
requests.post(
    'https://clickbase.so/api/sites/example.com/stats/journey/next-steps',
    json={'direction': 'forward', 'steps': [{'type': 'pageview', 'value': '/'}]},
    headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
)

Retention cohorts

GET /api/sites/{siteKey}/retention

Cohort retention: visitors are grouped by the period (day or week) of their first-ever event, then each cohort's activity is tracked forward, period by period. Retention has no dimension filters — only the date range and mode.

Path parameters

Parameter Type Required Description
siteKey string Yes Site UUID or domain.

Query parameters

Parameter Type Required Description
range/from/to string No Date range. See Conventions. Defaults to last_30_days on this endpoint (cohorts need a multi-period window).
mode string No day or week. Any other or missing value falls back to week.

Response

{
    "cohorts": {
        "2026-06-29": {
            "size": 120,
            "percentages": [100.0, 42.5, 30.0, null]
        }
    },
    "maxPeriods": 3,
    "mode": "week"
}
Field Type Description
cohorts object Keyed by the cohort's period start date (Y-m-d — the Monday of the ISO week in week mode, the calendar date in day mode).
cohorts.{period}.size int Visitors whose first-ever event fell in this cohort's period.
cohorts.{period}.percentages array (float | null) 0-indexed by periods since the cohort started (percentages[0] is always 100). null when there's no data for that many periods out for this cohort — either the period hasn't been reached yet, or nobody in the cohort returned. Every cohort's array is padded to the same length, maxPeriods + 1.
maxPeriods int The highest period offset with any data, across every cohort.
mode string The resolved day/week mode.

Status: 200 OK.

curl "https://clickbase.so/api/sites/example.com/retention?mode=day&range=last_30_days" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
await fetch('https://clickbase.so/api/sites/example.com/retention?mode=day&range=last_30_days', {
  headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' },
});
requests.get(
    'https://clickbase.so/api/sites/example.com/retention',
    params={'mode': 'day', 'range': 'last_30_days'},
    headers={'Authorization': f'Bearer {token}', 'Accept': 'application/json'},
)