The AI lead scoring model template
The rubric the agent runs. Copy it, replace the ICP rules with yours, and check it against your last 40 closed-won deals before you point it at the database. Three components, explicit weights, a ceiling, a cap, and decay. Everything the 2021 points score was missing.
- industry in your ICP list: up to 30
- employee count in range: up to 25
- title and seniority match the buyer or champion: up to 30
- region you sell to, tech stack you integrate with: up to 15
- fit under 40 cannot reach tier A or B
- demo or pricing form submitted: 40
- pricing or competitor page visits in 30 days: up to 30
- hiring or funding signal for the roles you serve: up to 20
- attended a bottom-funnel event: up to 20
- replied to an email: 40
- opened 3+ emails in 14 days: up to 20
- repeat site visits in 30 days: up to 20
- attended a webinar or event in 90 days: up to 20
- nothing older than 30 days counts
- score = 0.5*fit + 0.3*intent + 0.2*engagement
- A: 75+ (named owner, Slack alert, 24h SLA) · B: 55-74 (SDR sequence) · C: 35-54 (nurture) · D: under 35 (leave alone)
- existing customer or open deal: tier X, route to the account owner, stop
- students, job seekers, competitors: tier D, say why in the reason
- every branch has a fallback owner; nothing has no owner
Weights are a starting point, not a verdict. Check the model against what actually closed before you trust it, and re-check monthly. The reason line is non-negotiable: a score that cannot explain itself is a score reps will ignore the first time it is wrong.
The stack
- Per lead
- one scoring call on a mid-tier model, a fraction of a cent
- Nightly pass
- hundreds to low thousands of changed records, a few dollars a night for most teams
- Backfill
- one-time; a 50,000-record database is a coffee-money job spread over a weekend
- CRM + Slack
- free over MCP, no scoring add-on or orchestration plan
The problem
Every CRM has a lead score, and almost nobody trusts it. It was built as a points system years ago: plus 10 for a director title, plus 5 for a webinar, minus 20 for a gmail address. Then the ICP moved, the webinar program died, and the score kept counting. Reps learned the number was noise and went back to triaging the queue by feel, which means the most expensive people on the team spend their mornings doing a spreadsheet's job.
The deeper problem is that a points score cannot explain itself. A rep sees '74' and has no idea whether that is a great-fit account with no intent or a poor-fit account that clicked six emails. So they open the record, read the activity, and form their own opinion, at which point the score has added zero information and thirty seconds. A score nobody can argue with is a score nobody uses.
I built one of these. It was a beautiful HubSpot score with fourteen weighted properties, signed off by sales, launched with a deck. Six months later I pulled the data: 61 percent of the leads reps had actually worked were in the bottom half of the score. The model was fine in the deck. It just measured a market that had moved on, and nobody, including me, had a reason to look at it again. A scoring model with no maintenance loop is a monument to the quarter it shipped.
A Claude agent fixes both failures. It scores on three named components, fit, intent, and engagement, each with its own sub-score, so a '74' becomes 'A-tier fit, no intent signal yet, engaged with pricing content twice this month.' It writes that reason to the record next to the score. And because it runs as a nightly Routine, re-scoring the whole database against the current ICP, the model stays honest without someone remembering to revisit it. Reps trust a score they can read, and they use a score that is right when it says hot.
How it works
- 01 Write the model Rubricfit, intent, engagement, weights, tiers
- 02 Pull the population HubSpot (MCP)changed in 30 days, in batches
- 03 Score + explain Claude Codethree sub-scores, a tier, one reason
- 04 Write back HubSpot (MCP)score, tier, reason, nothing else
- 05 Route by tier Claude Codecustomer branch first, then A/B/C/D
- 06 Post the movers Slack (MCP)A-tier arrivals to the owner, with reasons
- 07 Re-run nightly Claude Routinesdecay applies, model stays current
- You write the scoring model as a rubric: what fit means, which intent signals count, how engagement decays, and the weights between them
- A nightly Routine (or a scheduled Claude Code run) pulls every lead changed in the last 30 days from the CRM over MCP, in batches
- The agent scores each lead on fit, intent, and engagement, then combines them into a 0-100 score and a tier
- It writes score, tier, and a one-line reason back to three CRM properties, never touching anything else
- Your routing rules run off the tier: A-tier to a named owner, B-tier to a sequence, C-tier to nurture, with a fallback owner for anything odd
- Leads that crossed into A-tier overnight are posted to the owning rep in Slack with the reason, so the morning starts with the right ten names
See it run
The playbook
Write the model as a rubric, with three components and explicit weights
A lead score is a claim about who will buy, so start by writing the claim down in words before anyone touches a prompt. Three components cover nearly every B2B motion. Fit is whether the account and person look like your best customers: industry, size, region, title, tech stack. Intent is whether there is a reason to believe they are in-market now: a demo request, a pricing-page visit, a competitor evaluation, a hiring signal. Engagement is whether they are responding to you: opens, replies, event attendance, repeat visits, with a decay so a click from March stops counting in June.
Weight them for your motion. A product with a tight ICP and long cycles should weight fit at half or more, because a perfect-fit account with no intent is still worth a rep's attention. A high-velocity motion can lean on intent, because timing matters more than shape. Write the weights down as percentages that sum to 100, and write the tier cut-offs next to them. The model template below is the one I start from.
Pull your last 40 closed-won deals and check the model against them by hand before you automate anything. If a meaningful share of your actual customers would have scored C-tier under the rubric, the rubric is wrong, and you found out for free. This is the step the 2021 points system skipped.
TipCap any single signal so it cannot carry a lead into A-tier alone. Six email opens from a student should never outscore a VP at a dead-center account who has opened nothing. Fit sets the ceiling; intent and engagement move a lead inside it.
Expose the fields the agent scores on, and the three it writes
Connect the CRM to Claude over the HubSpot MCP connector (or Salesforce) and list, by exact property name, every field the model reads: industry, employee count, job title, lifecycle stage, last activity date, page views on high-intent pages, form submissions, email engagement. Custom properties are invisible until you name them, so the agent will score on the standard ones and miss your setup if you skip this.
Create three new properties for the agent to write: lead_score (number), lead_tier (A/B/C/D), and lead_score_reason (single-line text). Keep the existing HubSpot score alive alongside for a month so you can compare. Do not let the agent write anything else. The whole play is safe because its write surface is three fields, and every one of them is reversible.
Decide the population. Scoring every record in a 200,000-contact database nightly is wasteful and slow. Score everything once as a backfill, then nightly re-score only leads with any activity or property change in the last 30 days, plus anyone currently in A or B tier so decay applies. That keeps the run to hundreds or low thousands of records for most teams.
- Fit inputs: industry, employee count, region, job title, seniority, tech stack
- Intent inputs: demo/pricing form, pricing-page visits, competitor page visits, hiring or funding signals
- Engagement inputs: last email reply, opens in the last 14 days, event attendance, repeat site visits
- Context inputs: lifecycle stage, existing customer or open deal, owner
- Outputs (the only writes): lead_score, lead_tier, lead_score_reason
Give the agent the scoring brief
The scoring prompt is the rubric from step one, translated into instructions the agent applies identically to every record. It must return the three sub-scores, the combined score, the tier, and a one-sentence reason that cites the specific facts, in strict JSON, because the orchestrator writes those fields programmatically and free text cannot be written to a number property.
Two rules carry most of the weight. First, use only the data on the record; if a field is blank, treat it as neutral and say so in the reason, rather than guessing a company size from the name. Second, an existing customer or an open deal short-circuits the whole thing: the lead gets flagged, routed to the account owner, and excluded from new-business tiers. Cold-pitching a customer because a scoring model got excited is the one failure that costs more trust than every mis-scored lead combined.
Run the brief on 50 leads you already know well before you point it at the database. Read every reason line. When a reason is wrong, the fix is almost always a missing rule in the rubric, and it is far cheaper to find it in 50 records than in 50,000.
Score this lead using ONLY the fields provided. Do not infer missing values.
Lead: {{FULL_NAME}}, {{TITLE}} at {{COMPANY}}
Fit fields: industry={{INDUSTRY}}, employees={{EMPLOYEES}}, region={{REGION}}, tech={{TECH_STACK}}
Intent fields: demo_or_pricing_form={{FORM}}, pricing_visits_30d={{PRICING_VISITS}}, competitor_visits_30d={{COMP_VISITS}}, hiring_signal={{HIRING}}
Engagement fields: last_reply={{LAST_REPLY}}, opens_14d={{OPENS}}, events_90d={{EVENTS}}, site_visits_30d={{VISITS}}
Context: lifecycle={{LIFECYCLE}}, existing_customer_or_open_deal={{EXISTING}}
Scoring model:
- fit (0-100): {{ICP_RULES}}. Fit sets the ceiling: a lead with fit < 40 cannot be tier A or B.
- intent (0-100): {{INTENT_RULES}}. Cap any single signal at 40 points.
- engagement (0-100): {{ENGAGEMENT_RULES}}. Decay: nothing older than 30 days counts.
- score = 0.5*fit + 0.3*intent + 0.2*engagement, rounded.
- tier: A >= 75, B 55-74, C 35-54, D < 35.
Rules:
- If existing_customer_or_open_deal is true: set route_to_owner true, tier "X", and stop scoring.
- Blank fields are neutral. Never penalize a blank; note it in the reason.
- Students, job seekers, competitors, and agencies scoring on your behalf: tier D, say why.
Return JSON only:
{"fit": n, "intent": n, "engagement": n, "score": n, "tier": "A|B|C|D|X", "route_to_owner": bool, "reason": "<one sentence citing the specific fields that drove the score>"}
TipMake the reason cite fields, never adjectives. 'Strong fit, high intent' teaches a rep nothing. 'Director of RevOps at a 900-person fintech (fit 88), pricing page twice this week (intent 60), no reply yet (engagement 15)' is a reason they can argue with, and a score they can argue with is a score they will use.
Schedule the pass and write back in batches
Put the run on a nightly Claude Routine, or a scheduled Claude Code job if you want it in your own repo with your own logging. Either way the shape is the same: page through the changed-in-30-days population in batches of 50 to 100, score each record, write the three properties back over MCP, and log every write with the old and new tier so you can audit a week later. Batching with a pause between pages keeps you well inside CRM API limits; a loop that hammers 20,000 records in one burst is how you meet the rate limiter at 2am.
Treat tier changes as the interesting event, not the score itself. A lead moving from C to A overnight is news. A lead sitting at 71 for the fourth week is furniture. Have the run collect the movers into a short list and hand that to the routing step, and let everything else quietly update in the background.
Keep a kill switch. The Routine should read a single flag before writing anything, so a bad rubric change can be halted with one property flip rather than a frantic revert at 7am when the reps log in.
Route by tier, with the boring guardrails first
Routing is a set of rules that run off lead_tier, and the first rule is always the existing-customer branch: route_to_owner true goes to the account owner or CS and never to new business. Only after that do the tiers apply. A-tier goes to a named rep by territory or round-robin with a Slack alert and a 24-hour SLA. B-tier enters a sequence owned by an SDR. C-tier gets nurture. D-tier is left alone.
Give every branch a fallback owner. The leads that match no rule, a personal email at a huge company, a title the rubric has never seen, a region you do not sell to but that keeps requesting demos, are exactly the unusual ones that turn out to matter. A real human owns the fallback bucket and works it weekly. Build this before you build anything clever.
Post the overnight A-tier movers to each owner in Slack, with the reason line and a link to the record. That message is the product. A rep who opens Slack at 8am to 'six leads crossed into A overnight, here is why' starts the day on the right names instead of sorting a list view.
TipMake A-tier genuinely scarce. If a third of the database is A, reps stop believing the tier and go back to gut. A useful rule of thumb: A-tier should be small enough that every A lead gets a human touch within a day. If it is bigger than your team can work, the cut-off is too low.
Audit the model monthly against what actually closed
The reason the 2021 score died was nobody had a reason to look at it again. Build the reason in. Once a month, pull every deal created in the last 90 days and check the tier each lead carried the day the deal was created. If closed-won deals are coming out of C-tier, the fit rubric is too narrow. If A-tier is full of leads that never took a meeting, intent is over-weighted or a single signal is leaking through the cap.
Compare the agent's tier to the legacy HubSpot score for the first month and to rep behavior after that: which tiers did reps actually work, and what converted. Adjust weights in the rubric, re-run the 50-lead test set, and let the nightly Routine roll the change across the database. A model you can change in one file and re-score overnight is a model that stays honest.
Audit the D-tier, too. A mis-scored A-tier lead generates a complaint. A real buyer parked in D generates silence, because you never hear about the deal you did not get. Sample D-tier monthly for anyone who later became a customer or an opportunity. That number is the cost of the model, and it is the one nobody measures.
Inside the prompt
The scoring prompt is short, but every line is there for a reason. Here is what each one is doing and why.
- Use ONLY the fields provided"Do not infer missing values"
- Stops the model guessing a company size from a name. It scores what the CRM knows, not what it imagines.
- Fit sets the ceiling"fit < 40 cannot be tier A or B"
- The structural fix for the student-with-six-opens problem. Intent and engagement move a lead inside the fit ceiling, never above it.
- Cap any single signal"cap any single signal at 40 points"
- One pricing visit or one webinar should nudge, not decide. Caps keep a noisy signal from impersonating a buying committee.
- Decay"nothing older than 30 days counts"
- A click from March is not engagement in June. Decay is why nightly re-scoring matters: tiers fall as well as rise.
- Existing-customer short-circuit"if existing_customer_or_open_deal: route_to_owner true, tier X, stop"
- Handles the most damaging error before any tier can fire. A current customer never lands in a new-business queue.
- Strict JSON, one-sentence reason{fit, intent, engagement, score, tier, route_to_owner, reason}
- The orchestrator writes numbers to number properties and branches on tier. The reason is the only free text, and it must cite fields.
What you get
One lead, scored and explained. The three sub-scores tell the rep what kind of 78 this is; the reason line tells them what to do about it.
RECORD (from HubSpot over MCP):
Priya Nair, Director of Revenue Operations, Halden Payments (900 employees, fintech, US)
Intent: pricing page x2 (last 7 days), no demo form. Engagement: opened 3 of last 4 emails, no reply. Lifecycle: lead. Existing customer/open deal: false.
AGENT OUTPUT:
{
"fit": 88,
"intent": 60,
"engagement": 40,
"score": 78,
"tier": "A",
"route_to_owner": false,
"reason": "Director of RevOps at a 900-person US fintech (fit 88); visited pricing twice this week with no demo request (intent 60); opening emails but has not replied (engagement 40)."
}
HUBSPOT WRITE: lead_score=78, lead_tier=A, lead_score_reason=<the sentence above>. Owner set to Marcus (fintech territory).
SLACK to @marcus, 7:02am:
6 leads crossed into A-tier overnight. Top of the list:
· Priya Nair, Dir RevOps @ Halden Payments (78): pricing twice this week, no demo yet, opening but not replying. <record>
· ...
SLA: first touch by end of day.
---
EXISTING-CUSTOMER CASE: a lead at a current customer scores tier X, route_to_owner true, and goes to the account owner. It never enters the A/B/C/D tiers.
- fit88
- The ceiling. Director-level RevOps at a 900-person fintech is dead-center ICP. Fit under 40 cannot reach A or B no matter what else happens.
- intent60
- Two pricing-page visits in a week, no demo form. Real but partial; the cap keeps a single signal from carrying the score.
- engagement40
- Opening emails, not replying. Counts for something, decays to zero after 30 days of silence.
- score0.5*88 + 0.3*60 + 0.2*40 = 78
- The weights are yours. Half on fit is a long-cycle, tight-ICP default; a velocity motion would lean harder on intent.
- tier"A"
- The field routing branches on. A-tier should be scarce enough that every A gets a human touch within a day.
- reasonDirector of RevOps at a 900-person fintech; pricing twice this week, no demo; opening, not replying
- The line the rep reads. It cites fields, never adjectives, so a rep can disagree with a specific claim instead of a number.
Pitfalls to avoid
A single signal carrying a lead into A-tierSix email opens from a student should never outscore a VP at a perfect-fit account who has opened nothing. Cap each signal, let fit set the ceiling, and let intent and engagement move a lead inside it.
Scores with no reasonA number reps cannot argue with is a number they will not use. Force a one-line reason that cites the fields that drove the score, and write it to the record next to the score.
No maintenance loopThe points system died because nobody had a reason to revisit it. Audit tier-at-deal-creation monthly against what closed, and adjust the rubric. A model you re-score overnight is a model that can stay honest.
Skipping the existing-customer branchA scoring model that gets excited about a current customer's pricing-page visit will route them to new business. Short-circuit on existing customer or open deal before any tier applies.
Scoring the entire database every nightScore everything once as a backfill, then re-score only records with recent activity or a property change, plus current A and B tiers so decay applies. Batch and pause, or you will meet the CRM's rate limiter at 2am.
Making A-tier too bigIf a third of the database is A, reps stop believing the tier. A-tier should be small enough that every A lead gets a human touch within a day. If your team cannot work it, the cut-off is too low.
Questions people ask
- What is AI lead scoring, and how is it different from a HubSpot points score?
- AI lead scoring uses a model, here a Claude agent following a written rubric, to judge each lead on fit, intent, and engagement and explain the judgment in a sentence. A points score adds fixed weights per property and returns a number with no reason attached. The practical differences: the agent can read messy fields (a title like 'Head of Growth & Ops'), it explains every score, and you can change the rubric in one file and re-score the whole database overnight.
- How is this different from the inbound lead enrichment and routing play?
- That play is the real-time path for one lead: a form submits, an agent enriches and routes it in seconds. This play is the model and the batch: it scores your whole database on a schedule so the leads already sitting in the CRM, the ones with no fresh form fill, get prioritized too. Most teams run both. The inbound agent handles the new arrival; the nightly pass keeps everyone else's score honest as intent and engagement rise and decay.
- How many components should a lead scoring model have?
- Three: fit, intent, and engagement. Fit is whether they look like your best customers, intent is whether there is a reason to think they are in-market now, engagement is whether they are responding to you. Give each a sub-score and a weight. More than three and the model gets hard to explain; fewer and you cannot tell a great-fit account with no timing from a poor-fit account that clicks everything.
- What weights should I use?
- Start at 50 percent fit, 30 percent intent, 20 percent engagement for a tight-ICP, longer-cycle motion, because a perfect-fit account with no intent is still worth a rep's time. A high-velocity motion can move weight toward intent. Whatever you pick, check it against your last 40 closed-won deals before automating: if many of your real customers would have scored C, the weights are wrong.
- Is it safe to let an agent write scores into the CRM?
- Yes, if you keep the write surface tiny. The agent writes three properties, score, tier, and reason, and nothing else. All three are reversible, and every write is logged with the previous value. Add a kill-switch flag the Routine reads before writing, so a bad rubric change can be halted with one property flip instead of a frantic revert.
- How often should the scores refresh?
- Nightly, over the records that changed in the last 30 days plus the current A and B tiers so decay applies. That keeps the run small and the scores current. Scoring the entire database every night is wasteful, and re-scoring once a quarter is how you end up with a model that measures a market that moved on.
- How do I know if the model is working?
- Monthly, pull every deal created in the last 90 days and look at the tier each lead carried on the day the deal was created. Closed-won coming out of C-tier means fit is too narrow. A-tier full of leads that never took a meeting means intent is over-weighted or a signal is leaking through the cap. Also sample D-tier for anyone who later became a customer; that silent number is the real cost of the model.
Related plays
- Lead Routing Rules That Explain Themselves: A Claude Skill That Assigns the Owner →The routing-rules half: who gets the lead once it is scored.
- Lead Enrichment and Routing with a Claude Agent →The real-time path for a single inbound lead; this play scores the rest of the database.
- Build an ICP List with Clay and Claude →Where the fit rules in the rubric come from.
- Claude + HubSpot integration guide →Connecting the CRM over MCP, and the read-write line to hold.
- Put Recurring GTM Work on Autopilot with Claude Routines →The scheduling pattern the nightly scoring pass runs on.