Bulk Phone Number Validator & Formatter (Offline) avatar

Bulk Phone Number Validator & Formatter (Offline)

Pricing

from $0.56 / 1,000 number checkeds

Go to Apify Store
Bulk Phone Number Validator & Formatter (Offline)

Bulk Phone Number Validator & Formatter (Offline)

Validate, format (E.164 / international / national) and classify phone numbers in bulk with Google libphonenumber. Offline, no data leaves Apify.

Pricing

from $0.56 / 1,000 number checkeds

Rating

0.0

(0)

Developer

James Brown

James Brown

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Phone Number Validator & Formatter (Bulk, Offline)

This phone number validator checks, formats and classifies phone numbers in bulk. Paste a list or point it at a CSV and get E.164, international and national formats, the number type (mobile, fixed line, VoIP, toll-free, premium rate…), region, timezones and carrier name (where Google's data has it) for every number, straight from Google's libphonenumber rules.

Fully offline. No third-party API, no lookups, no scraping. The numbers you submit are checked by a local copy of the libphonenumber rules, so they never leave your Apify run. That makes it fast, cheap and private: $0.80 per 1,000 numbers.

Why use this phone number validator

This actorLookup / enrichment actors
Data sourceLocal libphonenumber rules (Apache-2.0)Third-party carrier / HLR / web lookups
Your numbers sent to a third partyNoOften yes
SpeedThousands of numbers per secondLimited by remote lookups
Cost$0.005 start + $0.0008 per numberVaries: compare their per-number price
Live line status (is the phone switched on?)NoSometimes

If you need to know whether a line is currently live (HLR lookup), this is not that tool. If you need to clean, standardise and classify a list (CRM import, SMS list hygiene, dialler prep, dedupe), this is the cheap and private way to do it. It is an offline alternative to lookup-based actors such as memo23/phone-enrichment and automation-lab/phone-number-validator.

What the phone number formatter returns

original, valid, possible, possibleReason, e164, international, national, countryCallingCode, regionCode, location, numberType, carrier, timezones, extension, duplicateOf, and, only on rows re-written after a restart, recoveredAfterRestart.

Input

FieldDescription
numbersList of numbers in any common format
textFree-text blob, one number per line (or ; separated)
csvUrl + csvColumnPublic CSV URL, read as a stream (up to 200 MB). Column by header name or 1-based index; auto-detects headers like "phone" / "mobile" / "tel"
defaultCountryISO code (e.g. GB, US, DE) used for numbers written without + country code. Default GB
dedupeFlag repeats (compared by E.164) with duplicateOf; duplicates are free. Default on

Run it with no input and you get a 10-number sample.

Example input

{
"numbers": ["+44 20 7946 0958", "07911 123456", "+1 (650) 253-0000", "not a number"],
"defaultCountry": "GB",
"dedupe": true
}

Example output

{
"original": "+44 20 7946 0958",
"valid": true,
"possible": true,
"possibleReason": "IS_POSSIBLE",
"e164": "+442079460958",
"international": "+44 20 7946 0958",
"national": "020 7946 0958",
"countryCallingCode": 44,
"regionCode": "GB",
"location": "London",
"numberType": "FIXED_LINE",
"carrier": null,
"timezones": ["Europe/London"],
"extension": null,
"duplicateOf": null
}

Invalid inputs are still returned, with valid: false and the reason in possibleReason (NOT_A_NUMBER, TOO_SHORT, INVALID_COUNTRY_CODE…), so you can match results back to your source rows.

Pricing (pay per event)

EventPriceWhen it is charged
Actor start$0.005Once per run
Number checked$0.0008Per phone number checked, valid or not (duplicates free)
NumbersApproximate cost
1,000$0.805
10,000$8.005
100,000$80.005
  • Actor start: $0.005 per run (Apify's apify-actor-start event). Maximum run memory is capped at 1,024 MB so the start event is never multiplied.
  • Number checked: $0.0008 per number (number-checked event). Charged for every input that is checked, valid or not.
  • Duplicates flagged by dedupe are not charged.

Example: 100,000 numbers ≈ $80.00 + $0.005. The run stops cleanly if you set a maximum cost per run.

Performance

Numbers are processed as a stream in batches of 1,000, and progress is saved to the key-value store (PROGRESS) so a restart or migration continues where it left off. Results are never lost and never double-charged. In rare cases a platform restart leaves one batch whose outcome is unknown; that batch is written again without charge, so you may see duplicate rows, and every such row carries recoveredAfterRestart: true so you can de-duplicate (drop the flagged row if the number also appears unflagged). Measured end to end on a Windows dev machine (Python 3.11, local file storage, no pricing configured): 20,000 numbers took 66 s with a peak of about 182 MB resident memory (5,000 numbers: 21 s, 180 MB, so memory is dominated by the interpreter and libphonenumber metadata, not by input size). Validation alone runs at roughly 3,400 numbers/s; the rest is dataset writes. A 100,000-number run is projected at about 5-6 minutes and under 256 MB; this projection has not been run on the Apify platform, where dataset write speed will differ.

Data source, licence and compliance

  • Source: the phonenumbers Python port of Google's libphonenumber. Both are licensed under Apache-2.0 (verified 2026-10-21 against the LICENSE file in the python-phonenumbers repository). Apache-2.0 permits commercial use and redistribution with attribution. The bundled metadata (formats, carrier prefixes, timezones, geocoding) is part of the same project.
  • ToS / robots.txt: not applicable to the validation itself. The actor makes no network requests to any data provider, and nothing is scraped. The only network access is when you supply a csvUrl: the actor then fetches that file, identifies itself with a User-Agent, and honours the host's robots.txt (it refuses to fetch if disallowed, and also if robots.txt cannot be fetched or returns a 5xx error; every redirect target is checked again, private/internal addresses are blocked, and requests are spaced about 1 second apart; this cannot be switched off).
  • Credentials in URLs (user:pass@host) are not sent: the actor never makes authenticated requests, so use a URL that needs no login.
  • Attribution: powered by Google libphonenumber via python-phonenumbers (Apache-2.0).
  • Personal data: phone numbers are supplied by you. The actor does not store them beyond the run's dataset and key-value store (which you control and can delete), makes no external calls with them, and logs no numbers, CSV row contents or full URLs. You are responsible for having a lawful basis (e.g. UK GDPR) for processing the numbers you submit.
  • Monitoring / "changed since" mode: not applicable, as there is no external source that changes. Output is deterministic for a given library version.

Limitations

  • Checks numbers against numbering plans and formats, not whether a line is live or who owns it. "Valid" means the number is allocated within a valid range for its country.
  • Carrier is the original allocation holder and is only available for some countries; it is empty for many (including GB, where number portability makes prefix data unreliable). It is never a live lookup.
  • Number type can be FIXED_LINE_OR_MOBILE or UNKNOWN where the plan does not distinguish them.
  • Numbers must be one per row/line; commas are not used as separators in text (use new lines or ;).
  • Rules follow the bundled libphonenumber release and change as new versions are published.
  • CSV input: quoted multi-line fields are parsed as one record. csvColumn takes a header name or a 1-based number; csvHeader (auto/yes/no) says whether the first row is a header, so a headerless file with csvColumn: 2 keeps its first row. The PROGRESS key-value record holds only counters, never numbers.

FAQ

How do I validate phone numbers in bulk? Add them to numbers, paste them into text, or give a public csvUrl. Set defaultCountry for numbers written without a + prefix. Each number becomes one result row.

Can it format phone numbers to E.164? Yes. Every row has e164, international and national formats. Invalid numbers keep valid: false and a reason in possibleReason.

Does it tell mobile from landline and VoIP numbers? It returns numberType (mobile, fixed line, VoIP, toll-free, premium rate and more) from the libphonenumber numbering plans. It does not check whether a line is currently switched on.

Are my numbers sent to a third party? No. Validation runs offline inside your Apify run.