Lead List Cleaner — Dedupe, Phones, Addresses, Websites, Emails avatar

Lead List Cleaner — Dedupe, Phones, Addresses, Websites, Emails

Pricing

from $1.50 / 1,000 row cleaneds

Go to Apify Store
Lead List Cleaner — Dedupe, Phones, Addresses, Websites, Emails

Lead List Cleaner — Dedupe, Phones, Addresses, Websites, Emails

Clean any business lead list (CSV, Google Sheet, JSON or an Apify dataset such as Google Maps results): remove duplicates, format phones (E.164) and addresses, check websites are live and email domains have MX, drop personal emails, add a quality score. $1.50 per 1,000 rows.

Pricing

from $1.50 / 1,000 row cleaneds

Rating

0.0

(0)

Developer

Signalloom

Signalloom

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Features

Limited permissions

Share

Lead List Cleaner: Dedupe, Phones, Addresses, Websites & Emails

Turn a messy business lead list into a clean, de-duplicated one in a single run. Point it at the results of another Actor (Google Maps, store leads, directories), a CSV or JSON file, or paste rows, and every row comes back with your original columns plus clean_* columns:

  • Duplicates found and merged: the same business by website domain, phone number, or name + street address. Branches of a chain (same website, different address) stay separate unless you ask otherwise.
  • Phones in E.164 (+15124949252) with validity, line type (mobile, landline, toll-free, VoIP…), country and national format. Works offline for every country.
  • Addresses standardised: parsed into street, city, state and ZIP; title-cased; USPS-style abbreviations (Boulevard → Blvd, North → N, Suite → Ste); state names → codes (Texas → TX); ZIP and postcode formatting; missing US states filled from the ZIP.
  • Websites checked: root domain, live or dead, HTTP status, HTTPS, where it redirects, parked or for-sale domains, and social or delivery-app pages that aren't a real website.
  • Emails classified: syntax, whether the domain accepts mail (MX record in DNS), company role mailbox vs person-looking, free-mail (Gmail, Yahoo…) vs business domain. No email is ever sent.
  • Quality score 0–100 with a grade and plain reasons ("+25 valid phone", "0 website dead (HTTP 404)").

No paid APIs, no logins, no proxies.

Price: $1.50 per 1,000 unique rows ($0.0015 each). Duplicate rows are free, whether flagged or removed. The prefilled example (16 rows) finishes in a few seconds.

Use this when…

  • you just ran a Google Maps scrape and need to remove duplicate places, fix phone formats and drop businesses whose website is dead
  • you merged several lead lists (two scrapes, a purchased list, a CRM export) and the same business appears in different spellings and formats
  • you're about to import leads into a CRM or dialer (HubSpot, Salesforce, Pipedrive, Close) that needs E.164 phone numbers and one record per company
  • you want to prioritise outreach: sort by quality score, skip rows with invalid phones, dead websites or email domains that can't receive mail
  • you want company contacts only: keep info@ and sales@ style addresses and drop personal ones before your list goes anywhere

It cleans and checks the data you give it; it doesn't search for new leads or find missing emails.

For AI agents

  • Run signalloom/lead-list-cleaner (Apify MCP server call-actor, or the Apify API) with input like {"rows": [{"name": "Joe's Pizza", "phone": "(512) 555 0100", "website": "joespizza.com"}], "defaultCountry": "US"}
  • Returns each input row with your original columns plus clean_* columns: clean_phone (E.164), clean_address, clean_domain, clean_website_status, clean_email, clean_is_duplicate, clean_quality_score. Or pass datasetId / sourceUrl instead of rows.
  • Typical cost: 1,000 rows = $1.50 ($0.0015 per cleaned row); duplicate rows are free.

How to use it

  1. Choose your list (any one, or several together):
    • Apify dataset ID: pick the dataset of an earlier run (Google Maps Scraper, E-commerce Store Leads, any Actor). This is the quickest way to clean scraper output.
    • CSV or JSON file URL: any direct download link. Google Sheets links work when the sheet is shared as "Anyone with the link".
    • Rows (JSON): paste an array of objects.
    • Leave all three empty to try the built-in sample.
  2. Columns are mapped automatically (title/name/company, phone/phones, website/url/domain, email/emails, address or street/city/state/postalCode/country). If yours are named differently, set Field mapping, e.g. {"phone": "Main Phone"}.
  3. Choose Flag or Remove duplicates and which row to keep: Merge (default) keeps the most complete row and fills its missing phone, website, email or address from the duplicates.
  4. Click Start. Export to CSV, Excel or JSON, or send the results to Google Sheets or your CRM with Make, Zapier or n8n. The Unique businesses only view in the dataset shows one clean row per business.

