Lead Data Cleaner, Deduper & Scorer avatar

Lead Data Cleaner, Deduper & Scorer

Pricing

from $1.50 / 1,000 cleaned lead records

Go to Apify Store
Lead Data Cleaner, Deduper & Scorer

Lead Data Cleaner, Deduper & Scorer

Turn messy scraped leads into a clean, deduplicated, scored list. Chain after any Google Maps, LinkedIn or directory scraper. No scraping, no email sending, nothing stored.

Pricing

from $1.50 / 1,000 cleaned lead records

Rating

0.0

(0)

Developer

Logan Bishop

Logan Bishop

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Turn messy scraped leads into a clean, deduplicated list, and see exactly why each lead scored what it did.

Point this Actor at any Apify dataset (Google Maps, LinkedIn, directory or custom scrapers) or paste a few records. It normalizes emails, phones and websites, merges duplicate businesses, flags disposable and role-based emails, and gives every lead a 0–100 quality score with the reasons spelled out. It never scrapes, sends email or connects to mail servers, and it keeps nothing after the run.

What it does

  • Cleans the mess: trims and collapses whitespace, repairs garbled accents (Café becomes Café), fixes ALL-CAPS and all-lowercase business names, strips tracking parameters (utm_*, fbclid, gclid) from websites, and upgrades links to https.
  • Validates emails and phone numbers: checks email syntax, flags disposable domains and role accounts (info@, sales@), suggests fixes for common domain typos (gmial.com becomes gmail.com), and formats phones to international E.164 (+15125550134).
  • Removes duplicate leads: merges records that share a website, phone number, business email or exact name + city, and optionally catches near-identical names in the same city. The merged record keeps the most complete data.
  • Scores every lead 0–100: weighted by completeness and validity, with a plain-English list of reasons next to every score.
  • Checks email domains (optional): a DNS lookup confirms the domain can receive mail. No SMTP probing, ever.

How to use it

  1. Get your records. Run any scraper and copy its dataset ID, or paste records as JSON.
  2. Run the Actor. Set Dataset ID (or Records), pick a Scoring profile, and click Start. Field names such as title, email, phone, website and address are detected automatically.
  3. Use the clean list. Download it as CSV, Excel or JSON from the Dataset tab, or read it through the API.

Chain it after any scraper

JavaScript (apify-client):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
// 1. Run your scraper (replace with the Actor and input you use)
const scraperRun = await client.actor('<your-scraper>').call({ /* scraper input */ });
// 2. Clean its dataset
const cleanRun = await client.actor('hiredhandai/lead-data-cleaner').call({
datasetId: scraperRun.defaultDatasetId,
scoreProfile: 'local-business',
});
// 3. Read the cleaned, scored leads
const { items } = await client.dataset(cleanRun.defaultDatasetId).listItems();
console.log(items.filter((lead) => lead.score >= 70));

Python (apify-client):

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
clean_run = client.actor("hiredhandai/lead-data-cleaner").call(
run_input={"datasetId": "YOUR_DATASET_ID", "defaultCountry": "GB"}
)
for lead in client.dataset(clean_run["defaultDatasetId"]).iterate_items():
if lead["score"] >= 70:
print(lead["name"], lead["email"], lead["score"])

It also works as a step in Make, n8n, Zapier and Google Sheets flows: run your scraper, then pass its defaultDatasetId to this Actor with the Apify integration of your tool.

Input

FieldTypeDefaultDescription
datasetIdstringApify dataset to clean. Pick it in the Console, or pass its ID through the API. Use this or records.
recordsarrayUp to 10,000 inline records (small jobs, API use).
fieldMapobjectauto-detectMap your field names to name, email, phone, website, address, city, country, category. Only needed for unusual names, e.g. {"Company": "name"}.
defaultCountrystringUSTwo-letter code used to read phone numbers written without a country prefix.
dedupefuzzy / exact / offfuzzyHow aggressively to merge duplicates.
checkMxbooleantrueDNS check that each email's domain can receive mail.
scoreProfilegeneral / b2b-outreach / local-businessgeneralWhich signals matter most for your use case.
dropInvalidbooleanfalseRemove records scoring below minScore instead of just labelling them.
minScoreinteger 0–1000Used with dropInvalid.
maxRecordsintegerOptional cap on how many input records are read.

