Phone Number Validator & Formatter: E.164 by Country, Offline avatar

Phone Number Validator & Formatter: E.164 by Country, Offline

Pricing

from $0.35 / 1,000 phone number validateds

Go to Apify Store
Phone Number Validator & Formatter: E.164 by Country, Offline

Phone Number Validator & Formatter: E.164 by Country, Offline

Paste phone numbers, get valid/invalid, E.164, national format, country, line type and time zone per row. $0.0005 per number, unparseable rows free. Prefilled input: +1 415-555-2671 -> +14155552671, US, FIXED_LINE_OR_MOBILE. Offline libphonenumber, no API key. Click Start.

Pricing

from $0.35 / 1,000 phone number validateds

Rating

0.0

(0)

Developer

Penny Data

Penny Data

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

15 days ago

Last modified

Features

Limited permissions

Share

Validate Phone Numbers in Bulk: E.164, Line Type - $0.50 per 1,000

Paste phone numbers, get E.164, valid or not, line type, country and region for each. $0.50 per 1,000 numbers, first 3 per run free, unparseable rows free. Click Start: the prefilled 5 numbers run as is. Output below is a real local run of the prefilled input (about 2 s, fictional 555 numbers).

inpute164validtypecountrygeoLocationcarrier
+1 415-555-2671+14155552671trueFIXED_LINE_OR_MOBILEUSSan Francisco, CAnull
+44 20 7946 0958+442079460958trueFIXED_LINEGBLondonnull
+91 98765 43210+919876543210trueMOBILEINnullAirtel
(212) 555-0100+12125550100trueFIXED_LINE_OR_MOBILEUSNew York, NYnull
not a numbernullfalsenullnullnullnull

Try it in Apify Console: the input form opens already filled with a demo input (below), so you can click Start with no setup. A new Apify account includes free monthly credit.

Demo input:

{"phones":["+1 415-555-2671","+44 20 7946 0958","+91 98765 43210","(212) 555-0100","not a number"],"defaultRegion":"US"}

First 3 numbers per run are free (was 25 before 2026-10-25); after that $0.50 per 1,000. Offline libphonenumber, no API key. Enrichment: country, region, timezone, line type.

Validate, parse and format phone numbers in bulk using Google's libphonenumber metadata (via libphonenumber-js). Blank or unparseable inputs are returned with an error code.

Try it free: turn on sampleOnly ("Free sample: first 10 numbers, no charge") to validate the first 10 numbers of your list with no charge at all.

Drop-in compatible with pink_comic/phone-number-validation input (phoneNumbers, defaultRegion, maxResults, includeCarrier, includeGeocoding, includeTimezone).

Inputs saved for other phone validators also run here: phoneNumbers (or numbers, phone) in place of phones, and defaultCountry / defaultCountryCode in place of defaultRegion. Fields we do not return (includeCarrier, includeGeocoding, includeTimezone, formats, maxConcurrency) are accepted and ignored; maxResults limits the list. Output per row: E.164, validity, line type, country, calling code, national and international format; also carrier, region and time zones (offline, on by default).

Paste phone numbers in any format, get back E.164, validity, line type and country. 1,000 numbers = $0.50.

inpute164validtypecountrygeoLocation
+1 202-555-0143+12025550143trueFIXED_LINE_OR_MOBILEUSWashington D.C.
+44 20 7946 0958+442079460958trueFIXED_LINEGBLondon
+49 30 123456+4930123456trueFIXED_LINEDEBerlin
(415) 555-2671+14155552671trueFIXED_LINE_OR_MOBILEUSSan Francisco, CA
12345+112345falsenullUSnull

Try the sample dataset: the full JSON of these 5 rows, a real run of this actor (public, no login).

Offline format check (libphonenumber): no carrier lookup, no API key. Unparseable rows are free. Rows above are real output of this actor with defaultRegion US (fictional 555 numbers).

Pairs with Bulk Email Validator (no SMTP) for lead-list hygiene.

Features

  • Per-row status and run summary: every output row has rowStatus (ok, invalid or error) and rowReason, and each run saves a RUN_SUMMARY record in the key-value store with counts per status, rows billed and free rows.

Quick start

Input (phones is the only field you need):

{ "phones": ["+1 415-555-2671", "+44 20 7946 0958", "abc"], "defaultRegion": "US" }

