Phone Number Validator & Formatter avatar

Phone Number Validator & Formatter

Pricing

from $3.00 / 1,000 phone validateds

Go to Apify Store
Phone Number Validator & Formatter

Phone Number Validator & Formatter

Validate, classify and format phone numbers in bulk from Apify datasets, CSV files and inline JSON. Offline validation (E.164, line type, country) — no scraping, no carrier APIs.

Pricing

from $3.00 / 1,000 phone validateds

Rating

0.0

(0)

Developer

Data Runner

Data Runner

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Phone Number Validator & Formatter — Bulk Validation, E.164 & Line Type

Validate, classify and format thousands of phone numbers in one run. Turn messy, scraped phone data — (813) 555-0142, 813.555.0142, 0034 612 345 678, Call us! — into clean, consistent, ready-to-dial numbers with E.164 formatting, country detection, and line-type classification (mobile vs landline vs VoIP). Built for cold calling, SMS campaigns, WhatsApp outreach, CRM imports, and dialer prep.

This is a pure data processor: 100% offline validation powered by a battle-tested phone-number library. No scraping, no proxies, no carrier-lookup APIs — so it never breaks and your data never leaves the run.


Why validate phone numbers before you dial

A scraped phone list is full of landlines, typos, wrong-country numbers, and junk. Loading it straight into a dialer or SMS tool quietly burns money:

  • Stop wasting dialer minutes and agent time. Auto-dialers and power dialers churn through every number. Invalid and unreachable numbers waste connection attempts and skew your contact rates. Filter them out first.
  • Don't pay to SMS a landline. SMS and WhatsApp only work on mobile numbers. Texting a landline is a guaranteed failure you still pay for. Line-type classification tells you which numbers can actually receive a text.
  • Fix country-mixing bugs. A 612 345 678 is a Spanish mobile or an invalid US number depending on context. This Actor applies the right country (per-record hint or a default) so a multi-country list is interpreted correctly.
  • Keep your CRM clean. One consistent E.164 format (+18135550142) means no duplicate "same number, different format" records and clean imports into any CRM, dialer, or outreach platform.

What it does

  • Validates in bulk — every number gets a clear status: valid, possible_but_unverified, invalid_format, or invalid_garbage.
  • Formats consistently — E.164, international, and national formats for every number.
  • Detects line type — MOBILE, FIXED_LINE, FIXED_LINE_OR_MOBILE, VOIP, TOLL_FREE, PREMIUM_RATE.
  • Flags WhatsApp-likely numbers — a whatsappLikely heuristic for mobile-capable lines (great for WhatsApp outreach).
  • Infers country per number, with a per-record country hint (ISO code, English/Spanish name, or address) and a default-country fallback.
  • Cleans the junk — strips tel:, extracts extensions (ext. 12), converts 00 international prefixes, ignores letters/emoji.
  • Handles arrays & many fields — a record can have several phone fields and arrays of numbers; every one is processed.
  • Optional dedupe & filtering — collapse records that share the same E.164, or drop records with no usable number.
  • Never crashes on bad input — malformed rows, missing fields and exotic values are skipped, counted, and the run continues.

How it works (3 steps)

  1. Point it at your data. Apify dataset IDs from previous scraper runs, public CSV URLs, and/or inline JSON.
  2. Tell it where the phones and country live. Auto-detect common phone fields or name them; set a default country and optionally a per-record country hint field.
  3. Run it. Every record comes back enriched with a phoneValidation object, plus a summary breaking down valid/invalid counts by country and line type.

Input example 1 — Validate a previous scraper's dataset

{
"datasetIds": ["aBcD1234efGh5678"],
"defaultCountry": "US",
"countryHintField": "countryCode"
}

Input example 2 — Validate CSV files

{
"csvUrls": ["https://example.com/leads.csv"],
"defaultCountry": "MX",
"outputFormats": ["e164", "international"]
}

Input example 3 — Paste records directly (inline JSON)

{
"inlineRecords": [
{ "businessName": "Acme Plumbing", "phone": "(813) 555-0142 ext. 9", "countryCode": "US" },
{ "businessName": "Tacos El Sol", "phone": "55 1234 5678", "address": "Guadalajara, Mexico" },
{ "businessName": "London Cafe", "phones": ["+44 7400 123456", "020 7946 0958"] }
],
"countryHintField": "countryCode",
"dedupeByPhone": false,
"dropInvalid": false
}

Input options

OptionTypeDefaultDescription
datasetIdsstring[][]Apify dataset IDs from previous runs. Invalid IDs are skipped with a warning.
csvUrlsstring[][]Public CSV URLs. Tolerates BOM, , ; tab | delimiters, quoted fields.
inlineRecordsobject[][]Raw records pasted as JSON.
phoneFieldsstring[][] (auto)Field names holding phones. Empty = auto-detect (phone, mobile, phones, ...).
defaultCountrystringUSISO country for numbers with no international prefix.
countryHintFieldstringField with a per-record country (ISO code, EN/ES name, or address).
outputFormatsstring[]allAny of e164, international, national.
dropInvalidbooleanfalseExclude records whose numbers are all invalid (kept in summary).
dedupeByPhonebooleanfalseCollapse records sharing the same E.164 (keeps most complete).

