List Cleaner & Normalizer
Pricing
from $0.0001 / actor start
List Cleaner & Normalizer
Free email list cleaner & email list dedupe / contact list normalizer & mailing list dedupe tool: paste JSON/CSV contact lists, deduplicate, validate emails & domains, download clean rows plus a reject report. B2B list hygiene — free when empty.
List Cleaner & Normalizer — free email list cleaner, email list dedupe & contact list normalizer / mailing list dedupe tool
Paste a raw list of names, emails, domains and phones (JSON or CSV text) and get back a clean, deduplicated, normalized dataset plus a reject report. This Actor is a free email list cleaner / email list dedupe / list validation free / contact list normalizer / mailing list dedupe tool / B2B list cleaner for sales ops teams — no scraping, no SMTP probing, no per-email fees.
Actor: apex-nexus~list-cleaner-normalizer
Store listing: FREE — email list cleaner & contact list normalizer
What it is for
Bring your own data — paste messy prospect, vendor or contact lists as a JSON array of objects or CSV text with a header row (Apify Actor input has no file upload, so pasted text is the input). See Input for the full schema and Output for the returned shapes. The Actor:
- Parses the pasted input (JSON or CSV).
- Normalizes every field: trimmed, whitespace-collapsed; emails and domains lowercased; domains checked as IDNA-valid.
- Deduplicates rows by normalized email (or, when a row has no email, by the name + domain + phone signature) — first occurrence wins.
- Validates email syntax plus domain/MX format (best-effort DNS: a hard domain failure rejects the row, transient DNS problems keep it).
- Strips invalid rows and returns the clean rows plus one reject report with counts, reason codes and the rejected rows.
Typical workflows:
- Sales list cleanup. Paste a messy prospect export; download clean CSV with valid emails only, plus the reject report showing exactly which rows were dropped and why.
- B2B list dedupe. De-dupe by email across merged lists while keeping domain-only and name-only contact fragments.
- Mailing list hygiene. Run before a campaign to strip invalid addresses
and typos (
not-an-email, empty rows) without paying per-email validation fees. - Domain list normalizer. Lowercase and de-dupe domain lists, validate that each domain resolves.
What this is NOT
This is explicitly not a tracker: no watchlist state, no delta alerts, nothing remembered between runs. Each run is stateless and independent. It is also not an SMTP/MX email validator: it does not probe mail servers, does not check mailbox existence, and does not use paid enrichment APIs — the domain check is DNS format/resolution only, so it is safe on any list. The Actor is free when there is nothing to return (empty input → empty dataset).
Data sources
User-supplied data only. The Actor never fetches third-party data — the only external lookups are best-effort DNS MX/A resolution of email domains (public DNS, no credentials, no proxies, no API keys, no LLMs).
Search terms (Store discovery)
Users find this Actor on the Apify Store with terms such as:
- email list cleaner
- list validation free
- domain list normalizer
- mailing list dedupe tool
- B2B list cleaner
- contact list normalizer
- email list dedupe
The Store title and description carry the core terms ("List Cleaner & Normalizer", "email list cleaner", "contact list normalizer", "mailing list dedupe tool", "reject report"); this section lists them for reference when updating the listing metadata.
Input
See .actor/input_schema.json. All fields are optional; the default run
cleans the built-in mixed list (names, emails, domains, phones with
duplicates and invalid rows).
| Field | Type | Default | Description |
|---|---|---|---|
inputText | string (textarea) | built-in mixed list | Pasted list: JSON array of objects (name, email, domain, phone, …) or CSV text with a header row. |
normalizeDomains | boolean | true | Lowercase emails/domains; trim and collapse whitespace on every field. |
rejectInvalidEmails | boolean | true | Drop rows whose email fails syntax validation or whose domain publishes no MX and resolves to no A/AAAA record. |
maxRejectedReported | integer | 500 | Cap on rejected rows embedded in the reject report (counts stay exact), 1–5000. |
Example input (default run):
[{"name": "Alice Smith", "email": "ALICE@Example.COM ", "domain": "Example.COM", "phone": "+1 (555) 0100"},{"name": "Bob Jones", "email": "bob@example.com", "domain": "example.com", "phone": "555-0100"},{"name": "Carol Davis", "email": "not-an-email", "domain": "example.com", "phone": "555-0200"},{"name": "Frank Miller", "email": "FRANK@Example.COM", "domain": "Example.COM", "phone": "+1-555-0100"},{"name": "Grace Lee", "email": "", "domain": "example.com", "phone": "555-0500"}]
Example input (CSV):
name,email,domain,phoneAlice Smith,ALICE@Example.COM,Example.COM,+1 (555) 0100Carol Davis,not-an-email,example.com,555-0200
Output
One clean_record dataset item per valid row, plus exactly one
reject_report item (last item). Download the whole dataset as CSV or JSON
from the Apify run — clean CSV and the reject report together.
See .actor/output_schema.json and .actor/dataset_schema.json.
| Field | Type | Description |
|---|---|---|
_type | string | "clean_record" or "reject_report" |
rowId | integer | Sequential id of the clean row (clean_record) |
name | string | Normalized name |
email | string | Normalized email (lowercased) |
domain | string | Normalized domain (lowercased, IDNA-valid) |
phone | string | Normalized phone |
normalizedAt | string | UTC timestamp (ISO 8601) |
inputRows / cleanRows / rejectedRows | integer | Counts (reject_report) |
reasons | object | Rejection count per reason code (reject_report) |
rejected | array | Rejected rows with row index + reason (reject_report) |
generatedAt | string | UTC timestamp (ISO 8601, reject_report) |
Reject reason codes: invalid-email, invalid-domain,
domain-not-resolvable, duplicate, empty-row.
Example output item (clean record):
{"_type": "clean_record","rowId": 1,"name": "Alice Smith","email": "alice@example.com","domain": "example.com","phone": "+1 (555) 0100","normalizedAt": "2026-11-03T12:00:00+00:00"}
Example output item (reject report):
{"_type": "reject_report","inputRows": 10,"cleanRows": 7,"rejectedRows": 3,"reasons": {"invalid-email": 1,"domain-not-resolvable": 1,"empty-row": 1},"rejected": [{"rowIndex": 3, "row": {"name": "Carol Davis", "email": "not-an-email", ...}, "reason": "invalid-email"},{"rowIndex": 4, "row": {"name": "Dave Wilson", ...}, "reason": "domain-not-resolvable"},{"rowIndex": 7, "row": {"name": "", "email": "", ...}, "reason": "empty-row"}],"generatedAt": "2026-11-03T12:00:00+00:00"}
Limits
- One pasted list per run (JSON or CSV text; no file upload).
- Default mixed list (10 rows, duplicates + invalid rows) → 7 clean rows + reject report in well under 5 minutes.
- DNS domain checks are best-effort with a short timeout; transient DNS problems keep the row instead of rejecting it.
- Invalid input finishes with an empty clean dataset plus a reject report rather than crashing.
- Deterministic for a given input: same list in, same clean rows out (apart from timestamps).
Example runs
Default run — built-in mixed list:
{}
CSV paste, keep everything (no domain validation):
{"inputText": "name,email\nA,a@x.com\nB,bad-email\n","rejectInvalidEmails": false}
JSON paste, large reject lists:
{"inputText": "[{\"email\": \"a@x.com\"}, {\"email\": \"a@x.com\"}]","maxRejectedReported": 100}
Quality gate (live, verified)
Actor: apex-nexus~list-cleaner-normalizer (actor id JzALhGjT7HhhQCghP,
private, not published — publication is a director action).
Build: 1.0.1 (Apify build id IaBMBiPQ1MYpg049c, status SUCCEEDED,
tagged latest via apify push -b latest). Apify validated the input/output
schemas during the build.
Default run (input {}, built-in 10-row mixed list with duplicates and
invalid rows): run id WITAafDLwIoTfKxZJ, status SUCCEEDED, exit code 0,
runTimeSecs 3.134 (< 5 min ✓), default dataset nlMYVJdTvIPvcDSAy.
Output: 7 clean rows (Alice Smith, Bob Jones, Eve Wong, Frank Miller,
Grace Lee, Hank Boone, Heidi Cruz — emails lowercased/deduped; ALICE@...
and FRANK@... kept as distinct addresses) plus 1 reject report
(10 input rows, 3 rejected):
invalid-email: 1 —Carol Davis / not-an-emaildomain-not-resolvable: 1 —Dave Wilson / no-such-domain-9x9.invalid(live DNS NXDOMAIN)empty-row: 1 — fully empty row
Competing email list validators on the Apify Store are PAY_PER_EVENT per-address SMTP/MX checkers; this Actor is free, self-service, BYO-data list hygiene.
Claims statement
All claims in this README are limited to what the product verifiably does: it parses user-supplied JSON/CSV contact lists, normalizes and deduplicates them, validates email syntax plus domain/MX format via best-effort DNS, and returns clean rows with a reject report. This README contains no revenue, user, or adoption claims, because none are verified.