Output

One item per surviving record in the default dataset. Real output from the prefilled example input (three messy records, two of them the same business):

{
"name": "Acme Plumbing LLC",
"email": "info@acmeplumbing.com",
"emailStatus": "valid_syntax",
"emailIsRole": true,
"emailIsDisposable": false,
"phone": "+15125550134",
"phoneStatus": "valid",
"website": "https://www.acmeplumbing.com",
"domain": "acmeplumbing.com",
"city": "Austin",
"country": "US",
"score": 60,
"scoreReasons": ["+10 name", "+25 valid email", "+20 valid phone", "+15 website", "-10 role email"],
"dupeGroupId": "g_1",
"isPrimaryOfGroup": true,
"dupeCount": 1,
"sourceIndex": 0
}
FieldMeaning
emailStatusvalid_syntax, valid_syntax_mx_ok (domain can receive mail), valid_syntax_no_mx, invalid_syntax or missing
emailSuggestionCorrected address when the domain looks like a typo (joe@gmial.com gives joe@gmail.com). The original is left unchanged.
phoneStatusvalid, possible (plausible length, unverified), invalid or missing
score, scoreReasons0–100 and every contribution behind it
dupeGroupId, dupeCountThe duplicate group and how many other records were merged into this one
sourceIndexPosition of the kept record in your input

A run summary is saved to the key-value store as OUTPUT: records in and out, duplicates merged, invalid emails and phones, average score.

How scoring works

The score is deterministic and open, so you can trust and explain it. For the General profile:

SignalPoints
Business name present+10
Valid email+25 (+5 more if the domain accepts mail)
Valid phone+20 (+8 if only "possible")
Website+15
Address+10
Category+5
Name, email, phone, website and address all present and valid+10
Role email (info@, sales@)−10
Disposable email−30
Email domain has no mail server−10

B2B outreach weights email and a verified mail domain most and penalizes role and disposable emails harder. Local business weights phone and address most and is relaxed about role emails. Scores are capped to 0–100.

Pricing

Pay per event, no subscription:

  • $1.50 per 1,000 cleaned records (record-cleaned, $0.0015 each). You are charged for records returned, so duplicates that were merged away are free.
  • A tiny start fee charged by Apify on every run (about $0.00005).
JobRecords returnedCost
500 scraped leads with typical duplicates (about 400 unique)400about $0.60
10,000 unique leads10,000about $15
100,000 unique leads100,000about $150

You can set a maximum cost per run in the run options; the Actor stops cleanly and tells you how many records were not returned. Plan prices and platform usage are covered in the Apify pricing.

Limits

  • Up to 100,000 records per run (10,000 inline). Records larger than 100 KB are skipped and counted in the run summary.
  • Speed measured on Apify (1 GB): 500 records in about 3 seconds; 10,000 records with live email-domain checks in about a minute (turn off checkMx for seconds). Results depend on how fast the email domains answer DNS.

FAQ

Does it send emails? No. It never sends anything.

Does it check whether an inbox exists (SMTP)? No. It only does a DNS lookup of the email's domain. A valid-looking address can still bounce, and the score says "valid email", not "deliverable guaranteed".

What happens to my data? It is processed during the run and written to your own run dataset. The Actor stores nothing else and sends your data nowhere. The only network traffic is DNS lookups of email domain names (not addresses) when checkMx is on.

Does it enrich or look up missing data? No. It only cleans, merges and scores what you give it. No external data sources are used.

How does it decide two records are duplicates? Same website domain, same phone number, same business email (free-mail and disposable addresses are ignored), or the same name and city. In fuzzy mode it also merges near-identical names in the same city, but never when each name has a word the other lacks ("Red Rock Bakery" and "Red Rock Realty") or when numbers differ ("Store 1000" and "Store 1001").

Can I clean a CSV? Upload it as a dataset in Apify, or convert it to JSON and paste it into records.

Which countries work? Any country supported by the phone library. Set defaultCountry so national numbers parse correctly.

Support

Questions, bugs or feature requests: use the Issues tab on this Actor, or email leadcleaner@lbishop.app. I answer within 48 hours.

If this saved you time, a rating on the Actor page helps others find it.