Lead scoring hub → Salesforce template
Salesforce Lead Scoring Template: Custom Fields + Flow Builder
The 8 custom fields and 4 Flow Builder flows that run lead scoring across 127 audited B2B SaaS companies. Same data model as the HubSpot version, ported to Salesforce native automation.
A working Salesforce lead scoring system needs 8 custom fields (Fit_Score__c, Intent_Score__c, Total_Lead_Score__c, Lead_Tier__c, Last_Score_Update__c, Score_Decay_Pause__c, OwnerId, Last_High_Intent_Action__c) and 4 Flow Builder flows (Fit calculation, Intent calculation, daily recalc + decay, tier assignment).
Step 1: Create the 8 custom fields
Setup → Object Manager → Lead → Fields & Relationships → New. Apply the same fields to Contact (with conversion mapping) so post-conversion records keep their score history.
| Label | API name | Type | Notes |
|---|---|---|---|
| Fit Score | Fit_Score__c | Number(3, 0) | 0-50, sum of firmographic point values |
| Intent Score | Intent_Score__c | Number(3, 0) | 0-50, sum of behavioral point values, decays |
| Total Lead Score | Total_Lead_Score__c | Formula (Number) | Fit_Score__c + Intent_Score__c |
| Lead Tier | Lead_Tier__c | Picklist | Hot / Warm / Cold / Disqualified |
| Last Score Update | Last_Score_Update__c | DateTime | Updated on every Flow run |
| Score Decay Pause | Score_Decay_Pause__c | Checkbox | Manual override to freeze decay |
| Routing Owner | OwnerId (standard) | Lookup (User) | Assigned via Assignment Rule on tier |
| Last High-Intent Action | Last_High_Intent_Action__c | Text(80) | Audit trail for tier change |
Step 2: Flow #1 — Fit Score on firmographic change
Flow type
Record-Triggered Flow on Lead. Trigger: Updated. Entry condition: ISCHANGED(Industry) OR ISCHANGED(NumberOfEmployees) OR ISCHANGED(AnnualRevenue) OR ISCHANGED(Tech_Stack__c).
Action sequence
- • Industry in {SaaS, FinTech, HealthTech} → +12 points
- • NumberOfEmployees 50-500 → +10; 200-2000 → +12
- • AnnualRevenue $5M-$50M → +10
- • Tech_Stack__c contains core tool (HubSpot, Salesforce, Outreach, Gong) → +8
- • Country in {US, CA, UK, AU} → +5; EMEA non-UK → +3
Sum points into Fit_Score__c. Cap at 50. Use a Decision element with a Min function or an explicit IF(sum > 50, 50, sum).
Step 3: Flow #2 — Intent Score on behavior
Flow type
Record-Triggered Flow on Task (or your Behavior_Event__c custom object if MA pushes there). Trigger: Created. Entry condition: WhatId or WhoId matches a Lead.
Decision branches
- • Subject contains "Demo Request" → +15 + set
Last_High_Intent_Action__c= "demo_request" - • Subject contains "Pricing Page" AND Description count ≥ 3 → +12 + "pricing_revisit"
- • Subject contains "Case Study Download" → +10
- • Subject contains "ROI Calculator" → +10
- • Subject contains "Webinar Attended" → +8
- • Type = "Email Open" AND count in last 7 days ≥ 5 → +6
- • Subject contains "Unsubscribe" → set
Intent_Score__c= 0,Lead_Tier__c= "Disqualified"
Use the "Update Records" element with Intent_Score__c = Intent_Score__c + N rather than overwriting. Concurrent events stack.
Step 4: Flow #3 — Daily recalc + decay
Flow type
Scheduled Flow. Frequency: Daily. Time: 02:00 UTC. Object: Lead.
Filter
Score_Decay_Pause__c = false AND Last_High_Intent_Action_Date__c < TODAY() - 7.
Action
Intent_Score__c = ROUND(Intent_Score__c × 0.9, 0). After 60 days of no high-intent action, set Intent_Score__c = 0 and re-fire tier assignment.
Update Last_Score_Update__c = NOW().
Why intent expires covers the math behind the 0.9 multiplier and the 60-day cliff.
Step 5: Flow #4 — Tier assignment + Assignment Rule
Flow type
Record-Triggered Flow on Lead. Trigger: ISCHANGED(Total_Lead_Score__c).
Branches
- • Total_Lead_Score__c ≥ 80 → Lead_Tier__c = "Hot", Status = "SQL", trigger Assignment Rule "Hot Lead Round-Robin to AE", post Slack alert
- • 60-79 → Lead_Tier__c = "Warm", Status = "Working", assign to BDR queue, enroll in 24h cadence
- • 40-59 → Lead_Tier__c = "Cold", Status = "Open", marketing nurture
- • under 40 → Lead_Tier__c = "Disqualified", Status = "Closed - Not Converted", suppress outreach
Salesforce Assignment Rules have to fire from the Flow's "Reassign Lead Owner" action — they do not auto-fire on field updates by default.
The Slack alert payload should include: lead name + email, company, score breakdown, the triggering action (Last_High_Intent_Action__c), and a deep link to the Lead record. Without context, AEs ignore the alert.
Or skip the field-and-flow plumbing entirely
Salesforce was designed in 2010, and it shows in the scoring stack. 8 custom fields, 4 flows, validation rules, a separate scheduled flow because workflow rules don't run on a clock — that's a lot of admin time before you score a single lead. Set up scoring properties in Attio if you want a schemaless data model where Fit and Intent are first-class concepts and formula fields don't need workflow plumbing. Affiliate link.
Common mistakes
- Forgetting Lead-to-Contact field mapping. When MQLs convert, scores reset unless you map
Fit_Score__c,Intent_Score__c, andLead_Tier__cin the Lead Conversion field mapping. - Decay in workflow rules instead of Scheduled Flow. Workflow rules fire on save, not on a schedule. Decay needs Scheduled Flow.
- Routing via Assignment Rules without the explicit "Reassign Lead Owner" action. Assignment Rules don't fire automatically on field changes from Flow — you have to call them.
- Letting Einstein and the rule-based score race. Pick one for routing. Einstein in a separate field for sanity-checking, the rule-based score in
Total_Lead_Score__cfor action.
Frequently asked
Do I need Salesforce Sales Cloud Enterprise for this template?
Professional Edition works for the fields and basic assignment rules, but Flow Builder for the recalculation logic requires Enterprise or higher. If you're on Professional, you can build the same logic with Process Builder (deprecated but still functional) or with workflow rules — clunkier but it ships.
Can I run this on Lead and Contact objects, or just one?
Build it on Lead, then mirror the fields onto Contact for post-conversion scoring. Most teams forget the Contact mirror and lose all score history when MQLs convert to Contacts on opportunity creation. The conversion mapping has to copy fit_score__c, intent_score__c, and lead_tier__c forward.
How does this interact with Einstein Lead Scoring?
Einstein gives you a 0-100 score from a black-box ML model trained on your historical data. The custom-field model in this template is rule-based and explainable. Most teams keep both: Einstein in a separate field for sanity checks in dashboards, the rule-based score in Total_Lead_Score__c for routing. If you let Einstein drive routing, you can't tell AEs why a lead scored high — Einstein's reason codes are vague.
What's the right way to handle decay in Salesforce?
Scheduled Flow that runs nightly, queries leads where Last_High_Intent_Action__c is 7+ days old and Score_Decay_Pause__c = false, multiplies Intent_Score__c by 0.9. Don't try to do decay in workflow rules — they fire on record save, not on a schedule. Scheduled Flow is the only clean Salesforce-native option.
How do I keep this in sync with marketing automation?
Pardot, Marketo, and HubSpot all push behavior events into Salesforce as Tasks or custom objects. Wire your Intent Score Flow to fire on Task creation where Subject contains 'Form Fill', 'Page View', or 'Email Engagement'. The point allocations stay the same; only the trigger changes from native Salesforce events to MA-pushed Task events.
Related
- Lead scoring hub — the full Fit + Intent framework
- HubSpot version of this template
- Why intent expires
- BDR queue routing from lead scores
- Pain-First ICP Scoring