Remove Duplicate Leads - Google Maps & Apollo-style Lists avatar

Remove Duplicate Leads - Google Maps & Apollo-style Lists

Pricing

from $2.00 / 1,000 dedup runs

Go to Apify Store
Remove Duplicate Leads - Google Maps & Apollo-style Lists

Remove Duplicate Leads - Google Maps & Apollo-style Lists

Your Google Maps and Apollo exports are full of duplicates. Fuzzy-match name, phone, domain, address and map location, merge each group into one richest record and see exactly why. Also normalizes addresses and links records across sources. No login, no API key.

Pricing

from $2.00 / 1,000 dedup runs

Rating

0.0

(0)

Developer

mohamed alaya

mohamed alaya

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

16 days ago

Last modified

Share

Your Google Maps scrape, Apollo export or CRM CSV has the same business or person three times, spelled three ways. This Actor finds them with fuzzy name, phone, e-mail, website domain, address and map-location matching, merges each group into one record that keeps the richest data, and tells you exactly why rows were merged. No login, no API key, no browser.

Use it right after a Google Maps scraper run (point it at the run's dataset), after a lead-finder / Apollo-style export, or on any CSV. It also has two extra modes that replace separate tools: entity resolution (link rows across sources without deleting anything) and address / phone / e-mail normalization.

What it does

ModeResult
dedupe (default)One clean row per real business or person. Duplicates merged, gaps filled from the other copies, nothing silently lost.
resolveEvery row kept, each tagged with a shared _entityId so you can join several sources (Maps + Apollo + your CRM). Golden records saved to GOLDEN_RECORDS.
normalizeStandardised address parts (street, number, unit, city, region, postcode, country for US / UK / DE / FR), digits-only phone, canonical e-mail, website domain. No merging.

How two rows are compared

Rows are first grouped by cheap keys (phone, domain, e-mail, Google place id, LinkedIn URL, normalised name + city, address, ~200 m map cell) so a 100k-row list never needs a slow all-pairs comparison. Inside a group each pair is scored 0-100 from the fields both rows have:

  • name: business names ignore "LLC / Inc / The", "&" vs "and", accents, word order and "Roasters"-style add-ons; person names understand nicknames (Jen = Jennifer, Bill = William), initials ("J. Adams") and swapped order
  • phone (last 10 digits, so +1 512-555-0134 = (512) 555-0134), e-mail (plus-tags and Gmail dots ignored), website domain (tracking parameters, www. and paths ignored; Facebook / Linktree / Wix subdomains never count as identity), street address (Street = St, unit numbers, postcode), map distance (within ~40 m)
  • a shared Google placeId, the same LinkedIn profile or the same personal e-mail merges immediately
  • a pair with only one comparable field can never auto-merge, a different name is not rescued by a shared phone alone, and two branches of a chain at different addresses stay separate

Pairs that land between the review and merge thresholds are not merged: they are listed in REVIEW_PAIRS with the evidence so you decide. A cap on group size stops one weak link from chaining thousands of rows together.

Input

FieldDefaultWhat it does
records / datasetIds / sourceUrl / csvTextbuilt-in Google Maps sampleWhere the leads come from. Combine freely. Pick a dataset or pass its ID (any Actor run works).
modededupededupe, resolve or normalize.
schemaautoGoogle Maps (businesses), lead finder (people) or generic CRM. Auto-detect reads the column names.
fieldMap{}Override columns, e.g. {"name":"Company Name","phone":"Tel"}.
matchThreshold / reviewThreshold85 / 70Merge at or above, list for review in between.
mergePolicyrichestWhich value wins on conflict: richest record, longest, most common, first. Empty fields are always filled from the copies.
outputModecleanclean list only, clusters (merge report) or all.
addDedupeFieldstrueAdds _dedupeClusterId, _dedupeSize, _dedupeConfidence, _dedupeSourceRows, _dedupeMatchedOn.
maxClusterSize, maxBlockSize, maxRecords25, 500, 200000Safety limits.

Started with an empty input the Actor runs on a 14-row Google Maps sample (5 duplicates) so you can see the output.

Output

Dataset (default clean): one row per real entity, original columns untouched plus the optional _dedupe* columns.

{
"title": "Blue Door Dental Care",
"categoryName": "Dentist",
"address": "120 Main St, Austin, TX 78701",
"phone": "(512) 555-0134",
"website": "https://www.bluedoordental.com/",
"totalScore": 4.8,
"reviewsCount": 212,
"placeId": "ChIJ_bluedoor_A",
"_dedupeClusterId": "C00001",
"_dedupeSize": 2,
"_dedupeConfidence": 98,
"_dedupeSourceRows": "1,2",
"_dedupeMatchedOn": "name, phone, address, domain"
}

With outputMode: all or clusters you also get a report row per merged group:

{ "recordType": "cluster", "clusterId": "C00001", "size": 2, "confidence": 98,
"whyMerged": ["row 1 ↔ row 2: score 98 (name ✓ 95%, phone ✓ 100%, address ✓ 100%, domain ✓ 100%)"],
"conflicts": [{ "field": "website", "values": ["https://www.bluedoordental.com/", "http://bluedoordental.com/?utm_source=google"], "kept": "https://www.bluedoordental.com/", "rule": "richest" }],
"members": [ ... the original rows ... ] }

Key-value store: CLEAN.csv (one-click re-import file), REVIEW_PAIRS, CLUSTERS, SUMMARY (rows in / out, duplicates merged, conflicts by field, thresholds used). Resolve mode also saves GOLDEN_RECORDS and GOLDEN_RECORDS.csv.

Tested on

  • the sample above (14 Google-Maps-shaped rows, 5 true duplicates, including two Hill Country Coffee branches that correctly stay separate): 9 clean rows, 0 wrong merges
  • synthetic Google-Maps-shaped lists with known ground truth (reformatted phones, St/Street, reworded names, missing fields, moved coordinates): 5,000 rows and 200,000 rows both reached 99.99%+ pair precision and 100% recall
  • synthetic people lists (nicknames, initials, changed job titles, missing e-mail / phone): 5,000 rows, 99.9% precision, 100% recall. Two different people who share the same name, employer and e-mail pattern are genuinely ambiguous; they are merged only when nothing contradicts it, so check REVIEW_PAIRS on such lists
  • speed: 200,000 Google-Maps rows are matched in about 45 seconds on a laptop-class CPU (8 million pair comparisons)

These are synthetic benchmarks, not a promise for your data. Start with the default thresholds and read REVIEW_PAIRS.

Use after the Google Maps scraper

  1. Run a Google Maps scraper for several overlapping searches ("dentist Austin", "dental clinic Austin", ...).
  2. Start this Actor with the scraper's datasetId (or several, one per search).
  3. Download CLEAN.csv or connect the dataset to your CRM, then score the clean list with Google Maps Lead Scorer.

Works with Make, Zapier and n8n through the Apify integrations: trigger on "Actor run succeeded" and read the default dataset. From code:

curl -X POST "https://api.apify.com/v2/acts/that_red_bird~lead-list-deduplicator/runs?token=$APIFY_TOKEN" \
-H 'content-type: application/json' \
-d '{"datasetIds":["YOUR_MAPS_DATASET_ID"],"mode":"dedupe","matchThreshold":85}'

AI agents can call it as an Apify Actor tool (MCP) with the same JSON input.

Pricing

Pay per event: $0.002 per run + $0.002 per clean row exported (report rows are free). 10,000 leads that shrink to 7,000 cost about $14. Rows that fail to parse are never charged, and the run stops cleanly if you set a maximum cost.

FAQ

Will it delete good data? No. Duplicates are merged into the richest record, empty fields are filled from the others, and every conflicting value is kept in the cluster report. Turn outputMode to all to see everything.

Two branches of the same chain? Different addresses or coordinates keep them apart. Same name with the same address, phone or map pin merges them.

A column it does not understand? Set fieldMap. Nested fields (location.lat, address.city) are read automatically.

Other countries? Matching on name, phone, domain, e-mail and map position works anywhere. Structured address parsing covers US, UK, Germany and France; elsewhere the street text and postcode are compared as text.

Does it look anything up online? No. Nothing leaves the run; there is no geocoding, no e-mail verification and no website fetching.

Support

Found a wrong merge or a missed duplicate? Open an issue on the Actor page with two example rows and we will tune the matcher. If it saved you time, a short review helps other people find it.