Bulk Phone Number Validator & Formatter - E.164, Line Type avatar

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

Pricing

from $0.35 / 1,000 phone validateds

Go to Apify Store
Bulk Phone Number Validator & Formatter - E.164, Line Type

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

Bulk phone validator and formatter using Google's libphonenumber. Per number: valid/invalid, E.164, national and international formats, country, line type (mobile/landline/VoIP/toll-free), carrier lookup. Check mobile or landline, clean lists before you dial. No API key, no network. CSV, Excel.

Pricing

from $0.35 / 1,000 phone validateds

Rating

0.0

(0)

Developer

Flash Scrape

Flash Scrape

Maintained by Community

Actor stats

0

Bookmarked

6

Total users

3

Monthly active users

14 hours ago

Last modified

Share

Bulk phone number validator, E.164 formatter and mobile/landline checker for SDR teams, SMS senders and CRM owners. Paste numbers in any format — international, local, messy copy-paste — and each one comes back valid or not, normalized to E.164 / national / international, with country, line type (mobile, fixed line, VoIP, toll-free…) and best-effort carrier. Every check runs fully offline against Google's libphonenumber metadata: no API key, no network calls, no proxies — at $0.50 per 1,000 numbers.

Copy-paste input to start:

{
"phones": ["+1 415 555 0132", "+212 661-234567", "+44 20 7946 0958", "not a phone"],
"defaultRegion": "US"
}

Only phones is required — an array, one number per line, or a single string separated by newlines, commas, or semicolons.

