Lead Scoring Engine
**Lead scoring** transforms a raw list of prospects into a ranked, graded shortlist so your sales team contacts the right companies first. This actor scores every lead from 0 to 100 against your Ideal Customer Profile, assigns an A–F letter grade, and returns a full breakdown of why each lead received its score — all for $0.03 per lead, with no API subscriptions required.
Maintenance Pulse
90/100Documentation
Lead scoring transforms a raw list of prospects into a ranked, graded shortlist so your sales team contacts the right companies first. This actor scores every lead from 0 to 100 against your Ideal Customer Profile, assigns an A–F letter grade, and returns a full breakdown of why each lead received its score — all for $0.03 per lead, with no API subscriptions required.
The engine runs six weighted dimensions against each lead record: industry match, company size, services alignment, contact presence, intent signals, and data completeness. Weights are fully configurable and normalised automatically if they do not sum to 100. The computation is deterministic — the same input always produces the same output — and requires no external API calls, so runs complete in seconds regardless of batch size.
What data can you extract?
| Data Point | Source | Example |
|---|---|---|
| 📊 ICP Score | Computed across 6 dimensions | 82.5 |
| 🏅 ICP Grade | Derived from score thresholds | "A" |
| 🏭 Industry Match score | Lead's industry vs. target list | 100 (exact), 60 (partial), 0 (miss) |
| 📏 Company Size Match score | Employee band vs. target bands | 100 (exact), 50 (adjacent), 0 (miss) |
| 🛠 Services Match score | Lead's services + tech vs. targets | 100 (3+ matches), 80 (2), 50 (1), 0 |
| 📬 Contact Presence score | Emails, phones, named contacts, LinkedIn | 40–100 additive |
| 📈 Intent Signals score | Reviews, hiring, chat widget, keywords | 30–100 additive |
| 🗂 Data Completeness score | Populated field groups (5 groups × 20 pts) | 0–100 |
| 📝 ICP Notes | Human-readable per-dimension explanation | "Exact industry match: 'Marketing Agency'" |
| 🕐 Scored At | ISO 8601 timestamp | "2025-11-14T09:22:31.000Z" |
| 📋 Run Summary | Grade distribution, averages, config echo | { A: 12, B: 34, C: 19, ... } |
| ⚙️ Weights Used | Normalised weights applied to the run | { industry: 25, companySize: 20, ... } |
Why use Lead Scoring Engine?
Without a scoring system, sales teams work in gut-feel order. A rep opens the spreadsheet at row 1 and dials down. Half the list is the wrong industry, wrong size, or missing contact details — which means wasted calls, ignored emails, and a pipeline that looks fuller than it is.
This actor automates the entire ICP qualification process. Pass in leads from any upstream actor — Google Maps Email Extractor, Website Contact Scraper, B2B Lead Gen Suite, or your own enrichment output — and get back a scored, sorted, grade-filtered dataset ready for your CRM.
- Scheduling — run daily or weekly to re-score updated datasets as new leads enter the top of the funnel
- API access — trigger scoring runs from Python, JavaScript, or any HTTP client inside your existing pipeline
- Budget control — set a per-run spending limit; the actor stops when your cap is reached so there are no surprise bills
- Monitoring — connect Apify's Slack or email alerts to catch runs that fail or return unexpected grade distributions
- Integrations — push scored leads directly to HubSpot via HubSpot Lead Pusher, or export to Google Sheets, Zapier, or Make
Features
- Six independent scoring dimensions — industry match, company size, services alignment, contact presence, intent signals, and data completeness, each returning a 0–100 raw score before weight application
- Configurable dimension weights — assign any integer 0–100 to each dimension; weights are proportionally normalised to sum exactly to 100 so configuration errors never silently corrupt scores
- Fuzzy industry matching with 10 built-in alias groups — "digital agency" matches "marketing agency", "saas" matches "software", "google ads" matches "ppc", and more; exact matches score 100, partial substring matches score 60
- 8-band employee sizing with human-readable aliases — accepts numeric counts ("25 employees", 150), range strings ("11-50"), or plain-language labels ("small", "mid-market", "enterprise", "fortune 500"); adjacent-band leads score 50 rather than 0
- 15-service synonym library — "SEO" automatically matches "search engine optimisation", "organic search", "link building", "on-page seo", and 5 more variants; scores 100 for 3+ matches, 80 for 2, 50 for 1
- Additive contact presence scoring — 40 pts for a valid email, 20 pts for a named contact or LinkedIn URL, 20 pts for a phone number, 20 pts for 2+ named contacts or a titled decision-maker; validated against regex before counting
- Four-signal intent scoring — high review count (100+) or high rating (4.5+), active hiring via job postings or hiringCount, chat widget or contact form present, and intent/tech keywords in the record; additive up to 100
- 5-group data completeness scoring — identity (domain/website), company name, contact info (email or phone), location (address/city/country), and profile (description, founded year, revenue); 20 pts per group
- A–F letter grades — A (80–100), B (65–79), C (50–64), D (35–49), F (0–34)
- Per-dimension textual notes — every scored record includes an
icpNotesarray explaining exactly why each dimension received its score, formatted for direct display in CRM fields or Slack notifications - Inline leads or dataset ID — pass leads directly as a JSON array, or point to any Apify dataset by ID to chain with an upstream scraping actor
- Paginated dataset loading — loads large upstream datasets in 1,000-item batches to avoid out-of-memory errors on datasets of 10,000+ leads
- Minimum score filter — set
minScoreToIncludeto exclude junk leads from the output entirely; charges still apply only for leads processed, so filtering reduces total output volume without increasing cost - Run summary record — every run ends with a
type: "summary"record containing grade distribution, average score, top score, weights used, and ICP config, so you can audit any run without re-reading the logs - Spending limit awareness — when PPE spending cap is reached the actor stops cleanly and sets
spendingLimitReached: truein the summary record
Use cases for lead scoring
Sales prospecting and SDR prioritisation
Sales development reps waste 40–60% of dial time on companies that were never a real fit. Score every inbound lead from a trade show list, LinkedIn export, or Google Maps scrape against your ICP before the list ever reaches an SDR. Set minScoreToInclude: 65 to hand reps only B+ leads, and sort by score so grade-A prospects appear at the top of their queue.
Marketing agency lead generation
Agencies building prospect lists for outreach campaigns typically work with raw scrapes from directories, Google Maps, or contact databases. Running those lists through this actor before enrichment identifies which leads are worth paying to enrich further — saving enrichment budget on companies that will never convert. Combine with Waterfall Contact Enrichment for a cost-efficient pipeline.
CRM data quality and re-engagement
Existing CRM records go stale. Score your full contact database against a tightened ICP to surface dormant leads who now fit your profile, and identify records that no longer qualify. Export score and grade into a CRM custom field to drive automated re-engagement sequences based on grade changes over time.
Pipeline qualification and deal prioritisation
For teams running inbound pipelines, scoring provides an objective qualification signal alongside BANT. Integrate with HubSpot Lead Pusher to write icpScore and icpGrade directly into HubSpot contact properties, then use HubSpot workflows to route A-grade leads to senior reps and F-grade leads to nurture sequences automatically.
Recruiting and talent sourcing
Talent teams sourcing from job boards or LinkedIn can adapt the ICP model: set targetIndustries to the verticals you hire from, targetCompanySizes to the company sizes your candidates typically work at, and weight intentSignals heavily so actively hiring companies score highest. The intent signals dimension detects job posting activity in the lead record directly.
Market segmentation and research
Analysts who collect company data for market research use the scoring engine to segment a broad universe of companies into tiers. The per-dimension factor scores reveal where a segment is strong or weak across the six dimensions — useful for characterising an addressable market before building a go-to-market strategy.
How to score leads against your ICP
- Provide your leads — paste a JSON array of lead objects into the "Leads (inline)" field, or enter the dataset ID from an upstream actor run (e.g. from B2B Lead Gen Suite) into the "Dataset ID" field.
- Define your ICP — fill in Target Industries (e.g. "Marketing Agency", "SaaS"), Target Company Sizes (e.g. "11-50", "51-200"), and Target Services (e.g. "SEO", "PPC"). Leave a field blank to treat that dimension as neutral.
- Run the actor — click "Start" and wait. Scoring 100 leads typically takes under 10 seconds. Scoring 10,000 leads takes 2–3 minutes.
- Download results — open the Dataset tab, filter to records where
icpGradeis "A" or "B", and export as CSV, JSON, or Excel. The output is sorted by score descending by default.
Input parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
leads | array | One of these | — | Array of lead objects to score inline. Use this OR datasetId. |
datasetId | string | One of these | — | Apify dataset ID to load leads from. Use when chaining with an upstream actor. |
targetIndustries | array | No | ["Marketing Agency", "Digital Agency"] | Industry names matching your ICP. Fuzzy matching and aliases applied automatically. |
targetCompanySizes | array | No | ["11-50", "51-200"] | Employee bands matching your ICP. Accepts range strings, plain numbers, or labels like "small". |
targetServices | array | No | ["SEO", "Content Marketing"] | Services your ideal clients offer. Matched against lead's services field with synonym expansion. |
targetTechStack | array | No | [] | Technologies your ideal clients use. Matched against lead's techStack and techKeywords fields. |
weightIndustry | integer | No | 25 | Points weight for the Industry Match dimension (0–100). Normalised if weights don't sum to 100. |
weightCompanySize | integer | No | 20 | Points weight for the Company Size Match dimension. |
weightServices | integer | No | 20 | Points weight for the Services Match dimension. |
weightContactPresence | integer | No | 15 | Points weight for the Contact Presence dimension. |
weightIntentSignals | integer | No | 10 | Points weight for the Intent Signals dimension. |
weightDataCompleteness | integer | No | 10 | Points weight for the Data Completeness dimension. |
minScoreToInclude | integer | No | 0 | Exclude leads below this score from output. Set to 65 to keep only B+ leads. |
outputSortedByScore | boolean | No | true | Sort output descending by icpScore so best leads appear first. |
maxLeads | integer | No | 10000 | Safety cap on leads processed. Prevents runaway costs on very large datasets. |
Input examples
Score leads from an upstream actor run (most common pipeline use):
{
"datasetId": "aBcDeFgHiJkLmNoP",
"targetIndustries": ["Marketing Agency", "Digital Agency"],
"targetCompanySizes": ["11-50", "51-200"],
"targetServices": ["SEO", "PPC", "Content Marketing"],
"targetTechStack": ["HubSpot", "Google Analytics"],
"minScoreToInclude": 50,
"outputSortedByScore": true
}
Score inline leads with custom ICP weights (B2B SaaS targeting):
{
"leads": [
{
"domain": "pinnacletech.io",
"companyName": "Pinnacle Technologies",
"industry": "SaaS",
"services": ["CRM", "Marketing Automation"],
"companySize": "51-200",
"emails": ["[email protected]"],
"contacts": [{ "name": "James Okafor", "title": "CEO", "email": "[email protected]" }],
"phones": ["+44 20 7946 0123"],
"techStack": ["HubSpot", "Salesforce"],
"rating": 4.8,
"reviewCount": 214,
"hasChatWidget": true,
"hasContactForm": true,
"city": "London",
"country": "UK",
"foundedYear": 2016,
"description": "B2B SaaS platform for marketing operations teams."
}
],
"targetIndustries": ["SaaS", "Software"],
"targetCompanySizes": ["51-200", "201-500"],
"targetServices": ["CRM", "Marketing Automation"],
"targetTechStack": ["HubSpot", "Salesforce"],
"weightIndustry": 30,
"weightCompanySize": 25,
"weightServices": 20,
"weightContactPresence": 15,
"weightIntentSignals": 5,
"weightDataCompleteness": 5,
"outputSortedByScore": true
}
Quick filter — keep only grade A leads, no ICP on services:
{
"datasetId": "xYz123datasetId",
"targetIndustries": ["Ecommerce", "Online Retail"],
"targetCompanySizes": ["11-50", "51-200", "201-500"],
"minScoreToInclude": 80,
"outputSortedByScore": true
}
Input tips
- Start with the default weights — industry 25, company size 20, services 20, contact 15, intent 10, completeness 10 covers most B2B agency use cases without adjustment.
- Leave unused dimensions at zero — if you don't care about tech stack, set
targetTechStack: []; the services dimension returns neutral (50) when no target is configured, which does not hurt scores. - Use
minScoreToIncludeto reduce output volume — setting it to 50 cuts typical output by 30–50% and makes the dataset easier to action in a CRM import. - Batch all leads in one run — scoring 500 leads in one run is significantly faster than 500 single-lead runs; load time and actor startup overhead is paid once per run.
- Pass
datasetIdfrom upstream actors — the actor reads any Apify dataset directly; there is no need to download and re-upload data between pipeline steps.
Output example
{
"domain": "brightedge.com",
"companyName": "BrightEdge",
"industry": "Marketing Agency",
"services": ["SEO", "Content Marketing", "Analytics"],
"companySize": "51-200",
"emails": ["[email protected]"],
"contacts": [
{ "name": "Sarah Chen", "title": "Head of SEO", "email": "[email protected]" }
],
"phones": ["+1 415-555-0182"],
"address": "1 Market St, San Francisco, CA",
"rating": 4.7,
"reviewCount": 143,
"hasChatWidget": true,
"hasContactForm": true,
"techStack": ["HubSpot", "Google Analytics", "Salesforce"],
"foundedYear": 2011,
"description": "Enterprise SEO and content performance platform for B2B companies.",
"icpScore": 87.5,
"icpGrade": "A",
"icpFactors": {
"industryMatch": 100,
"companySizeMatch": 100,
"servicesMatch": 100,
"contactPresence": 100,
"intentSignals": 100,
"dataCompleteness": 100
},
"icpNotes": [
"Industry (25pts weight): Exact industry match: 'Marketing Agency' in lead data",
"Company Size (20pts weight): Company size '51-200' exactly matches ICP target",
"Services (20pts weight): Matched: [SEO, Content Marketing]; Not matched: []",
"Contact Presence (15pts weight): Email present: 1 address(es); 1 named contact(s) present; Phone present: 1 number(s); Contact has role/title — decision maker identifiable",
"Intent Signals (10pts weight): High rating: 4.7 (≥4.5); High review count: 143 (≥100); Engagement tools present: chat widget, contact form",
"Data Completeness (10pts weight): Identity: domain/website present; Company: name present; Contact: email + phone present; Location: address present; Profile: description, foundedYear present"
],
"scoredAt": "2025-11-14T09:22:31.000Z"
}
Run summary record (always the last record in the dataset):
{
"type": "summary",
"totalInput": 150,
"totalScored": 127,
"filteredOut": 23,
"minScoreFilter": 50,
"averageScore": 68.4,
"topScore": 92.5,
"gradeDistribution": { "A": 18, "B": 41, "C": 35, "D": 21, "F": 12 },
"weightsUsed": {
"industry": 25,
"companySize": 20,
"services": 20,
"contactPresence": 15,
"intentSignals": 10,
"dataCompleteness": 10
},
"icpConfig": {
"targetIndustries": ["Marketing Agency", "Digital Agency"],
"targetCompanySizes": ["11-50", "51-200"],
"targetServices": ["SEO", "PPC", "Content Marketing"],
"targetTechStack": ["HubSpot", "Google Analytics"]
},
"spendingLimitReached": false,
"scoredAt": "2025-11-14T09:22:45.000Z"
}
Output fields
| Field | Type | Description |
|---|---|---|
icpScore | number | Overall ICP score, 0–100 (one decimal place). Higher is better. |
icpGrade | string | Letter grade: A (80–100), B (65–79), C (50–64), D (35–49), F (0–34). |
icpFactors.industryMatch | number | Raw 0–100 score for the industry dimension before weight application. |
icpFactors.companySizeMatch | number | Raw 0–100 score for the company size dimension. |
icpFactors.servicesMatch | number | Raw 0–100 score for the services + tech stack dimension. |
icpFactors.contactPresence | number | Raw 0–100 score for contact richness (emails, phones, LinkedIn, named contacts). |
icpFactors.intentSignals | number | Raw 0–100 score for buying intent (reviews, hiring, chat widget, keywords). |
icpFactors.dataCompleteness | number | Raw 0–100 score for how many field groups are populated (0, 20, 40, 60, 80, or 100). |
icpNotes | string[] | Per-dimension text explanations showing exactly why each score was assigned. |
scoredAt | string | ISO 8601 timestamp of when the lead was scored. |
| (all original lead fields) | mixed | Every field from the input lead record is preserved unchanged in the output. |
type | string | Present only on the summary record: "summary". |
totalInput | number | Summary only: total lead records loaded. |
totalScored | number | Summary only: leads that passed the minimum score filter. |
filteredOut | number | Summary only: leads excluded by minScoreToInclude. |
averageScore | number | Summary only: mean icpScore across all scored leads. |
topScore | number | Summary only: highest icpScore in the run. |
gradeDistribution | object | Summary only: count of A, B, C, D, F leads. |
weightsUsed | object | Summary only: the normalised weights actually applied to this run. |
spendingLimitReached | boolean | Summary only: true if the PPE spending cap was hit mid-run. |
How much does it cost to score leads?
Lead Scoring Engine uses pay-per-event pricing — you pay $0.03 per lead scored. Platform compute costs are included. Scoring happens in-process with no external API calls, so there are no variable costs from third-party services.
| Scenario | Leads | Cost per lead | Total cost |
|---|---|---|---|
| Quick test | 10 | $0.03 | $0.30 |
| Small batch | 100 | $0.03 | $3.00 |
| Medium batch | 500 | $0.03 | $15.00 |
| Large batch | 2,000 | $0.03 | $60.00 |
| Enterprise | 10,000 | $0.03 | $300.00 |
You can set a maximum spending limit per run in the Apify console. The actor stops when your budget is reached and marks spendingLimitReached: true in the summary record.
Charges apply to each lead processed through the scoring computation, including leads that are subsequently filtered out by minScoreToInclude. The computation is always performed — filtering happens after scoring.
Compare this to manual qualification: an SDR spending 3 minutes qualifying each lead costs $25–50 per hour, meaning 100 leads cost $125–250 in labour. With this actor the same 100 leads cost $3.00 and return in under 30 seconds.
Score leads using the API
Python
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("ryanclinton/lead-scoring-engine").call(run_input={
"datasetId": "aBcDeFgHiJkLmNoP",
"targetIndustries": ["Marketing Agency", "Digital Agency"],
"targetCompanySizes": ["11-50", "51-200"],
"targetServices": ["SEO", "PPC", "Content Marketing"],
"minScoreToInclude": 65,
"outputSortedByScore": True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item.get("type") == "summary":
print(f"Run complete — A:{item['gradeDistribution']['A']} B:{item['gradeDistribution']['B']} avg:{item['averageScore']}")
else:
print(f"{item.get('companyName')} | Score: {item.get('icpScore')} | Grade: {item.get('icpGrade')}")
JavaScript
import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: "YOUR_API_TOKEN" });
const run = await client.actor("ryanclinton/lead-scoring-engine").call({
datasetId: "aBcDeFgHiJkLmNoP",
targetIndustries: ["Marketing Agency", "Digital Agency"],
targetCompanySizes: ["11-50", "51-200"],
targetServices: ["SEO", "PPC", "Content Marketing"],
minScoreToInclude: 65,
outputSortedByScore: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
if (item.type === "summary") {
console.log(`Run complete — avg score: ${item.averageScore}, top: ${item.topScore}`);
} else {
console.log(`${item.companyName} — ${item.icpScore} (${item.icpGrade})`);
}
}
cURL
# Start the actor run
curl -X POST "https://api.apify.com/v2/acts/ryanclinton~lead-scoring-engine/runs?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"datasetId": "aBcDeFgHiJkLmNoP",
"targetIndustries": ["Marketing Agency", "Digital Agency"],
"targetCompanySizes": ["11-50", "51-200"],
"targetServices": ["SEO", "PPC", "Content Marketing"],
"minScoreToInclude": 65,
"outputSortedByScore": true
}'
# Fetch results (replace DATASET_ID from the run response)
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_API_TOKEN&format=json"
How Lead Scoring Engine works
Weight normalisation
When the actor starts, normaliseWeights() in scorer.ts accepts the six raw weight inputs and forces them to sum exactly to 100. It clamps each value to zero minimum, sums all six, and scales each proportionally using weight = rawWeight / total * 100, rounded to one decimal place. If all weights are zero (an edge case), the defaults (25/20/20/15/10/10) are restored. This means you can set weights like 3/2/2/1/1/1 and the engine will scale them correctly to 30/20/20/10/10/10 — no manual arithmetic required.
Per-dimension scoring
Each of the six dimension modules (dimensions/industry.ts, dimensions/company-size.ts, etc.) receives the raw lead record and the relevant ICP targets, and returns a DimensionResult object with a score (0–100), a maxScore (always 100), and a notes array.
- Industry: reads
industry,vertical,category,niche, andservicesfields; resolves targets through a 10-group alias map; returns 100 for exact match, 60 for partial substring match, 50 for no-target (neutral), 0 for no match - Company size: parses numeric counts, range strings ("11-50"), and text labels ("mid-market") into one of 8 employee bands; returns 100 for exact band match, 50 for adjacent band (±1 position on the ordered band list), 0 for all others
- Services: expands each target through a 15-service synonym library; checks
servicesandtechStackfields; scores 100 for 3+ matches, 80 for 2, 50 for 1, 0 for none - Contact presence: additive scoring — 40 pts for validated email (regex
/^[^@\s]+@[^@\s]+\.[^@\s]+$/), 20 pts for named contact or LinkedIn URL, 20 pts for phone, 20 pts for 2+ named contacts or a titled contact - Intent signals: additive scoring — 30 pts for rating ≥4.5 or reviewCount ≥100, 25 pts for active hiring (jobPostings or hiringCount), 25 pts for chat widget or contact form, 20 pts for intent/tech keywords; returns neutral 50 if no signal data present
- Data completeness: 5 groups × 20 pts each — identity (domain/website), company name, contact info (email or phone), location (address/city/country), and profile (description, foundedYear, revenue, or minProjectSize)
Score assembly and grading
The final icpScore is computed as the sum of each dimension's proportional contribution: (dimensionScore / 100) * dimensionWeight. The six weighted values are summed and rounded to one decimal place. The grade thresholds are fixed: A ≥80, B ≥65, C ≥50, D ≥35, F <35. Both the score and grade are written directly onto the lead record alongside the per-dimension icpFactors and icpNotes arrays.
Dataset loading and PPE charging
When datasetId is provided, the actor paginates through the dataset in 1,000-item batches using the Apify client's listItems with limit and offset parameters, accumulating records up to maxLeads. The PPE charge event "lead-scored" fires once per lead immediately after scoring, so the spending limit check runs at each iteration and the actor stops cleanly if the cap is reached mid-batch.
Tips for best results
-
Define at least
targetIndustriesandtargetCompanySizesbefore anything else. These two dimensions account for 45 points at default weights and have the largest impact on final scores. An ICP with only these two configured will already produce meaningful lead tiers. -
Use
minScoreToInclude: 50for most pipeline use cases. Leads scoring below 50 (grade C or lower) rarely convert without further qualification. Filtering them at scoring time reduces CRM clutter and downstream enrichment costs. -
Increase
weightContactPresencefor cold outreach campaigns. If your SDRs need an email or phone to reach out, raise this weight to 25 or 30. Leads with no contact data will score significantly lower and sort below actionable leads. -
Increase
weightIntentSignalsfor growth-focused targeting. If you sell to companies that are actively scaling, raise the intent weight to 20 or 25. Leads with active hiring, high review volume, and engagement tools will rank higher than equivalently-sized but dormant companies. -
Chain with Waterfall Contact Enrichment after scoring. Run enrichment only on A and B grade leads (pass
minScoreToInclude: 65). This cuts enrichment cost by 50–70% compared to enriching the entire raw list. -
Use the
icpNotesfield to diagnose score distribution issues. If most leads are scoring 30–40 and you expect higher, read the notes on a few low-scoring records. A common cause istargetCompanySizesbands that don't match the size format in your lead data — for example, passing "small" when the lead hasemployeeCount: 45works, but passing "SMB" with no numeric count does not. -
Re-score the same dataset with different weights to test ICP hypotheses. Because the engine is deterministic, you can run the same
datasetIdtwice with different weight configs and compare grade distributions in the summary records to see which ICP definition produces the most A-grade leads from your existing data. -
Set
outputSortedByScore: falseif you need to preserve the original lead order — for example, when the upstream dataset is sorted by Google Maps ranking or scraping order and you want to maintain that sequence for reporting.
Combine with other Apify actors
| Actor | How to combine |
|---|---|
| B2B Lead Gen Suite | Full pipeline: pass the output dataset ID from B2B Lead Gen Suite directly as datasetId to score every scraped lead against your ICP in one chained run |
| Google Maps Email Extractor | Extract local business leads with emails from Google Maps, then score the output dataset to identify which local businesses match your agency's ICP |
| Website Contact Scraper | Scrape contact details from a list of company websites, then score the enriched records to prioritise outreach by ICP fit |
| Waterfall Contact Enrichment | Run scoring first; pass only A and B grade leads (score ≥65) into enrichment to reduce enrichment cost by 50–70% |
| HubSpot Lead Pusher | Push scored leads with icpScore and icpGrade fields into HubSpot as contact properties, then use HubSpot workflows to route by grade |
| Bulk Email Verifier | After scoring, verify emails only on A and B grade leads before handing to SDRs — avoids bounce rates from low-quality contacts |
| B2B Lead Qualifier | Use alongside this actor for a 30-signal deep-qualification pass on your top-scoring leads; Lead Scoring Engine provides the first filter, B2B Lead Qualifier provides the deep profile |
Limitations
- No live data enrichment — the actor scores only the fields already present in the lead record. If a lead is missing
industryorcompanySize, those dimensions return 0 or neutral rather than fetching the data from an external source. Use Waterfall Contact Enrichment upstream to add missing fields before scoring. - Industry matching is text-based — the fuzzy match works against the 10 built-in alias groups. Industry terms outside those groups must match verbatim (exact or partial substring). Highly niche verticals (e.g. "maritime logistics", "precision agriculture") may not match aliases and will require exact string configuration.
- Intent signals require upstream data — the intent dimension scores neutrally (50) when no signal fields are present in the lead record. Rating, review count, job postings, and chat widget data must be scraped upstream (e.g. by Google Maps Email Extractor or Website Contact Scraper) and included in the lead object.
- Company size bands are fixed — the 8 bands (1–10, 11–50, 51–200, 201–500, 501–1000, 1001–5000, 5001–10000, 10001+) cannot be customised. Very large or very small employee thresholds that fall outside these bands cannot be expressed.
- No deduplication — if the input leads array or dataset contains duplicate domain entries, each will be scored and charged separately. Deduplication should happen upstream.
- Charges apply even to filtered leads — the $0.03 charge fires after the scoring computation completes, before the
minScoreToIncludefilter is applied. Leads excluded from the output dataset are still charged. - Maximum 10,000 leads per run by default — set
maxLeadsup to 100,000 if needed, but very large runs on 256 MB memory are possible due to the streaming pagination approach. - No partial tech stack matching within a single string — tech stack matching checks for the target term as a substring of the combined lead text. If a lead stores tech as
"shopify-plus-theme"and you target"Shopify", it will match. But deeply abbreviated or encoded tech strings may not resolve correctly.
Integrations
- Zapier — trigger a lead scoring run when new leads are added to a Google Sheet or CRM, then write scored results back automatically
- Make — build multi-step scenarios that scrape leads, score them, filter by grade, and push A/B leads to HubSpot or ActiveCampaign
- Google Sheets — export scored leads directly to a Sheet for manual review, sorting by
icpScorecolumn to surface top prospects - Apify API — chain scoring runs programmatically using the dataset ID from any upstream run; retrieve results in JSON, CSV, or XLSX format
- Webhooks — trigger downstream actions (Slack notification, CRM push, email alert) when a run completes and the summary shows more than N grade-A leads
- LangChain / LlamaIndex — feed scored lead data into an AI agent that generates personalised outreach copy ranked by
icpScore, targeting only A and B grade leads
Troubleshooting
Most leads scoring 0 on the industry dimension despite having industry data. Check that your targetIndustries values match the format in the lead record. The engine checks industry, vertical, category, niche, and services fields. If the lead stores industry as "Digital Marketing" and you target "Marketing Agency", the fuzzy alias resolves correctly. But if the lead has no industry field at all, the dimension returns 0. Inspect icpNotes[0] on a low-scoring record — it will state exactly which fields were read and what the target was.
Company size dimension returning 0 despite employee data present. The actor reads employeeCount, teamSize, employees, headcount, and companySize fields. Ensure at least one of these is present and contains a number or a parseable string like "45 employees", "11-50", or "mid-market". A field named staff or team_size (snake_case) will not be read — map it to a supported field name upstream.
spendingLimitReached: true in the summary record. The PPE spending cap was hit before all leads were processed. Leads processed before the limit was reached are in the dataset. Either increase the per-run spending limit in the Apify console, or reduce the number of leads per run by lowering maxLeads.
Run completes but output dataset is empty. This happens when minScoreToInclude is set too high for the data quality of the input leads. Check the summary record (it is always written regardless of the filter) for the grade distribution. If all leads are grade F or D, lower minScoreToInclude to 0, inspect the icpNotes on a sample of records, and adjust your ICP configuration accordingly.
Charged for leads not in the output dataset. This is expected behaviour — the $0.03 charge fires after the scoring computation completes, before the minimum score filter is applied. The charge reflects compute work done, not records in the output. Use minScoreToInclude to reduce output volume; to reduce charges, pre-filter leads upstream before passing them to the scoring engine.
Responsible use
- This actor processes only the lead data you supply — it does not scrape any websites or call any external APIs.
- When using scored lead data for outreach, comply with GDPR, CAN-SPAM, CASL, and other applicable data protection laws in your jurisdiction.
- Do not use scored lead data for spam, harassment, or unsolicited contact outside the terms of service of your outreach platform.
- Ensure you have a lawful basis for processing personal data (including email addresses) contained in the lead records you supply.
- For guidance on web scraping legality, see Apify's guide.
FAQ
How does lead scoring against an ICP work? The actor evaluates each lead across six dimensions — industry match, company size, services alignment, contact presence, intent signals, and data completeness — and combines weighted dimension scores into a single 0–100 number. Dimension weights default to 25/20/20/15/10/10 and can be customised. The final score determines a letter grade (A through F) using fixed thresholds.
How many leads can I score in one run? Up to 100,000 (set via maxLeads). The default cap is 10,000. The actor paginates large datasets in 1,000-item batches to stay within the 256 MB memory allocation.
Does lead scoring require exact field names? The actor reads a defined set of field names (listed in the Limitations section). If your upstream scraper uses different names (e.g. staff_count instead of employeeCount), map the fields before passing leads to the scoring engine. Renaming can be done in a Make/Zapier step or with a lightweight transformation actor.
What happens if I don't configure any ICP targets? Dimensions with no configured targets return a neutral score of 50. If all dimensions return neutral, the final score is 50 (grade C). This is useful for testing the pipeline before you have a defined ICP — all leads score similarly and the output reflects contact presence and data completeness only.
How is Lead Scoring Engine different from B2B Lead Qualifier? Lead Scoring Engine scores any lead record you supply against a configurable ICP using six dimensions. It is a computation layer in a pipeline, not a data source. B2B Lead Qualifier fetches and analyses 30+ signals from external sources about a company. The two work best together: score first to identify which leads are worth deeper qualification, then run B2B Lead Qualifier on grade-A leads only.
Can I use custom ICP dimensions beyond the six built-in ones? Not currently. The six dimensions (industry, company size, services, contact presence, intent signals, data completeness) cover the most common B2B qualification criteria. If you need additional dimensions — for example, a revenue threshold or geographic filter — pre-filter your leads before passing them to the actor.
How accurate is the industry matching? Exact matches (target term equals a field value verbatim or via alias) score 100% accurately. Partial matches (target term appears as a substring of combined field text) score 60 and are correct most of the time but can produce false positives — for example, targeting "SEO" would partially match a company description mentioning "our CEO". For high-precision industry filtering, ensure your leads have a dedicated industry field from upstream enrichment.
Is it legal to score leads using this actor? Yes — the actor processes data you supply and makes no external data requests. The legality of your outreach depends on how you obtained the lead data and how you use it, not on the scoring computation itself. Ensure your lead acquisition and outreach comply with GDPR, CAN-SPAM, and relevant local laws.
Can I schedule lead scoring to run automatically? Yes. Use Apify's built-in scheduling to trigger a scoring run daily or weekly. Point datasetId at the output of a scheduled upstream actor (e.g. Google Maps Email Extractor) and the scoring run will process new leads automatically as they are collected.
How long does a typical run take? Scoring 100 leads takes under 10 seconds. Scoring 1,000 leads takes approximately 30–60 seconds, primarily due to actor startup time. Scoring 10,000 leads takes 2–4 minutes. If datasetId points to a large dataset, loading time adds 10–20 seconds per 10,000 records retrieved.
What is the difference between icpScore and icpFactors? icpScore is the final weighted score (0–100) used for grading and sorting. icpFactors contains the raw 0–100 score for each dimension before weight application — useful for diagnosing which specific dimension is dragging a lead's score down.
Can I run this actor from a Cursor or Claude workflow via MCP? Yes. The Apify platform exposes actor runs through the Apify MCP server. You can call this actor from any LLM agent that supports MCP tool calls, passing leads inline and receiving scored results in the same response cycle.
Help us improve
If you encounter issues, you can help us debug faster by enabling run sharing in your Apify account:
- Go to Account Settings > Privacy
- Enable Share runs with public Actor creators
This lets us see your run details when something goes wrong, so we can fix issues faster. Your data is only visible to the actor developer, not publicly.
Support
Found a bug or have a feature request? Open an issue in the Issues tab on this actor's page. For custom ICP configurations, pipeline integrations, or enterprise scoring volumes, reach out through the Apify platform.
How it works
Configure
Set your parameters in the Apify Console or pass them via API.
Run
Click Start, trigger via API, webhook, or set up a schedule.
Get results
Download as JSON, CSV, or Excel. Integrate with 1,000+ apps.
Use cases
Sales Teams
Build targeted lead lists with verified contact data.
Marketing
Research competitors and identify outreach opportunities.
Data Teams
Automate data collection pipelines with scheduled runs.
Developers
Integrate via REST API or use as an MCP tool in AI workflows.
Related actors
GitHub Repository Search
Search GitHub repositories by keyword, language, topic, stars, forks. Sort by stars, forks, or recently updated. Returns metadata, topics, license, owner info, URLs. Free API, optional token for higher limits.
Weather Forecast Search
Get weather forecasts for any location worldwide using the free Open-Meteo API. Returns current conditions, daily and hourly forecasts with temperature, precipitation, wind, UV index, and more. No API key needed.
EUIPO EU Trademark Search
Search EU trademarks via official EUIPO database. Find registered and pending trademarks by name, Nice class, applicant, or status. Returns full trademark details and filing history.
Nominatim Address Geocoder
Geocode addresses to GPS coordinates and reverse geocode coordinates to addresses using OpenStreetMap Nominatim. Batch geocoding with rate limiting. Free, no API key needed.
Ready to try Lead Scoring Engine?
Start for free on Apify. No credit card required.
Open on Apify Store