Numbers in a Google Sheet? Set sheetUrl to the share link (shared as "Anyone with the link can view"; converted to CSV export automatically) and optionally sheetColumn: { "sheetUrl": "https://docs.google.com/spreadsheets/d/<id>/edit#gid=0", "sheetColumn": "Phone", "defaultRegion": "US" }. Output, one row per number (illustrative shape; values for +14155552671):

{ "input": "+1 415-555-2671", "e164": "+14155552671", "valid": true, "possible": true, "type": "FIXED_LINE_OR_MOBILE", "country": "US", "callingCode": "1", "nationalFormat": "(415) 555-2671", "internationalFormat": "+1 415-555-2671", "error": null }

Pricing event: phone-validated, $0.0005 per parseable number; blank or unparseable inputs are free.

Input: phones (list of numbers in any common format), defaultRegion (ISO 2-letter code, used for numbers without a + prefix, default US) and sampleOnly (process only the first 10 numbers, no charge). Inputs saved for other validators also work: phoneNumbers, numbers or phone are accepted in place of phones; phoneNumbersText takes numbers pasted one per line, defaultCountry works like defaultRegion, and onlyValid returns only valid numbers (invalid ones are left out and not charged).

Output per number: input, e164, valid, possible, type (MOBILE, FIXED_LINE, FIXED_LINE_OR_MOBILE, TOLL_FREE, VOIP, ...; null if unknown), country, callingCode, nationalFormat, internationalFormat, error.

Phone number formatter for WhatsApp: E.164 + wa.me click-to-chat link (format only, no WhatsApp account check). The E.164 digits are what a https://wa.me/<digits> link expects. This Actor does not contact WhatsApp and cannot tell you whether a number has a WhatsApp account.

Validate leads from a Google Maps Scraper run

  1. Run a Google Maps scraper (for example compass/crawler-google-places) and copy the dataset ID of the run (Storage tab).
  2. Paste it into inputDatasetId. The actor reads phoneUnformatted, internationalPhoneNumber or phone from each place (first one present) and validates it. Set defaultRegion to the scrape's country for numbers without a +.
  3. Each result row keeps the place's title, placeId, website and address when present, so you can join results back to the scrape.

Example: { "inputDatasetId": "YOUR_DATASET_ID", "defaultRegion": "US", "onlyValid": true }. This checks format and line type offline; it does not call the number or confirm it is in service.

UK, India and Brazil phone number validator

UK, India and Brazil phone number validator: +44, +91, +55 numbers parsed, validated and formatted offline. Set defaultRegion to GB, IN or BR for local-format numbers, or use the + prefix.

Telefonnummern validieren - Español, Deutsch, Português

Español: validar números de teléfono masivo (formato E.164)

Valida y normaliza una lista de teléfonos al formato E.164, con país y tipo de línea (móvil, fijo, VoIP), sin clave de API y sin conexión a servicios externos (libphonenumber). Entrada de ejemplo: { "phones": ["(415) 555-2671", "+34 612 34 56 78"], "defaultRegion": "ES" }. Coste: $0,50 por 1.000 números analizables; los primeros 25 de cada ejecución y las filas no analizables son gratis. Solo comprueba el formato y el plan de numeración: no confirma que el número esté activo.

Deutsch: Telefonnummern prüfen und in E.164 umwandeln (Liste, Massenprüfung)

Prüft eine Liste von Telefonnummern auf Gültigkeit, wandelt sie ins E.164-Format um und liefert Land und Leitungstyp (Mobil, Festnetz, VoIP) - ohne API-Schlüssel, offline mit libphonenumber. Beispiel-Eingabe: { "phones": ["030 123456", "+49 151 23456789"], "defaultRegion": "DE" }. Kosten: $0,50 pro 1.000 auswertbare Nummern; die ersten 25 je Lauf und nicht lesbare Einträge sind kostenlos. Geprüft werden nur Format und Nummernplan, nicht ob die Nummer erreichbar ist.

Português: validar números de telefone em massa (formato E.164)

Valida uma lista de telefones, converte para E.164 e devolve país e tipo de linha (celular, fixo, VoIP), sem chave de API, offline com libphonenumber. Exemplo de entrada: { "phones": ["(11) 91234-5678", "+55 21 2345-6789"], "defaultRegion": "BR" }. Custo: US$ 0,50 por 1.000 números analisáveis; os primeiros 25 por execução e as linhas não analisáveis não são cobrados. Verifica apenas formato e plano de numeração, não se o número está ativo.