Recipe: clean a Google Maps scrape. Paste the run's dataset ID, set Duplicates to Remove, then sort by clean_quality_score and filter out rows where clean_website_status is DEAD or clean_phone_valid is false.

Output

One row per input row: your original columns first, then the clean_* columns. Real example from the built-in sample (the prefilled run), row 4:

{
"title": "24 Diner",
"phone": "5124725400",
"website": "https://www.24diner.com/",
"email": "info@24diner.com",
"address": "600 N Lamar Blvd Ste 200, Austin, TX 78703",
"clean_row": 4,
"clean_name": "24 Diner",
"clean_phone": "+15124725400",
"clean_phone_valid": true,
"clean_phone_type": "landline_or_mobile",
"clean_phone_country": "US",
"clean_phone_national": "(512) 472-5400",
"clean_website": "https://www.24diner.com",
"clean_domain": "24diner.com",
"clean_website_status": "LIVE",
"clean_website_http_status": 200,
"clean_website_https": true,
"clean_website_redirects_to_domain": null,
"clean_email": "info@24diner.com",
"clean_email_mx": true,
"clean_email_kind": "role",
"clean_email_free_mail": false,
"clean_email_matches_website": true,
"clean_emails_dropped": 0,
"clean_address": "600 N Lamar Blvd Ste 200, Austin, TX 78703",
"clean_street": "600 N Lamar Blvd Ste 200",
"clean_city": "Austin",
"clean_state": "TX",
"clean_postal_code": "78703",
"clean_country": "US",
"clean_is_duplicate": false,
"clean_duplicate_count": 1,
"clean_quality_score": 100,
"clean_quality_grade": "A",
"clean_quality_reasons": [
"+10 business name present",
"+25 valid phone (landline_or_mobile)",
"+25 website live (HTTPS)",
"+25 business email, domain accepts mail (MX)",
"+15 full street address"
]
}

Row 5 of the same run is the same business written differently. It is flagged, not charged:

{
"title": "24 Diner",
"phone": "+1 (512) 472-5400",
"address": "600 North Lamar Boulevard, Suite 200",
"city": "Austin",
"state": "TX",
"postalCode": "78703",
"clean_phone": "+15124725400",
"clean_address": "600 N Lamar Blvd Ste 200, Austin, TX 78703",
"clean_is_duplicate": true,
"clean_duplicate_of_row": 4,
"clean_duplicate_reason": "same phone; same name and address",
"clean_quality_score": 50
}

More from the same run (shortened):

RowBusinessInputResult
14Lick Honest Ice Creamsphone 512-363-562clean_phone_valid: false (one digit short), score 50
10Canary Roost Karaoke Barwebsite canary-roost.business.siteclean_website_status: "DEAD", HTTP 404
6Bennu Coffee Shopemail bennucoffee@gmail.com, no stateclean_email_kind: "brand", clean_email_free_mail: true, state TX filled from the ZIP
8, 9Starbucks (two branches)same website domain, different addressesboth kept: different locations, not duplicates

Other columns: clean_phone_extension, clean_phone_original, clean_other_phones, clean_domain_source, clean_website_is_platform_page, clean_website_live, clean_website_final_url, clean_website_error, clean_email_valid_syntax, clean_email_disposable, clean_emails, clean_emails_invalid, clean_state_from_zip, clean_merged_fields.

Website status values: LIVE (answers, including sites that turn automated visitors away with 401/403/429), DEAD (no DNS record, connection refused, or HTTP 404/410/5xx), PARKED (redirects to a domain-sale or parking page), ERROR (timed out or failed in a way that may be temporary), PLATFORM_PAGE (a Facebook, Yelp or delivery-app page, not checked).

Run summary (key-value store → OUTPUT). Real summary of the prefilled run:

{
"rowsIn": 16, "rowsOut": 16, "uniqueBusinesses": 13, "duplicateRows": 3, "duplicateGroups": 3, "rowsCharged": 13,
"phones": { "valid": 14, "invalid": 1, "missing": 1 },
"websites": { "live": 13, "dead": 1, "parked": 0, "checkFailed": 0, "platformPages": 0, "missing": 2, "uniqueSitesChecked": 13 },
"emails": { "rowsWithEmail": 5, "noMailServer": 0, "freeMail": 1, "personEmailsDropped": 0, "invalidSyntax": 0, "domainsLookedUp": 5 },
"quality": { "averageScore": 74, "grades": { "A": 5, "B": 7, "C": 3, "D": 1 } }
}

