Goals and funnels
Goals
A goal is something a session can reach. Goals are evaluated on the server whenever a session
changes and stored on the session (goals[]), so goal filters and conversion rates are as fast as
any other filter.
| Match kind | Reached when | Example |
|---|---|---|
event | an event with this name (and, optionally, these exact prop values) happened | {"kind": "event", "event": "signup", "props": {"plan": "pro"}} |
page | a pageview of this page (exact) or below it (prefix) | {"kind": "page", "page": "/thank-you", "mode": "exact"} |
lead | a lead / identify() is linked to the session (optionally of one form) | {"kind": "lead", "form": "contact"} |
conversion | a server-side conversion is linked (optionally of one definition) | {"kind": "conversion", "definition": "booking"} |
Fields: key (snake_case, stable), name, match, isConversion (counts into converted and the
conversion rate), value (per converting session, in the project currency), sort, archived.
curl -X POST https://api.3x.example/v1/projects/$PROJECT/goals \
-H "Authorization: Bearer $X3_SECRET_KEY" -H "Content-Type: application/json" \
-d '{"key":"demo_booked","name":"Demo booked","match":{"kind":"event","event":"booking"},"isConversion":true,"value":250}'New projects start with three conversion goals: form_submit, booking and lead. The CPI preset
uses quiz_submit and booking, which makes converted identical to cpi-website2.
Changing goals bumps the project's goal version; a background job re-evaluates existing sessions (the same rescoring job as for relevance), so reports reflect the new definition retroactively.
Filters: goal=demo_booked (repeatable, all must be reached), converted=true|false. Breakdown
dimension goal. MCP tool analytics_goals and REST GET …/analytics/goals return per goal the
sessions reaching it, the rate and the value sum.
Funnels
A funnel is an ordered list of 2–20 steps. Step kinds:
| Kind | Step reached when |
|---|---|
sessions | always (use as the first step: every session of the filter) |
event | an event with this name (and props) |
page | a pageview of the page (exact / prefix) |
goal | the goal is reached |
answered | at least count distinct questions of a questionnaire were answered |
funnel_step | x3.funnelStep(funnel, step) was called with this step key |
Modes:
- independent – each step counts sessions that reached it, regardless of order; the share is relative to step 1. This is the cpi-website2 semantics (used by the CPI preset).
- sequential – a session counts for step n only if it reached steps 1…n−1 earlier in the session. Use it for real conversion paths.
Every step reports sessions, share of step 1 and rate from the previous step. One funnel per project is the default funnel shown on the overview.
{
"key": "signup",
"name": "Signup",
"mode": "sequential",
"steps": [
{ "key": "visit", "label": "Sessions", "match": { "kind": "sessions" } },
{ "key": "pricing", "label": "Pricing page", "match": { "kind": "page", "page": "/pricing", "mode": "exact" } },
{ "key": "form", "label": { "en": "Form started", "de": "Formular begonnen" }, "match": { "kind": "event", "event": "form_start" } },
{ "key": "done", "label": "Signed up", "match": { "kind": "goal", "goal": "signup" } }
]
}Questionnaires (quizzes)
A questionnaire describes a quiz or multi-step form: questions with option values and labels.
The quiz preset events (quiz_view, quiz_answer {variant, q, value}, quiz_contact,
quiz_submit) reference it by its id (variant). With tracking.questionnaires.strict, answers
that do not match a registered question and option are dropped at ingest – no free text can slip in.
GET …/analytics/answers (MCP analytics_answers) returns, per questionnaire, the funnel (viewed,
started, contact, submitted) and the distribution of the last answer per session and question,
in definition order with labels.
Where to define them
Dashboard Settings → Goals / Funnels / Questionnaires, REST (goals.*, funnels.*,
questionnaires.* in the API reference), or MCP (goals_create,
funnels_create, questionnaires_upsert, …).