FAQ

How do I convert a list of phone numbers to E.164 in bulk?

Put the numbers in phones and set defaultRegion (for example US, GB, DE) for numbers written without a + prefix. Every row comes back with e164, nationalFormat and internationalFormat. Example input for a mixed list (the first has no +, so defaultRegion is used):

{ "phones": ["(415) 555-2671", "+44 20 7946 0958", "+49 30 123456"], "defaultRegion": "US" }

Numbers that can be parsed cost $0.0005 each ($0.50 per 1,000). Blank or unparseable inputs are returned with an error code and are not charged.

Can I clean a phone list before an SMS campaign?

Partly. Use valid and possible to find numbers that cannot exist (wrong length, no matching numbering-plan range) and type to see line type where the numbering plan says. It does not check whether a number is active, reachable or ported; that needs a paid carrier/HLR lookup. Turn on sampleOnly to run the first 10 numbers of your list free before you pay for the rest.

Is this number mobile or landline?

The type field returns MOBILE, FIXED_LINE, FIXED_LINE_OR_MOBILE, TOLL_FREE, VOIP and other libphonenumber types, or null when unknown. In the US and Canada mobile and landline share ranges, so you will often see FIXED_LINE_OR_MOBILE. This is numbering-plan metadata only, not a carrier check.

Does it work offline, with no API key?

Yes. The Actor runs Google's libphonenumber metadata (via libphonenumber-js) inside the run: no third-party lookup service, no API key and no per-lookup vendor fee. You pay only the Actor's pay-per-event price of $0.50 per 1,000 parseable numbers.

Do I need an API key or external credits?

No. There is no third-party lookup account, API key or prepaid credit balance to top up, so you cannot hit a "no balance" error from an outside service. The only cost is this Actor's pay-per-event charge on your Apify account. Set sampleOnly to validate the first 10 numbers free.

What does it not return?

No live-line / active / reachable / ported status, no WhatsApp or SMS deliverability, no owner name and no personal-data lookup. It returns only what libphonenumber's numbering-plan metadata can say: format, validity, line type and country, plus carrier (original allocation), region and time zones (includeGeoCarrier, on by default).

I already use libphonenumber. Why pay for this?

You don't have to if you are happy to run it in your own code. Use this Actor when you want phone validation as an API or scheduler step (Make, n8n, Zapier, or a direct API call) or as a one-off CSV job without setting up code. Results match libphonenumber output; there is no extra data beyond that.

What about emails in the same list?

Use Bulk Email Validator (No SMTP) for the email column of the same lead list.

Use it from Google Sheets (=PHONE_E164)

Paste this Apps Script into Extensions > Apps Script, add your own Apify token as script property APIFY_TOKEN (never in the code), then use =PHONE_E164(A2:A50) to get E.164, valid, line type and country per row. It calls this Actor's run-sync-get-dataset-items endpoint on your account.

function PHONE_E164(range, defaultRegion) {
var token = PropertiesService.getScriptProperties().getProperty('APIFY_TOKEN');
if (!token) throw new Error('Set script property APIFY_TOKEN.');
var rows = Array.isArray(range) ? range : [[range]], flat = [];
rows.forEach(function (r) { r.forEach(function (c) { flat.push(String(c == null ? '' : c).trim()); }); });
var phones = flat.filter(function (p, i) { return p && flat.indexOf(p) === i; });
if (!phones.length) return flat.map(function () { return ['', '', '', '']; });
var res = UrlFetchApp.fetch('https://api.apify.com/v2/acts/pennydata~phone-number-validator-offline/run-sync-get-dataset-items?format=json&clean=true', {
method: 'post', contentType: 'application/json', headers: { Authorization: 'Bearer ' + token },
payload: JSON.stringify({ phones: phones, defaultRegion: defaultRegion || 'US' }), muteHttpExceptions: true });
if (res.getResponseCode() >= 300) throw new Error('Apify HTTP ' + res.getResponseCode());
var by = {}; JSON.parse(res.getContentText()).forEach(function (it) { by[it.input] = it; });
return flat.map(function (p) { var it = by[p]; return !p ? ['', '', '', ''] : !it ? ['no result', '', '', ''] : [it.e164 || '', it.valid === true, it.type || '', it.country || '']; });
}

Runs are billed to your Apify account at the per-number price below.

Pricing

