Contact List Cleaner: Fix Phones, Emails & Names, Dedupe
Pricing
from $1.20 / 1,000 contact row cleaneds
Contact List Cleaner: Fix Phones, Emails & Names, Dedupe
Clean a contact list: fix name case, tidy emails (syntax and typos), format and validate phone numbers, then remove duplicates. Takes JSON, CSV or a dataset. Offline logic: no mailbox, DNS or phone-line checks. Pay per contact row.
Pricing
from $1.20 / 1,000 contact row cleaneds
Rating
0.0
(0)
Developer
Data Done Right
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare
Contact List Cleaner: Fix Phones, Emails & Names, Remove Duplicates
Contact List Cleaner fixes phone numbers, emails and names in a contact list and removes duplicate contacts. Give it a JSON list, a CSV link or an Apify dataset; get back one tidy row per contact with +E.164 phone numbers, corrected name capitalisation, cleaned email addresses and a clear list of what was fixed and what is still wrong.
What this does NOT do. It does not check that an email mailbox exists (no DNS lookup, no SMTP, nothing is sent), does not check that a phone line is connected or who owns it, does not enrich contacts, and does not find fuzzy or misspelled duplicates (matches are exact on a normalised key: email, phone, or name plus company). Name splitting is a rule-based heuristic for Western name order; check non-Western names yourself. For mailbox-level email checks use Verify Email Addresses in Bulk: Syntax, MX & Disposable.
What you get
- Names:
JANE DOEbecomesJane Doe,doe, janebecomesJane Doe,van/destay lower case,O'BrienandMcDonaldare handled, titles (Dr) and suffixes (Jr, III) are split out. Mixed-case names are never touched. - Emails: lower-cased, extracted from
Name <a@b.com>ormailto:, syntax-checked (international domains work), role accounts flagged (info@), known domain typos suggested (gmial.comtogmail.com). - Phones: parsed with Google's libphonenumber port (
phonenumbers9.0.41), written as E.164, international or national format, with validity, line type (mobile, fixed line, toll free) and country. - Duplicates: removed or flagged, the most complete row is kept and can be filled from its duplicates.
- Your other columns (id, notes, tags) travel along untouched.
How to clean a contact list
- Paste contacts into Contacts as a JSON list of objects, or set CSV file URL, or pick a Dataset. Sources are combined.
- Column names are detected (
name,Full Name,email,Work Email,phone,Mobile,company,First Name,Last Nameand similar). If detection is wrong, set the column mapping fields. - Set Default country (for example
GB) so numbers written without+44are read correctly. - Pick how duplicates are found and whether to remove or flag them, then press Start.
- Download the dataset as CSV, Excel or JSON. Views: Overview, Phone details, Duplicates. The
SUMMARYrecord has the counts.
How to format phone numbers to E.164 in bulk
Put the numbers in a phone column (or any column and name it in Phone column). Set Default country. Valid numbers come back in phone (in your chosen format) and always in phoneE164. Invalid numbers keep their original text, have phoneValid: false, and an entry in issues telling you why (wrong length, or not valid in that country's numbering plan). A cell with two numbers separated by ; keeps the first as the phone and the rest in extraPhones.
How to remove duplicate contacts from a list
Choose Find duplicates by:
email(default): same address after lower-casing; for Gmail also ignoring dots and+tags;+tagsare also ignored for Outlook, Hotmail, Live, iCloud and Proton.phone: same valid number in E.164 form. Shared office lines can merge different people, which is why this is not the default.emailOrPhone,nameAndCompany,any: matches chain, so A=B by email and B=C by phone puts all three in one group.none: only clean, no duplicate search.
With What to do with duplicates = remove only the most complete row of each group is delivered; with flag every row is delivered with isDuplicate and duplicateOf. Fill gaps from duplicates copies a missing valid email, phone, name or company from a duplicate to the kept row (listed in filledFromDuplicates).
How to fix names and emails in a CRM export
Send the export as CSV or paste the rows. fullName, firstName, lastName, prefix and nameSuffix are filled; changes lists name-recased, name-reordered, email-lowercased, email-extracted, phone-formatted; issues lists problems such as email-invalid: needs exactly one @, email-domain-possible-typo: did you mean ..., phone-invalid: ..., name-contains-digits. Domain typos are only suggested unless you switch on Auto-correct email domain typos.
Input
{"contacts": [{"name": "JANE DOE", "email": "Jane.Doe@GMAIL.com", "phone": "(415) 555-2671", "company": "Acme Inc."},{"name": "doe, jane", "email": "<jane.doe@gmail.com>", "phone": "", "company": "Acme Inc"},{"name": "mcdonald, ronald a. jr", "email": "info@mcdonalds-example.con", "phone": "+44 20 7946 0958", "company": "McD Ltd"}],"defaultCountry": "US","phoneFormat": "e164","dedupeBy": "email","duplicates": "remove","maxContacts": 1000}
| Field | Default | What it does |
|---|---|---|
contacts | 6 sample rows | JSON list of objects, one per contact. |
csvUrl | empty | Public CSV link (header row, up to 25 MB). Internal/private addresses are blocked. |
datasetId | empty | Apify dataset; each item is one contact. |
nameColumn, firstNameColumn, lastNameColumn, emailColumn, phoneColumn, companyColumn | auto-detect | Override the detected column (case and punctuation are ignored). |
defaultCountry | US | ISO country for numbers without +. |
phoneFormat | e164 | e164, international or national. |
fixNameCase | true | Recase ALL CAPS / all lower case names. |
fixEmailTypos | false | Apply known domain typo fixes (otherwise only suggested). |
dedupeBy | email | email, phone, emailOrPhone, nameAndCompany, any, none. |
duplicates | remove | remove or flag. |
mergeDuplicates | true | Fill gaps of the kept row from its duplicates. |
maxContacts | 1000 | Cap on non-empty rows processed and charged (1 to 200,000). |
Output
Real output of the sample input (the input has 6 rows: 1 blank, 5 contacts; shown here are two of the 4 delivered rows, Jane Doe merged with her duplicate):
{"rowNumber": 1, "firstName": "Jane", "lastName": "Doe", "fullName": "Jane Doe","email": "jane.doe@gmail.com", "emailValid": true, "emailDomain": "gmail.com", "emailIsRole": false,"phone": "+14155552671", "phoneE164": "+14155552671", "phoneValid": true, "phoneType": "fixed_line_or_mobile", "phoneCountry": "US","company": "Acme Inc.", "issues": [], "changes": ["name-recased", "email-lowercased", "phone-formatted"],"isDuplicate": false, "duplicatesFound": 1, "duplicateRows": [2], "filledFromDuplicates": []}{"rowNumber": 3, "firstName": "Ronald", "middleName": "A.", "lastName": "McDonald", "nameSuffix": "Jr", "fullName": "Ronald A. McDonald Jr","email": "info@mcdonalds-example.con", "emailValid": true, "emailIsRole": true, "emailSuggestion": "info@mcdonalds-example.com","phone": "+442079460958", "phoneValid": true, "phoneType": "fixed_line", "phoneCountry": "GB", "company": "McD Ltd","issues": ["email-domain-possible-typo: did you mean info@mcdonalds-example.com"],"changes": ["name-reordered", "name-recased", "phone-formatted"]}
(Shortened: unchanged null fields are left out of this README; the real rows contain every field.) Your own extra columns are added to each row under their own names; a column that collides with an output field is renamed input_<name>. emailValid: true means the syntax is valid; a flagged typo domain can still be syntactically valid.
How much does it cost
Pay per event: $0.0015 per contact row cleaned (event contact-row-cleaned, $1.50 per 1,000). A row is charged when it is processed, including rows later removed as duplicates; completely empty rows are free. Lower prices apply on higher Apify plans.
| Rows | Cost |
|---|---|
| 1,000 | $1.50 |
| 10,000 | $15.00 |
| 100,000 | $150.00 |
maxContacts caps the spend, and the Apify run limit is respected: the run stops and says "spending limit" in its status.
Use cases
- Clean a CRM or spreadsheet export before importing it into HubSpot, Salesforce or a mailing tool.
- Convert mixed-format phone numbers to E.164 for an SMS or dialer import.
- Merge duplicate signups from several forms into one row per person.
- Prepare scraped lead lists: tidy names, drop invalid emails and phones, keep source columns.
- Add a cleaning step in an n8n, Make or Zapier flow, or let an AI agent call it through MCP.
FAQ
Does it verify that an email exists? No. It checks syntax, flags role accounts and suggests fixes for known domain typos. No DNS or mailbox check is made, nothing is sent.
Does phoneValid: true mean the number is in use? No. It means the number fits a real numbering plan (libphonenumber rules, version 9.0.41 at build time). It can still be disconnected. The library's data lags new number ranges.
How are names handled? Names that are ALL CAPS or all lower case are recased token by token; mixed-case tokens are left alone. Last, First with a comma is swapped; Smith John without a comma is not (it cannot be told apart from a real name). First name is the first word, last name the last word plus particles like van.
Can it find near-duplicates like Jon and John? No, matching is exact on normalised keys. Use the nameAndCompany mode for same name and company after case, accent and company-suffix (Inc, Ltd, GmbH) normalisation.
Which row is kept among duplicates? The row with the most usable data (name, valid email, valid phone, company); the earlier row wins ties.
What if my CSV link is private? Public links only. Private or internal addresses are blocked and the run notes it in SUMMARY.
Use with the Apify API / MCP / n8n / Make
from apify_client import ApifyClientclient = ApifyClient("<APIFY_TOKEN>")run = client.actor("<username>/contact-list-cleaner").call(run_input={"contacts": [{"name": "JANE DOE", "email": "Jane@Acme.com", "phone": "(415) 555-2671"}],"defaultCountry": "US",})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["fullName"], item["email"], item["phoneE164"])
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<APIFY_TOKEN>' });const run = await client.actor('<username>/contact-list-cleaner').call({contacts: [{ name: 'JANE DOE', email: 'Jane@Acme.com', phone: '(415) 555-2671' }],defaultCountry: 'US',});const { items } = await client.dataset(run.defaultDatasetId).listItems();
In n8n or Make use the Apify node/module "Run Actor" with the same input and read the dataset. AI agents can call it through the Apify MCP server.
Data and credits
Phone parsing uses the open-source phonenumbers package (Apache 2.0, a port of Google's libphonenumber). No external data source or list is downloaded at run time except the CSV you point to.
Related tools
- Remove Duplicates: Deduplicate Datasets, CSV & Excel: generic duplicate removal on any dataset.
- Phone Number Validation & Lookup: Format, Carrier, Line Type: phone-only validation with carrier and time zones.
- Verify Email Addresses in Bulk: Syntax, MX & Disposable: MX and disposable-domain checks for the emails you keep.
- Email Extractor from Text: Emails, Phones & URLs from Any Text: pull contacts out of raw text first.