Build an AI-powered ICP scorer that handles the fuzzy stuff
This post is part of the GTM Automation Playbook — a 13-part series on building AI-powered GTM agents with HubSpot.
Lead scoring tells you who's engaged. ICP scoring tells you who's worth engaging with. Most teams conflate the two and end up chasing contacts who downloaded a whitepaper but will never buy.
ICP scoring operates at the account level, not the contact level. It asks: does this company match the profile of our best customers? The attributes are firmographic (industry, size, geography) and technographic (what tools they use, how sophisticated their stack is). Behavioral signals matter too, but they're secondary. A company in your exact target vertical with 200 employees and your competitor's product installed is a better prospect than one that visited your pricing page six times but sells into a market you don't serve.
Companies that use scoring models see a 77% improvement in lead gen ROI. The gap between scored and unscored pipelines widens the more deals you run.
Why HubSpot's native scoring falls short
HubSpot has built-in score properties. They work fine for simple rules: +10 if industry equals SaaS, +5 if employee count is between 50 and 500. But real ICP criteria involve judgment. Is "digital marketing platform" close enough to "Martech" to get points? Does a company with 48 employees count as "in range" for a 50-500 sweet spot? Should a Series A company in fintech score higher than a Series C company in healthcare?
Native scoring can't handle fuzzy matching. And HubSpot's custom coded actions, which could, require Operations Hub Professional at $800/month. n8n is open source.
Set up the properties first
Create four custom properties on the Company object in HubSpot. Use the Properties API (POST /crm/v3/properties/companies) or do it in Settings > Properties.
icp_score— type:number, fieldType:numbericp_tier— type:enumeration, fieldType:select, options: Tier 1, Tier 2, Tier 3icp_score_reasoning— type:string, fieldType:textareaicp_scored_at— type:datetime, fieldType:date
Group them under a custom property group called "ICP Scoring" so they're easy to find. Both type and fieldType are required when creating via API.
Build the scoring workflow in n8n
The workflow has six nodes. Trigger, data pull, AI scoring, parse, write back, route.
Node 1: Schedule Trigger. Run nightly to batch-score all companies where icp_scored_at is empty or older than 30 days. You could use the HubSpot Trigger node instead (fires on company creation), but batch scoring is more practical for initial rollout. One caveat: HubSpot only allows one webhook per app, so if you're already using a HubSpot Trigger elsewhere, use the schedule approach and poll via the search endpoint.
Node 2: HubSpot node — pull companies. Use the HTTP Request node to call POST /crm/v3/objects/companies/search with a filter for unscored companies. Pull properties: name, industry, numberofemployees, annualrevenue, city, state, country, description, website. For technographic data, either pull from a custom property you've already enriched or add an enrichment step (Clay or Clearbit via HTTP Request).
Node 3: AI scoring — the core. Use a Basic LLM Chain node with the Anthropic Chat Model sub-node. Claude Sonnet is the right choice here — fast, cheap, and accurate enough for classification. The prompt is everything. Here's the structure that works:
You are an ICP scoring engine. Score this company on a 0-100 scale.
OUR ICP CRITERIA:
- Industry: [YOUR TARGET VERTICALS] (exact match = 30 pts, adjacent = 15)
- Company size: [YOUR RANGE] employees (exact = 20, close = 10)
- Tech stack: Uses [YOUR KEY INTEGRATIONS] (match = 15, partial = 8)
- Geography: [YOUR REGIONS] (Tier 1 = 10, Tier 2 = 5)
- Funding/Revenue: [YOUR RANGE] (match = 10, close = 5)
- Growth signals: Recent funding, hiring, tech changes (yes = 10, some = 5)
- Engagement: Site visits, content downloads (high = 5, medium = 3)
COMPANY DATA:
Name: {{ $json.name }}
Industry: {{ $json.industry }}
Employees: {{ $json.numberofemployees }}
Revenue: {{ $json.annualrevenue }}
Location: {{ $json.city }}, {{ $json.state }}
Description: {{ $json.description }}
Return ONLY valid JSON:
{
"total_score": <0-100>,
"tier": "Tier 1|Tier 2|Tier 3",
"breakdown": {
"industry": {"score": <n>, "max": 30, "reason": "..."},
"company_size": {"score": <n>, "max": 20, "reason": "..."},
...
},
"summary": "1-2 sentence fit assessment"
}
The model handles the fuzzy matching you can't do with rules. It reads "we're a digital marketing platform" in the description and maps it to your Martech vertical. It sees 48 employees and gives partial credit instead of a binary pass/fail. It notices the company just raised a Series B and adds growth signal points. All with reasoning you can audit.
Node 4: Code node — parse the response. Extract total_score, tier, and summary from the JSON. Add error handling for malformed responses (retry once if JSON parsing fails).
Node 5: HubSpot node — write back. PATCH /crm/v3/objects/companies/{companyId} with the score, tier, reasoning, and timestamp. Now the score lives on the company record where it's filterable, sortable, and usable in any HubSpot workflow or list.
Node 6: IF node — route by tier. Tier 1 (80+): send a Slack alert to the account owner and create a HubSpot task. Tier 2 (50-79): add to a nurture sequence. Tier 3 (below 50): log and move on.
Define your rubric from actual wins
The scoring criteria above are placeholders. Your rubric should come from your own data. Pull 50-100 closed-won deals from the last 12 months. Tag each with industry, company size, tech stack, geography, and funding stage. Look for clusters. Typically 70-80% of your wins share 3-5 common traits. Those traits become your highest-weighted criteria.
Don't guess at weights. If 90% of your wins are in SaaS and fintech, industry gets 30 points. If company size barely correlates with win rate, drop it to 10. The rubric should reflect your actual sales data, not your assumptions about who should buy.
Cost and performance
Claude Sonnet scoring costs roughly $0.001 per company. Scoring 1,000 companies in a nightly batch costs about a dollar. The n8n workflow processes roughly 100 companies per minute, depending on HubSpot API rate limits (100 requests per 10 seconds).
The real value isn't the score itself. It's what happens downstream. When your Tier 1 list is actually composed of companies that look like your best customers, every activity your team runs against that list performs better. Outbound reply rates go up. Demo-to-close rates go up. Average deal size goes up. The ICP scorer doesn't close deals. It points your team at the right ones.

Need a Fractional Head of AI?
I help companies build an AI operating system — shared context across teams, AI handling the repetitive work, and your people focused on what actually matters.
15+
Years in Tech
12+
AI Products Shipped
3
Fortune 500 Brands