Pay per event, no start fee. Prices match .actor/pay_per_event.json.

EventPriceWhen it is charged
phone-validated$0.0005 per number ($0.50 per 1,000)One number that could be parsed and returned (valid or invalid)
Blank or unparseable inputFreeReturned with an error code, never charged

Example: 1,000 inputs of which 40 are blank or unparseable cost 960 x $0.0005 = $0.48. Set a maximum cost per run in the run options; the actor stops charging when that limit is reached. Apify platform usage is billed separately if your plan includes it.

Honest limits

  • Offline only. No carrier lookup, no HLR, no "is this number active/reachable/ported" check, no owner or personal-data lookup. valid means the number matches a real numbering plan range; it may not be assigned to anyone.
  • Line type comes from libphonenumber metadata and is not always determinable (US numbers are often FIXED_LINE_OR_MOBILE).
  • Time zones come from libphonenumber metadata (on by default; includeGeoCarrier false drops them); where an area spans several zones all are returned.
  • Numbers without a + prefix use defaultRegion; a wrong region gives wrong results.
  • Metadata is as current as the bundled library version.

Not affiliated with Google or the libphonenumber project. Written with the assistance of an AI (Claude Sonnet 5.5).

Switching from another phone validator

A khadinakbar/phone-number-lookup-api input (phoneNumbers, defaultCountry, maxConcurrency, maxCostUsd, requireCarrier, include* flags) runs here verbatim, at $0.0005 per number instead of $0.025. Offline only: no WhatsApp, Telegram or reverse lookup.

Paste the input you already use and change only the actor ID. These keys are accepted as aliases:

Other validator's inputUsed here as
phoneNumbers, numbers, phone, phoneNumbersText (list, text or {phone} objects)phones
defaultCountry, defaultCountryCode, countrydefaultRegion
maxResultscap on numbers processed
maxCostUsdstop charging after floor(maxCostUsd / 0.0005) numbers; 0 = no cap
requireCarrieronly rows with an offline carrier name are returned (others dropped, not charged)
includeReverseLookupUrls, includeWhatsAppCheck, includeTelegramCheckaccepted and ignored: this actor is offline validation only, with no reverse lookup, WhatsApp or Telegram check
includeCarrier, includeGeocoding, includeTimezone, formats, maxConcurrencyaccepted and ignored (use includeGeoCarrier for offline carrier, region and time zone)

Input is compatible; the output field names are this actor's own (e164, valid, type, country), so check your downstream mapping once.

Use from Claude, Cursor or any MCP client

Apify's MCP server can expose this actor as a tool. Use this URL (format from the Apify MCP docs, ?tools= takes a comma-separated list of actors):

https://mcp.apify.com/?tools=pennydata/phone-number-validator-offline

Client config (mcpServers format; sign in with OAuth when the client asks):

{"mcpServers": {"apify": {
"url": "https://mcp.apify.com/?tools=pennydata/phone-number-validator-offline"
}}}

Example prompt: "Validate these phone numbers with default region GB and give me E.164 and line type: 020 7946 0958, 07911 123456."

Pair with: Website Contact Extractor (step 1 extract, step 2 validate)

  1. Extract: run Website Contact Extractor on your list of company websites. Each output row has a phones array (public business contact data only).
  2. Validate: copy those phones values into phones here and set defaultRegion to the sites' country for numbers without a +. You get E.164, validity and line type per number.

Each step is a separate run billed at its own pay-per-event price.

Other small pay-per-event Actors from the same publisher:

Phone number lookup (carrier, line type, time zone, region)

Use this actor as an offline phone number lookup. Every valid number comes back with these fields. No API key and no third-party site calls (libphonenumber metadata, Apache-2.0):

FieldMeaning
lineType (also type)MOBILE, FIXED_LINE, FIXED_LINE_OR_MOBILE, TOLL_FREE, VOIP, ... or null
carrieroriginal mobile carrier from the numbering-plan allocation, null where the metadata has none
timeZoneslist of IANA time zones, e.g. ["America/New_York"]
geoLocationcity or region text, e.g. "New York, NY" or "London"
country, callingCodeISO country and calling code
e164, nationalFormat, internationalFormatthe three formats

Limits: carrier is the original allocation and ignores number porting; this is not an owner lookup and not a live-line check. Set includeGeoCarrier to false to drop carrier, geoLocation and timeZones. Pricing is unchanged.