How duplicates are decided

Two rows are the same business when they share any of the keys you enable in Match duplicates by:

  • Website domain: https://www.example.com/menu and example.com match. Shared hosting subdomains (name.business.site, name.wixsite.com) count as separate sites, and social or delivery pages (Facebook, Yelp, Uber Eats…) never match.
  • Phone number: compared in E.164, so (512) 472-5400 and +1 512.472.5400 match. Only valid numbers are compared.
  • Name + street address: names compared without punctuation, "The" or legal suffixes (LLC, Inc), addresses after standardising (600 North Lamar Boulevard = 600 N Lamar Blvd).

Branches stay separate. If two rows share a website or phone but have different street addresses, they're treated as different locations of one company, even through a chain of matches. Turn on Merge branches of the same company for one row per company.

Which row is kept: Merge (default) keeps the most complete row and fills its empty clean_* fields from the others; Most complete keeps that row unchanged; First keeps the first row in your list. Your original columns are never merged.

Data handling and privacy

  • Company mailboxes only (default). With Drop person-looking emails on, only company role mailboxes (info@, sales@, reservations@…) and the business's own name (bennucoffee@gmail.com for Bennu Coffee) are kept. Addresses that look like a person's (jane@, j.smith@) are removed from the output, including from your original columns, and counted in clean_emails_dropped. The detection is cautious: a misspelt role mailbox may also be dropped. Turn this off only if you have a lawful basis to process personal email addresses.
  • Only light, polite checks. Each unique website gets one request to its homepage (plus one per redirect); the page content is not read or stored. Email domains are checked with a DNS MX lookup only. The Actor never connects to a mail server or sends email.
  • Your data stays yours. Rows are processed in your run and written only to your run's dataset. Datasets you pick are opened read-only.
  • Use the results lawfully: follow the anti-spam and privacy laws that apply to you (for example CAN-SPAM, GDPR, CASL) when contacting businesses.

Pricing

  • $1.50 per 1,000 unique rows ($0.0015 each)
  • Duplicate rows: free, whether flagged or removed
  • Websites and email domains that appear on several rows are checked once

Limitations

  • Address parsing is rule-based and tuned for the US and Canada (UK postcodes are formatted too). Other countries get whitespace and capitalisation fixes only. There is no geocoding and no check that the address exists.
  • US and Canadian numbers can't be told apart as mobile or landline from the number alone, so they show landline_or_mobile. Other countries usually get an exact type.
  • An MX record means the domain can receive email, not that a specific mailbox exists. For mailbox-level checks, use a dedicated email verification service.
  • A LIVE website answered our request; it may still be a placeholder page. Sites that block automated visits are counted as live because the server exists.
  • Up to 100,000 rows per run (default 10,000). Website checks take most of the time: in our tests 72 sites took about 17 seconds at the default 10 in parallel, so plan on roughly 4–5 minutes per 1,000 different websites. Turn off Check websites are live for a fast run.

The built-in sample uses real Austin, TX businesses from OpenStreetMap (© OpenStreetMap contributors, ODbL). Some rows were reformatted on purpose (spacing, capitals, phone formats, one phone cut short) to show the cleaning.

FAQ

How do I remove duplicate leads from a list?

Give the list (dataset ID, CSV/Sheet link or pasted rows) and run. Rows are the same business when they share a website domain, a phone, or a name plus address; choose Flag to mark them or Remove to keep one row per business. Duplicates are never charged.

How do I clean Google Maps scraper results?

Pass the scraper run's dataset ID in datasetId. Columns are detected automatically; you get formatted phones, standardized addresses, live-website checks and a quality score.

How do I check which websites in my lead list are dead?

clean_website_status says LIVE, PARKED, DEAD or ERROR after one request to each homepage, with the HTTP status and any redirect target.

Does it verify email addresses?

It checks syntax and whether the domain has a mail server (MX), and flags free-mail and disposable domains. It never sends email or contacts a mail server, so it doesn't confirm individual mailboxes.

Feedback

Need another column detected, a country's address format, or a different duplicate rule? Open an issue on the Issues tab.