Score HubSpot leads based on firmographic and technographic fit using n8n
Prerequisites
- n8n instance (cloud or self-hosted)
- HubSpot private app token with
crm.objects.contacts.readandcrm.objects.contacts.writescopes - A custom HubSpot contact property for the fit score (e.g.,
icp_fit_score, number type, 0-100) - n8n HubSpot credential configured
- Enriched contact data already in HubSpot (company size, industry, job title)
Step 1: Add a HubSpot Trigger node
Create a new workflow and add a HubSpot Trigger node:
- Authentication: Select your HubSpot credential
- Event: Contact Property Changed
- Property:
hs_analytics_source(or whichever property is updated when enrichment completes)
This fires when a contact's enrichment data is updated, signaling it's time to score.
You can also trigger on contact creation (Contact Created) to score every new lead immediately. Or use a Schedule Trigger to batch-score all contacts every hour.
Step 2: Fetch full contact details
The trigger only sends the contact ID. Add an HTTP Request node to get the full record:
- Method: GET
- URL:
https://api.hubapi.com/crm/v3/objects/contacts/{{ $json.objectId }} - Authentication: Predefined -> HubSpot API
- Query params:
properties=firstname,lastname,jobtitle,company,numberofemployees,industry,hs_analytics_source
Step 3: Score the contact with a Code node
Add a Code node with your scoring model:
const contact = $('Fetch Contact').first().json.properties;
let score = 0;
// --- Company size scoring (0-30 points) ---
const employees = parseInt(contact.numberofemployees || '0');
if (employees >= 200 && employees <= 2000) score += 30; // sweet spot
else if (employees >= 50 && employees < 200) score += 20; // good fit
else if (employees >= 2000 && employees <= 10000) score += 15; // enterprise
else if (employees > 0) score += 5; // at least known
// --- Industry scoring (0-25 points) ---
const industry = (contact.industry || '').toLowerCase();
const idealIndustries = ['saas', 'technology', 'software', 'computer software'];
const goodIndustries = ['financial services', 'consulting', 'marketing'];
if (idealIndustries.includes(industry)) score += 25;
else if (goodIndustries.includes(industry)) score += 15;
else if (industry) score += 5;
// --- Seniority scoring (0-30 points) ---
const title = (contact.jobtitle || '').toLowerCase();
const cSuite = ['ceo', 'cto', 'cfo', 'coo', 'cmo', 'cro', 'chief'];
const vp = ['vp', 'vice president', 'head of'];
const director = ['director', 'senior director'];
const manager = ['manager', 'senior manager', 'lead'];
if (cSuite.some(t => title.includes(t))) score += 30;
else if (vp.some(t => title.includes(t))) score += 25;
else if (director.some(t => title.includes(t))) score += 20;
else if (manager.some(t => title.includes(t))) score += 10;
// --- Lead source scoring (0-15 points) ---
const source = (contact.hs_analytics_source || '').toLowerCase();
const sourceScores = {
'organic_search': 15,
'direct_traffic': 12,
'referrals': 10,
'paid_search': 8,
'social_media': 5,
'email_marketing': 5,
};
score += sourceScores[source] || 0;
return [{
json: {
contactId: $('HubSpot Trigger').first().json.objectId,
score: Math.min(score, 100),
name: `${contact.firstname || ''} ${contact.lastname || ''}`.trim(),
title: contact.jobtitle,
company: contact.company,
employees,
}
}];These weights are a starting point. Replace the industry lists, employee ranges, and point values with your actual ICP criteria. The total should add up to 100 maximum.
Step 4: Write score to HubSpot
Add an HTTP Request node to update the contact's fit score:
- Method: PATCH
- URL:
https://api.hubapi.com/crm/v3/objects/contacts/{{ $json.contactId }} - Body:
{
"properties": {
"icp_fit_score": "{{ $json.score }}"
}
}Step 5: Add a high-score notification (optional)
For leads scoring above 70, add an IF node followed by a Slack node to notify the team:
- IF Condition:
{{ $json.score }}greater than70 - Slack Channel:
#high-fit-leads - Message:
🎯 *High-Fit Lead Scored*
*{{ $json.name }}* — {{ $json.title }} at {{ $json.company }} ({{ $json.employees }} employees)
Score: *{{ $json.score }}/100*Step 6: Activate
- Click Execute Workflow to test with a real contact
- Check the contact's
icp_fit_scoreproperty in HubSpot - Toggle the workflow to Active
Cost
- n8n Cloud Starter: $24/mo for 2,500 executions. Each scored contact = 1 execution.
- Self-hosted: Free. Unlimited executions.
Need help implementing this?
We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.