Docs

Relevance score

Every session gets a relevance score between 0 and 100 that says how close it came to being a lead. It turns "1,200 sessions from campaign A" into "38 hot sessions from campaign A" – the number that matters for ad spend. Scores are computed on the server after every ingest with the project's relevance model, and the same function renders the "why this score" explanation, so the stored score and its explanation can never disagree.

The default model

SignalPoints
Forced 100quiz submitted, meeting booked, form submitted, confirmed server-side conversion
Forced 0 (floor)engaged < 3 s and none of: interactive click, video start, quiz answer, CTA, WhatsApp, calculator, quiz contact step
Engaged time≥ 10 s +5 · ≥ 30 s +10 · ≥ 60 s +15 · ≥ 180 s +20 (highest reached)
Scroll≥ 90 % +10 · ≥ 50 % +7 · else left the first screen +3
Pages2 pages +5 · ≥ 3 pages +10
Videostarted +8 · watched ≥ 30 s +10 · ≥ 50 % covered +7 · completed +10
Interactive clicks+2 each, at most +8
CTA click+10
Calculator used+15
Quizviewed +2 · first answer +25 · each further answer +5 (max +20) · contact step +15
WhatsApp click+40
Identified (identify() or a lead)+30 in new projects (0 in the CPI preset)

The sum is capped at 100. The CPI preset (relevance v1) reproduces the cpi-website2 model exactly – a property test over 20 000 random sessions proves it.

Tiers and thresholds

TierScore
cold0–9
interested10–29
engaged30–59
hot60–89
lead90–100

KPIs use two thresholds: engaged+ (≥ 30) and hot+ (≥ 60). Ad cost per relevant session uses settings.ads.relevantMinScore (default 30).

Customizing the model

Edit it under Settings → Relevance, with PUT /v1/projects/{project}/relevance, or the MCP tool relevance_update_config. A model is JSON (RelevanceConfig):

{
  "schema": 1,
  "forced": { "flags": ["quiz_submitted", "booked", "form_submit", "confirmed_conversion"], "events": ["trial_started"], "goals": [] },
  "floor": { "engagedMsBelow": 3000, "interactions": ["int_clicks", "video", "cta_click"], "events": ["pricing_toggle"] },
  "engaged": [[180, 20], [60, 15], [30, 10], [10, 5]],
  "scroll": { "steps": [[90, 10], [50, 7]], "foldScrolled": 3 },
  "pages": [[3, 10], [2, 5]],
  "video": { "started": 8, "watched": { "seconds": 30, "points": 10 }, "coverage": { "pct": 50, "points": 7 }, "completed": 10 },
  "intClicks": { "each": 2, "max": 8 },
  "flags": { "cta_click": 10, "calculator": 15, "quiz_viewed": 2, "quiz_contact": 15, "whatsapp": 40, "identified": 30 },
  "quizAnswers": { "first": 25, "furtherEach": 5, "furtherMax": 20 },
  "events": [{ "event": "pricing_toggle", "points": 5, "each": 2, "max": 9, "label": "Compared plans" }],
  "goals": [{ "goal": "pricing_page", "points": 10 }],
  "tiers": [{ "key": "cold", "min": 0 }, { "key": "interested", "min": 10 }, { "key": "engaged", "min": 30 }, { "key": "hot", "min": 60 }, { "key": "lead", "min": 90 }],
  "thresholds": { "engagedPlus": 30, "hotPlus": 60 }
}
  • events rules: points for the first occurrence, each for every further one, at most max in total. Works with built-in and custom events.
  • goals rules add points when the session reached a goal (Goals and funnels).
  • forced.events / forced.goals force 100 – use them for your real conversions.
  • Tiers: 2–8 tiers, the first starts at 0, minimums increase; labels optional ({"en": …, "de": …}).

Preview before saving

POST /v1/projects/{project}/relevance/preview scores up to 10 000 recent sessions in memory with a proposed model and returns the tier distribution and examples. Nothing is stored.

Versioning and rescoring

Every saved model is a new immutable version. Saving sets the project's current version and starts retroactive rescoring: a background job rescores all sessions in chunks of 2 000, newest data first, and updates the daily rollups. Progress is shown in the project status (pendingSessions); until it reaches zero, sessions scored with an older version are flagged in the dashboard. A conversion recorded later (for example a WhatsApp lead marked via MCP) rescores its session immediately.

Why this score

The session view and the MCP tool sessions_get show the breakdown: each item with its points, the cap note when the sum exceeded 100, and whether the score was forced (conversion or floor).