Output

Every input record is preserved untouched and enriched with a phoneValidation object (keyed by the source field; an array when the field held multiple numbers).

Example — before → after

Before (scraped):

{ "businessName": "Acme Plumbing", "phone": "(813) 555-0142 ext. 9", "countryCode": "US" }

After (validated):

{
"businessName": "Acme Plumbing",
"phone": "(813) 555-0142 ext. 9",
"countryCode": "US",
"phoneValidation": {
"phone": {
"original": "(813) 555-0142 ext. 9",
"status": "valid",
"isValid": true,
"e164": "+18135550142",
"international": "+1 813 555 0142",
"national": "(813) 555-0142",
"country": "US",
"countryName": "United States",
"lineType": "FIXED_LINE_OR_MOBILE",
"whatsappLikely": true,
"extension": "9"
}
}
}

Run summary (key-value store → OUTPUT)

{
"totalInput": 18500,
"withPhone": 17200,
"noPhone": 1300,
"phonesProcessed": 19100,
"valid": 13520,
"possibleButUnverified": 980,
"invalid": 4600,
"byCountry": { "US": 11000, "MX": 4200, "GB": 1800 },
"byLineType": { "MOBILE": 9800, "FIXED_LINE": 5200, "TOLL_FREE": 300 },
"duplicatesCollapsed": 0,
"malformedRowsSkipped": 12,
"runtimeSeconds": 14
}

Works perfectly with the rest of the suite

This Actor is the dial-ready step in the Data Runner lead pipeline:

scrape → deduplicate → verify emails → validate phones → outreach

  • Google Maps Lead Generator Pro — local business leads with phone numbers and addresses.
  • Lead Deduplicator & Merger — merge and de-duplicate lists from multiple scrapers first.
  • Email Verifier & Enricher Pro — clean the email side of the same list.
  • Website Email Extractor — pull contact data from any website list.
  • Instagram / TikTok / YouTube Email Scrapers — creator and business contacts.

Run your scrapers, dedupe and merge, verify the emails, then validate the phones here — and load a list that's truly ready to call and text.


Pricing

Simple, transparent pay-per-event pricing:

  • $3.00 per 1,000 phone numbers processed ($0.003 each).

You are billed per phone number that reaches validation, as work happens (so partial runs only bill for what was handled). Important details:

  • A record with 3 phone numbers generates 3 charges — you pay per number, not per record.
  • Invalid results are charged, because the validation is the work performed (an "invalid" answer is still a useful answer).
  • Pure junk is NOT charged — values with too few digits to be a phone, records with no phone field, and malformed CSV rows are free.

There is no per-run start fee.


Honest limitations (read this)

Offline validation checks a number's format, length, numbering-plan range, and line type. It is fast, free of carrier fees, and private. What it does not do:

  • It does not confirm the line is currently active / in service (no carrier HLR ping).
  • It does not confirm a number is registered on WhatsAppwhatsappLikely is a line-type heuristic (mobile-capable), not a registration check.
  • It does not detect number portability (a number ported to a different carrier or type).

For most outreach prep — filtering junk, separating mobiles from landlines, fixing formats and countries — offline validation is exactly what you need, without paying per-lookup carrier fees. If you need live line-status, pair this with a carrier-lookup service after pre-filtering here (it'll cost far less, because you've already removed the junk).


FAQ

Which countries are supported? All of them. The underlying numbering-plan metadata covers every country and territory. defaultCountry and the country-hint field control how local (non-+) numbers are interpreted.

What does the default country actually do? It only affects numbers written without an international prefix (e.g. a local 813...). Numbers that already start with + or 00 keep their own country regardless of the default.

Can a record have multiple phone numbers? Yes. Multiple phone fields and arrays of numbers are both supported — every number is validated and you're billed per number.

What happens to extensions? Extensions (ext. 12, x12, #12) are detected, removed before validation, and returned separately in the extension field.

How does the country hint work? Point countryHintField at a field that holds a country — an ISO code (MX), an English or Spanish country name (Mexico / México), or even an address that contains a country name. It's used per record, falling back to defaultCountry.

Which export formats can I get? Results land in a standard Apify dataset — export as CSV, JSON, Excel, or HTML.

Is this GDPR/privacy-friendly? Validation is 100% offline — numbers are processed in your own run and never sent to any third-party service. You remain the data controller for your own lists; use them in line with applicable laws and the consent you've obtained.

Will it crash on a messy file? No. Malformed rows, missing fields, arrays where strings were expected, and exotic values are skipped, counted in the summary, and the run continues. It only fails if there are zero processable records at all.