Skip to main content

Lead Scoring

Audience: Sales · Management · Support · QA · Engineering · Where in app: Settings → Lead Scoring (config); shown on Dashboard Hot Leads, Live Sessions, Recorded Sessions, Person Detail · Plan availability: All plans

Every visitor accumulates a lead score as they interact with the widget. Each meaningful action adds points; the more high-intent the action, the more it's worth. The score ranks visitors on the dashboard, drives hot-lead notifications, and can gate automation. It's a rule-based heuristic — a prioritization aid, not a guaranteed probability of conversion.

What it does

  • Adds points to a visitor as they take scored actions (visit a key page, share contact info, return, book, etc.).
  • Surfaces the highest scorers so teams act on the hottest visitors first.
  • Fires hot-lead notifications (Slack / email / FCM / webhook) when a visitor crosses the threshold.
  • Buckets scores into levels (Low / Medium / High / Very High) with badges and a fire icon for the hottest.

How it works

Two timelines run in parallel:

  1. Per sessionuser_sessions.lead_score accumulates as the visitor browses, chats, calls, and books.
  2. Per visitorvisitor_profiles carries a higher-level engagement_score over time.

Each scored signal is individually toggleable and weighted in companies.lead_score. When a visitor's total crosses the company's hot threshold, the notification fan-out fires.

Score levels (customer-facing)

LevelScore rangeMeaning
Low0–20Minimal engagement; just arrived or casual browse
Medium21–50A few meaningful actions; showing interest
High51–99Actively engaged, multiple high-intent actions
Very High100+Many high-value actions; likely ready to convert (gets a 🔥 fire icon)

Configuration & options

Per-signal weights

Configured under companies.lead_score. Each signal has a toggle (enabled: true/false), a numeric weight (typically 0–200), and a threshold where applicable.

SignalDefault weightFires when
visited_heigh_intent_page (spelling per schema)configurableVisitor lands on a page in high_value_pages[]
user_initiated_callconfigurableVisitor clicked call (not the AI starting it)
call_auto_connect_acceptedconfigurableVisitor accepted the call auto-trigger
chat_auto_connect_acceptedconfigurableVisitor accepted the chat auto-trigger
call_greater_thanconfigurable (+ seconds threshold)Call lasted longer than the threshold
chat_greater_thanconfigurable (+ seconds threshold)Chat lasted longer than the threshold
booked_meetinghighA booking was created (any source)
shared_emailmediumVisitor gave their email
shared_phonemediumVisitor gave their phone
industry_matchconfigurableVisitor's company/domain matches companies.knox.target_market
product_searchedconfigurableVisitor searched a product (ecommerce RAG)
returned_visitor50At least the 2nd session (heavy on purpose)
pages_visited_exceeded50Session pages > lead_score.pages_visited_threshold
notification_sentconfigurableA notification has already fired for this visitor

Exact non-50 defaults (booked_meeting / shared_email / shared_phone / the configurable signals) are tenant-tunable and the shipped numeric defaults should be confirmed against CompanyModel's lead_score schema — verify before quoting precise numbers. The two firmly-documented defaults are returned_visitor = 50 and pages_visited_exceeded = 50.

SettingDefaultEffect
companies.lead_score.thresholdconfigurableThe implicit hot-lead threshold; crossing it fires notifications
lead_score.pages_visited_threshold3Pages-per-session above which pages_visited_exceeded (+50) fires
call_greater_than / chat_greater_than secondsconfigurableDuration thresholds for those signals
companies.knox.high_value_pages[]Pages that trigger visited_heigh_intent_page
companies.knox.target_marketIndustry tag matched for industry_match

Editing weights (QA/support)

Settings → Lead Scoring (admin-side). Each signal exposes a toggle, a numeric weight (typically 0–200), and a threshold where relevant. If a tenant says "scoring looks wrong," check which signals are enabled, their weights, and whether high_value_pages[] is polluted with low-intent pages.

Hot-lead notification channels

When the threshold is crossed, the system can: send a Slack message (if notifications.slack_hot_lead = true), send an email, push via FCM, and fire a webhook (hot_lead_identified; also lead_score_changed). Routed via SlackService, FcmService, EmailQueueService in backend.

Behaviors & edge cases

  • Anonymous visitors accumulate score normally; the score moves to their PersonProfile once identified.
  • returned_visitor only fires across a session boundary (1+ hour gap) — multiple sessions same day are still separate for scoring, but the return bonus needs the gap. The +50 weight often pushes a known visitor over the line on visit 2.
  • AI-only conversations count — accepting an AI auto-trigger is an explicit engagement signal.
  • Score is rule-based, not a learned conversion probability. A Low-score visitor can still be a great customer (early in research).
  • Score can climb mid-session — a Medium → High jump while browsing is a real-time buying signal.
  • Misconfigured high_value_pages[] pollutes scoring — keep low-intent pages out of it.

Plan & limits

  • Lead scoring is available on all plans; weights and thresholds are tenant-configurable.
  • Defaults work out of the box but need tuning per business — one tenant's "hot" is not another's. Signals that depend on enrichment (industry_match) or ecommerce search (product_searched) only fire if those features/integrations are active.

Technical implementation

  • Config: companies.lead_score (per-signal weights + threshold + pages_visited_threshold) on CompanyModel.
  • Accumulator: user_sessions.lead_score (per-session rolling total) in ms-sessions; visitor_profiles.engagement_score (lifetime) updated by the recording-analysis rollup.
  • Notifications: backend SlackService / FcmService / EmailQueueService; webhook events hot_lead_identified, lead_score_changed.
  • Score visibility surfaces: Dashboard → Hot Leads (top-N, server-paginated, sort by total), Live Sessions (badge per row), Recorded Sessions (detail), Identity → Person Detail (per session + lifetime), and webhook payloads.
  • Nox tools: knox-visitor-profile, knox-stats(metric=hot_leads), knox-aggregate(metric=hot_leads) — current score, which signals fired, hottest leads this week, and why a visitor isn't ranking (signal breakdown).
  • Subsystems: feeds Identity Graph and Session Recording signals.