What it does

  • Validates each number with Google's libphonenumber — the same library that powers Android's dialer — returning both a strict valid flag and a looser possible flag.
  • Normalizes every valid number into three formats: E.164 (+14155550132), international (+1 415-555-0132), and national ((415) 555-0132), so your dialer, SMS gateway, and CRM all get the format they expect.
  • Classifies the line typemobile, fixed_line, fixed_line_or_mobile, voip, toll_free, premium_rate, shared_cost, pager, and more — so you can skip landlines in an SMS campaign or flag premium-rate traps.
  • Identifies the country and location: the country name (United States, Morocco), a human-readable locality/region description (San Francisco, CA) where available, the ISO region code (US, MA, GB), and the country calling code.
  • Looks up the carrier (best-effort, from libphonenumber's carrier metadata) where available.
  • Parses local numbers without a + prefix using a defaultRegion you choose, so 020 7946 0958 parses correctly as a UK number when defaultRegion is GB.
  • Deduplicates on the normalized E.164 form (on by default) — the same number written three ways (+1 415 555 0132, +14155550132, (415) 555-0132) collapses to one billed row. Optionally drop invalid numbers from the output so the dataset is import-ready.

Because everything runs locally against bundled metadata, runs are fast and deterministic — no rate limits, no third-party phone-validation API bills, no data sent to external services.

Input

FieldTypeDefaultDescription
phonesarray(required)Phone numbers to validate, one per line: international (+1 415 555 0132) or local (0661 234567, read with the default region). Blank cells are skipped and never billed; spreadsheet floats (14155550132.0) and objects with a phone key (a dataset row piped in as-is) are accepted.
defaultRegionstring"US"Two-letter ISO country code used to read local numbers typed without a + prefix (e.g. US, MA, FR, GB). USA, UK or a country name are recognised too and noted in the status message. Numbers that start with + ignore it.
onlyValidbooleanfalseDeliver (and bill) only numbers that pass full validation. Dropped rows are counted in the status message, never billed.
dedupebooleantrueCollapse the same number written different ways into one row (keyed on the normalized E.164 form after validation), so a duplicate is billed once.

Output

Each dataset row is one validated number:

FieldDescription
inputThe raw number exactly as you provided it
validtrue if the number is fully valid for its region
possibletrue if the number has a plausible length/structure (looser check)
e164Normalized E.164 format (+14155550132)
international / nationalInternational and national display formats
countryCountry name derived from the region code (United States, Morocco, United Kingdom)
locationHuman-readable locality / region description (San Francisco, CA) where libphonenumber has geo metadata; empty otherwise
region_codeISO region code (US, GB, MA)
country_codeNumeric calling code (1, 44, 212)
number_typemobile, fixed_line, fixed_line_or_mobile, voip, toll_free, premium_rate, …
carrierCarrier name where metadata exists (best-effort)
statusvalid, possible_but_invalid, invalid, or parse_error:<code> (libphonenumber's numeric code: 0 invalid country code, 1 not a number, 2 too short after the international prefix, 3 too short, 4 too long)
reasonPlain-English explanation for every non-valid row (not a phone number, too long for +1, right length for GB, but not an assigned number range, no + prefix and the number cannot be read with the default region…); null on valid rows. Last column, so existing exports keep their column order.

A real row (2026-08-23):

{
"input": "+212 661-234567",
"valid": true,
"possible": true,
"e164": "+212661234567",
"international": "+212 6 61 23 45 67",
"national": "06 61 23 45 67",
"country": "Morocco",
"location": null,
"region_code": "MA",
"country_code": 212,
"number_type": "mobile",
"carrier": "Maroc Telecom",
"status": "valid",
"reason": null
}

Export the dataset to CSV, Excel, or JSON straight from the Apify Console, or pull it via the API.

Example output

Real rows from a run of the validation engine (2026-08-23, defaultRegion: "US"):

inputvalide164countrylocationnumber_typecarrier
+1 415 555 0132true+14155550132United StatesSan Francisco, CAfixed_line_or_mobile
+212 661-234567true+212661234567MoroccomobileMaroc Telecom
+44 20 7946 0958true+442079460958United KingdomLondonfixed_line
not a phonefalse

Pricing — what does it cost to validate 1,000 phone numbers?

$0.50 per 1,000 numbers on the Apify free plan; paid Apify plans get their usual per-tier discount. Pay-per-event: you're charged one result event per row that lands in your dataset, and only after it has landed — delivered and billed are always the same number. No subscription, no minimum, no charge for runs that deliver nothing (the status message then names the cause and ends with "You were not charged."), and E.164 dedupe means the same number pasted in three formats bills once. A free Apify plan's monthly credit is enough to validate thousands of numbers before spending anything.

FAQ

How do I check if a phone number is mobile or landline?

Run the list and read the number_type column: mobile and fixed_line are answered directly for most countries. One honest caveat: in the US and Canada the numbering plan doesn't separate mobile from landline ranges, so most valid US numbers return fixed_line_or_mobile rather than a definitive answer (the real sample above shows it). A definitive US split needs a live carrier (HLR) lookup, which this actor deliberately doesn't do. For SMS prep, keep mobile + fixed_line_or_mobile rows and drop fixed_line, voip and toll_free.

Does "valid" mean the number is currently in service?

No. Validation is structural: the number matches the official numbering plan for its country (right length, real prefix, assigned range). It cannot tell whether a specific line is currently active or answered — that would require a live carrier (HLR) lookup, which this actor deliberately doesn't do. It reliably catches typos, fake numbers, wrong lengths, and impossible prefixes.

How accurate is the carrier field?

Best-effort. Carrier names come from libphonenumber's metadata and reflect the carrier the number range was originally assigned to. Ported numbers may show the old carrier, and many ranges (especially US fixed lines) have no carrier metadata at all — you'll get null there.

How do local numbers without a + prefix get parsed?

Through defaultRegion. It matters: 020 7946 0958 with defaultRegion: "US" comes back invalid (reason: too long for +1), but with defaultRegion: "GB" it parses as a valid London fixed line. If your list mixes countries, prefer full international format with +, which ignores the default region entirely. USA, UK and country names (Morocco) are read as their ISO code and noted in the status message; a region nobody can read (Narnia) stops the run before billing when any number lacks a + prefix, with a status message saying which numbers could not be read — instead of billing every local number as a parse error.

What happens to numbers that can't be parsed?

They still get a row (unless onlyValid is on) with valid: false, a status like parse_error:1 (the numeric libphonenumber code, kept stable for filters) and a reason column that says it in words — not a phone number, too long, no + prefix and the number cannot be read with the default region — so you can audit exactly which inputs were rejected and fix them upstream. Numbers that parse but fail validation get a reason too (too short for +1, local-only length for +1 (missing area code?), right length for GB, but not an assigned number range). Blank cells (null, empty strings) are skipped, counted in the status message, and never billed.

Is there a limit on list size?

No hard limit in the actor. Validation is offline and fast (roughly 10,000+ numbers per second), so even lists with hundreds of thousands of numbers finish in minutes. Rows are written to the dataset in chunks of 500 as they are validated and each chunk is billed right after it lands — so if a run ever hits its timeoutSecs or your maxTotalChargeUsd, everything already delivered stays in the dataset, the status message says exactly how many numbers were validated and how many remain, and you are billed only for the delivered rows. Dedupe (on by default) keys on the normalized E.164 form, so you never pay twice for the same number written two ways.

Do I need proxies or an API key?

No. The actor makes zero network requests — every check runs locally against bundled metadata, so there's nothing to block, rate-limit, or subscribe to.

How do I automate this?

Call the actor from the Apify API with your list in the phones field, or put it on an Apify Schedule to re-validate your CRM export weekly. The dataset is available as CSV/JSON/Excel the moment the run finishes, and you can wire it to Zapier/Make via Apify integrations.

Every run comes with a report

Every run that delivers at least one row also saves a REPORT record to the run's key-value store: a single self-contained HTML page with the verdict split (valid / possible-but-invalid / invalid / parse error), line types, top countries and carriers, the mobile / SMS-capable count and the first 100 rows. Find it on the run's Output tab → REPORT, or follow the Report: link in the status message. It is one file with no external assets, safe to forward or screenshot; the dataset stays the source of truth.

Run summary for API and scheduled callers

Every run — including zero-row ones — writes a RUN_SUMMARY key-value record: input count, blank inputs skipped, numbers validated, rows removed by onlyValid, duplicates merged, delivered, billed, valid / invalid / parse-error / SMS-capable counts, whether the time budget or the charge limit cut the run short, the cause of a zero-row run (no_input, bad_region, only_valid_removed_all, charge_budget, time_budget, push_failed) and the report URL. Read it with GET /v2/key-value-stores/{storeId}/records/RUN_SUMMARY instead of parsing the status message.

What the status message tells you

  • A delivering run: Done - N number(s) delivered: V valid, I invalid, M mobile / SMS-capable. plus the report link and every note that changed the bill (rows onlyValid removed, duplicates merged, blank inputs skipped, a salvaged defaultRegion, local numbers that could not be read with it).
  • A zero-row run exits SUCCEEDED with the real cause and ends with "You were not charged." — empty phones, an unreadable defaultRegion with local numbers in the list, onlyValid removing every row, a maxTotalChargeUsd with no room, or a time budget that ran out before the first number.
  • A dataset push that fails mid-run is reported as a failure (Delivered N of M number(s) before the dataset push failed…), never as "no results", and you are billed only for the rows that landed.

What this actor does NOT do

  • No live-line (HLR) lookup — it can't tell whether a line is currently active, in service, or answered
  • No owner lookup — no names, no addresses, no spam scores, no do-not-call registry checks
  • Carrier is assignment-time, not ported reality — a number moved to a new carrier may still show the original one
  • It doesn't verify email addresses — the email column of the same list goes to Bulk Email Verifier

Use cases

  • Sales prospecting — clean the phone column of a scraped lead list before handing it to SDRs, so nobody wastes dials on numbers that were never valid.
  • SMS campaign prep — filter by number_type and drop landlines, VoIP, and toll-free numbers that can't receive texts, protecting your sender reputation and per-message spend.
  • CRM hygiene — normalize every contact to E.164 so HubSpot, Salesforce, or your dialer stops choking on (0)6-12 34 56 78-style formatting, and dedupe contacts that are the same number written two ways.
  • Agency deliverables — if you sell lead lists on Fiverr or Upwork, run every list through the validator and ship a valid column plus proper formatting as part of your quality guarantee.
  • Call-center routing & compliance — split lists by country and region code to route to the right team, and flag premium_rate numbers before your auto-dialer ever touches them.
  • Bulk Email Verifier — the email counterpart from the same publisher: verify and score the email column of the same lead list before you hit send.
  • Local Business Leads — scrape local business leads with phones and MX-verified emails, a natural upstream source for this validator.
  • Email Pattern Finder — guess likely work emails from a name + company domain.

Found a bug or missing a feature? Open an issue on this actor's Issues tab — typical response within 1 business day.


More from Flash Scrape

Same publisher, same rules: no API keys, pay per row, filters run before billing.