Scoring Configuration
GTM Clarity scores every entity on two axes -- Fit (how well a prospect matches your ICP) and Engagement (how actively they interact with your brand). These combine into a unified score that places each entity into a quadrant tier.
Scoring configuration is stored per-tenant in the scoring_configs table and is fully customizable.
Scoring Pipeline Overview
Fit Configuration
Fit scoring measures how closely an account matches your Ideal Customer Profile. The configuration is defined by the FitConfig type:
ICP Profile
| Parameter | Type | Default | Description |
|---|---|---|---|
industries | string[] | [] | Target industries (exact match) |
minEmployees | number | 50 | Minimum employee count |
maxEmployees | number | 1000 | Maximum employee count |
minRevenue | number | 1,000,000 | Minimum annual revenue (USD) |
maxRevenue | number | 100,000,000 | Maximum annual revenue (USD) |
customAttributes | array | [] | Additional scored fields |
Custom Attributes
Custom attributes allow scoring on any field in the account data:
{
"customAttributes": [
{
"field": "technology_stack",
"values": ["Salesforce", "HubSpot", "Marketo"],
"weight": 15
},
{
"field": "region",
"values": ["North America", "EMEA"],
"weight": 10
}
]
}
Fit Dimension Weights
Weights control how much each dimension contributes to the overall fit score. They are expressed as percentages and should sum to 100:
| Dimension | Default Weight | Description |
|---|---|---|
industry | 30 | Industry match |
companySize | 25 | Employee count within range |
revenue | 25 | Annual revenue within range |
customAttributes | 20 | Custom field matches |
Engagement Configuration
Engagement scoring measures behavioral signals with time-based decay. The configuration is defined by the EngagementConfig type:
Core Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
decayHalfLifeDays | number | 30 | Days until signal value halves |
signalWeights | Record<string, number> | See below | Weight per activity type |
channelCaps | Record<string, number> | See below | Max score per channel |
qualityHierarchy | Record<string, number> | See below | Signal quality ranking (0-1) |
Signal Weights
Each activity type has a configurable weight. Default weights are all 1.0:
| Signal | Default Weight | Description |
|---|---|---|
demo_request | 1.0 | Demo or trial request |
form_fill | 1.0 | Form submission |
email_click | 1.0 | Email link click |
email_open | 1.0 | Email open |
page_view | 1.0 | Website page view |
ad_click | 1.0 | Advertisement click |
event_attend | 1.0 | Event attendance |
content_download | 1.0 | Content download |
meeting_attend | 1.0 | Meeting attendance |
Channel Caps
Channel caps prevent any single channel from dominating the engagement score:
| Channel | Default Cap | Description |
|---|---|---|
email | 30 | Email interactions |
web | 25 | Website activity |
ads | 15 | Advertising engagement |
events | 20 | Event participation |
content | 20 | Content consumption |
meetings | 25 | Meeting engagement |
other | 15 | Uncategorized |
Quality Hierarchy
The quality hierarchy assigns a multiplier (0-1) reflecting signal intent strength:
| Signal | Quality Score | Intent Level |
|---|---|---|
demo_request | 1.0 | Highest |
event_attend | 0.9 | Very High |
meeting_attend | 0.9 | Very High |
form_fill | 0.8 | High |
content_download | 0.7 | Medium-High |
email_click | 0.6 | Medium |
ad_click | 0.5 | Medium |
email_open | 0.4 | Low-Medium |
page_view | 0.2 | Low |
Decay Formula
Engagement scores decay exponentially over time:
decayed_score = raw_score * e^(-lambda * days_since_activity)
Where lambda = ln(2) / decayHalfLifeDays. With the default 30-day half-life, a signal loses 50% of its value after 30 days and approximately 75% after 60 days.
Set a shorter half-life (e.g., 14 days) for fast-moving sales cycles, or a longer one (e.g., 90 days) for enterprise deals with extended timelines.
Combined Weights
The combined score blends fit and engagement:
| Parameter | Default | Description |
|---|---|---|
fitWeight | 1 | Relative weight for fit |
engagementWeight | 1 | Relative weight for engagement |
The formula: combined = (fitScore * fitWeight + engagementScore * engagementWeight) / (fitWeight + engagementWeight)
Quadrant Thresholds and Tier Assignment
Entities are assigned to quadrants based on their fit and engagement scores:
| Quadrant | Fit | Engagement | Tier Label |
|---|---|---|---|
| Fast-Track | >= threshold | >= threshold | hot |
| Investigate | < threshold | >= threshold | warm |
| Nurture | >= threshold | < threshold | cool |
| Deprioritize | < threshold | < threshold | cold |
Default thresholds:
| Parameter | Default | Description |
|---|---|---|
fitThreshold | 50 | Fit score boundary |
engagementThreshold | 50 | Engagement score boundary |
hysteresisBand | 10 | Points beyond threshold needed to change tier |
Hysteresis
Hysteresis prevents entities from oscillating between tiers when scores hover near thresholds. An entity must move beyond the threshold by the full hysteresis band (default: 10 points) before changing tier. For example, a hot entity must drop below 40 (not just 49) to become cold.
Hysteresis is applied automatically by the TierAssigner class and is tracked in the score breakdown as hysteresisApplied: true/false.
Rollup Strategies
Account and opportunity scores are aggregated from their associated people scores:
Account Rollup
| Strategy | Description | Best For |
|---|---|---|
champion | Highest individual score wins (default, weight: 0.6) | Small buying groups |
weighted-average | All contacts contribute proportionally | Large accounts |
max-breadth | Rewards engagement breadth across contacts (cap: 1.5x) | Enterprise deals |
Opportunity Rollup
| Parameter | Default | Description |
|---|---|---|
fitSource | inherit-account | Inherit fit from parent account |
stageVelocityWeight | 0.1 | Weight for deal stage velocity |
contactEngagementStrategy | weighted-average | How contact scores aggregate |
Configuration Storage
Scoring configs are stored in the scoring_configs table:
| Column | Type | Description |
|---|---|---|
id | text (UUID) | Primary key |
tenant_id | text | Tenant scope |
type | text | fit, engagement, or combined |
config | jsonb | Full configuration object |
version | integer | Configuration version (default: 1) |
is_active | boolean | Whether this config is active |
Only one active configuration per type per tenant is allowed (enforced by a unique index on tenant_id + type). Changing the config creates a new version -- the old config is deactivated but retained for audit purposes.
Related Pages
- Architecture -- System-level scoring pipeline
- Tenant Setup -- Per-tenant configuration
- Database Schema -- Schema reference for
scoring_configsandengagements