LeadPolishclean and qualify lead lists, privately
no storage no account AI optional MIT

Your lead list is a mess.
Half of it isn't worth calling.

LeadPolish cleans a CSV or Excel export, merges the duplicates, verifies every email address and phone number, then grades each record on whether the person behind it is actually worth someone's afternoon. It runs in memory on your own machine. There is no database, no account, and nothing to delete afterwards.

# four commands, then open localhost:8000 pip install -e ".[server]" npm --prefix web install && npm --prefix web run build uvicorn leadpolish.api:app

Measured, not asserted

Every number below comes from benchmarks/run.py against 200 hand-labelled leads. The labels were written from what a person would say after ten seconds on each row, before any of the scoring existed.

Duplicates found
100%
20 of 20 planted duplicates, in every disguise
Wrong merges
0
never merged two records that contradict each other
Grade agreement
100%
163 of 163 records graded as a human would
Junk promoted
0
no worthless record reached grade A or B
Good leads missed
0
no genuine decision maker was buried in C or D
Throughput
50,000
rows cleaned, deduplicated and graded in 42 seconds

What that benchmark is, exactly

200 synthetic leads built to look like a real export: Indian and international names, phone numbers in six formats, duplicates with the surname misspelt, shared info@ mailboxes, disposable addresses, placeholder junk, and free-mail addresses filed under company names. Synthetic data cannot prove behaviour on your list — it can only show the tool does what it claims on data whose right answer is known. Run it yourself: python benchmarks/run.py.


How it works

Column mapping screen showing detected fields

1It reads the file you actually have

Bad encodings, semicolon delimiters, BOMs, blank spacer rows, ragged lines, Excel turning a phone number into 9.82e+09. Columns are detected from the headers and the cell contents, so a column called Column3 full of things with an @ in it is still the email column. Anything it does not recognise passes through untouched.

Duplicate groups with match scores and reasoning

2Nothing is applied until you have seen it

Every proposed change is shown as before → after. Every duplicate group carries its score and its reasoning, and you approve or reject them one at a time. Two records with a different email and a different phone number are never merged on a similar name — they are surfaced for you to judge instead.

Lead quality tab showing grade spread and the best leads

3Then it tells you who to actually call

Each record is scored on four things: can you reach them, can they say yes, is this a real business contact, and do they match the buyer you described. Out comes an A–D grade, a next step, and the reasoning in plain English. Describe your buyer in one click and the ranking rearranges to match.

First page of the client-ready PDF audit report

4And hands you something to give a client

A cleaned CSV or Excel file with the grades written in, plus a PDF report that opens with a plain-English paragraph, shows real before/after evidence rather than only counts, and pairs every issue with what to do about it. Put your own name and logo on it.


Four things nothing else does this way

It checks whether the address belongs to the company

Every tool checks syntax and MX records. LeadPolish also compares the email domain against the website and the company name. So minh.nguyen@vnexpress.net filed under "Minh Corp" gets flagged: the address works, it just belongs to a newspaper. That record passes every other validator on the market.

Qualification against your buyer, not a generic score

A generic lead score answers a question nobody asked. Say you sell to marketing directors in India at registered companies, and the same file reorders itself around that. Records that break a rule are still scored and ranked, and marked so you can filter them out — never silently dropped.

The AI is optional, and it never does the cleaning

The engine is deterministic: same file, same result, no key, no network calls beyond an optional DNS lookup. Paste in your own provider key and the AI gets only what the rules deliberately refused to guess at — the borderline duplicate pairs and a column's distinct values. If the key is wrong or the provider is down, those steps are skipped and the rest is byte-identical.

Your file never leaves the machine

No database, no session, no cache, no temp files. The upload is held in memory for one request and dropped when the response is sent. No webfonts, no analytics, no CDN. Because nothing is stored, there is nothing to delete and no breach surface — closing the tab is the entire cleanup.


What it actually repairs

ProblemWhat happens to it
DuplicatesExact matches on email and phone first, then fuzzy matching you approve group by group. Blank fields on the record you keep are filled in from the copies removed.
Dead email domainsLive DNS check that the domain publishes a mail server. No mailbox is ever probed — that gets your IP blocklisted and lies on catch-all domains.
Disposable & shared inboxes8,000+ throwaway providers, plus info@, sales@ and friends, flagged separately from real problems.
Misspelt domainsgmial.com, hotnail.com, yahooo.com — a correction is suggested, never applied silently.
Phone numbersParsed against every country's published numbering plan, normalised to E.164, with region, line type and carrier. Handles missing country codes, 00 prefixes, leading zeros, extensions and spreadsheet damage.
Namesshaun mcdonaldShaun McDonald. MARY-ANNE VAN DER BERGMary-Anne van der Berg. A name you typed as DeShawn is left exactly as you typed it.
CompaniesPvt Ltd, Private Limited and Pvt. Ltd. all converge, so records that should deduplicate finally do.
Countries & statesusa, U.S.A. and United States of America become one thing. So do KA and karnataka.
JunkN/A, asdf, xxx, keyboard mashing, placeholder emails and empty critical fields — flagged against the row, never quietly dropped.

What it does not claim

A report that overstates its confidence is worse than no report, so these are stated in the tool itself as well as here:

  • A domain that accepts mail is not proof a mailbox exists. LeadPolish checks MX records. It never sends a test message.
  • Line type comes from published numbering plans, not a live carrier lookup. A ported number still reports its original allocation.
  • Fuzzy matching is a judgement call. It shows its score and its reasoning and lets you overrule it.
  • A grade is a ranking, not a verdict. Nothing is deleted on the tool's say-so — low-graded records stay in the file, marked.
  • The benchmark above is synthetic. It shows the tool does what it claims on data whose right answer is known. Your list is the real test.

Under the hood

Engine

Python. Google's libphonenumber for phones, RapidFuzz for matching, RFC-correct email validation, pandas for the table. Runs as a CLI or a library.

Server

FastAPI, fully stateless. Every request carries its own file; the server holds nothing between requests and writes nothing to disk.

Interface

React and Tailwind, built into the Python package so one process serves both. System fonts, no third-party requests.

332 tests, including a labelled calibration set for the duplicate scorer that asserts the lowest true match still outscores the highest false one.