Phone Number Validator avatar

Phone Number Validator

Pricing

from $1.00 / 1,000 number validateds

Go to Apify Store
Phone Number Validator

Phone Number Validator

Validate phone numbers offline with Google's libphonenumber. Get validity, number type (mobile, landline, VOIP, toll-free), country, and E.164/international/national formats. Never charged for an invalid number.

Pricing

from $1.00 / 1,000 number validateds

Rating

0.0

(0)

Developer

Adrian Voss

Adrian Voss

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

20 hours ago

Last modified

Share

You paste a list of phone numbers and get back, per number, whether it's a real, validly formatted number — plus its type (mobile, landline, VOIP, toll-free...), country, and E.164/international/national formats. Every answer comes from Google's libphonenumber, computed entirely offline: no third-party API, no scraping, no network request of any kind. That also means no rate limit, no blocking, and no per-call vendor cost — you're only ever charged for a number libphonenumber actually confirms is real.

Who it's for

Anyone who needs to clean a list of phone numbers before it hits a dialer, a CRM, an SMS campaign, or a lead-gen pipeline: sales-ops teams deduping a contact export, form-validation services checking a signup field server-side, or an AI agent that just scraped a list of numbers off the web and needs to know which ones are even worth trying. If your list mixes real numbers with typos, placeholders, and copy-paste garbage, this sorts them before you spend money dialing or texting a dead number.

Why offline

Most "phone validator" actors on Apify wrap a paid third-party API (Twitter's account-lookup tricks, a paid HLR/carrier-lookup service, or phoneinfoga-style OSINT scraping) — that means per-lookup vendor cost, rate limits, and a network round trip per number. This actor's validation logic is the same open-source number-plan metadata Android and Google's own products ship with: no vendor in the loop, no network call, no rate limit, and results in milliseconds. The trade-off is honesty about scope — see What you don't get below.

What you get

  • isValid — confirmed against libphonenumber's real per-country number-plan rules (not just "the right number of digits").
  • isPossible — true whenever the length is plausible for the country, even if isValid turns out false. Exposed separately so you can see why a number failed, not just that it did.
  • numberType — MOBILE, FIXED_LINE, FIXED_LINE_OR_MOBILE, VOIP, TOLL_FREE, PREMIUM_RATE, PERSONAL_NUMBER, PAGER, UAN, VOICEMAIL, or UNKNOWN, per libphonenumber's own classification.
  • regionCode, countryCallingCode — the ISO country and dialing code the number resolves to.
  • e164Format, internationalFormat, nationalFormat — libphonenumber's three standard renderings, ready to paste into a dialer or an SMS API.

What you don't get

Carrier name. Google's real carrier-name mapping (e.g. "this is a Verizon number") is a separate, proprietary dataset that was never released for the open-source JS library this actor uses — anyone claiming to give you a live carrier name from a client-side/offline library is either calling a paid HLR lookup behind the scenes or guessing from the prefix (which goes stale the moment a number is ported). This actor doesn't fabricate that field.

How to use

  1. In the Apify Console. Open the actor page and click Start — the phoneNumbers field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~phone-number-validator/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"phoneNumbers":["+14155552671","+442071838750"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.

Input

{
"phoneNumbers": [
"+14155552671",
"+442071838750"
]
}

One phone number per line. International format with a leading + is always safe (e.g. +14155552671); a number in national format (e.g. 4155552671) needs the optional "Default country" field set below. Accepted formats: +14155552671, +44 20 7183 8750, (415) 555-2671 with Default country = US.

phoneNumbers is a list of phone numbers in any format — E.164 (with a leading +) is always safe with no other input needed. A number in national format (no +, e.g. 4155552671 or (415) 555-2671) needs the optional Default country field set to a 2-letter ISO code (e.g. "US"), since libphonenumber needs a region hint to interpret a number with no country code embedded in it. One dataset row is returned per item; rows with "found": false are never charged.

Output

One row per item, for example:

queryfoundstatusisValidisPossibleregionCodenumberTypecountryCallingCodee164FormatinternationalFormatnationalFormatscrapedAt
+14155552671trueOKtruetrueUSFIXED_LINE_OR_MOBILE1+14155552671+1 415-555-2671(415) 555-26712026-08-31T06:01:41.060Z

A miss comes back as a row with "found": false and is never charged.

Pricing

$2 per 1,000 phone numbers, plus a $0.00005 start fee. Misses (found:false) are never charged.

Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~phone-number-validator/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"phoneNumbers":["+14155552671","+442071838750"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~phone-number-validator/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"phoneNumbers":["+14155552671","+442071838750"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~phone-number-validator/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"phoneNumbers":["{{phone number}}"]}, mapping the row's phone number into the phoneNumbers array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Phone Number Validator | Apify" — the agent will find and run this actor.

Tips

  • Always prefer E.164 input (+14155552671) when you have it — it's unambiguous and needs no Default country field, and it's what most CRMs and dialers store anyway.
  • Set Default country once per run if your whole list is from a single country in national format (e.g. a US-only contact export) — it applies to every row in that run.
  • A row with isPossible: true but no row at all (billed as found: false) means the number has a plausible length for its country but doesn't match any real, allocated number pattern — treat it as suspicious even though the digit count "looks right".

FAQ

Does this actually call the phone number or a carrier network? No. Nothing is dialed, no SMS is sent, and no network request of any kind is made — this is pure offline computation against libphonenumber's bundled number-plan metadata, the same library Android's own dialer uses to validate numbers as you type.

Why is a number marked invalid when it "looks right" (correct digit count)? Digit count alone isn't enough — isPossible covers that. isValid additionally checks the number against the real allocated prefix ranges for its country, so an unallocated or fictional-format number (right length, wrong pattern) correctly comes back invalid — and isn't charged.

Can I get the carrier name (e.g. "Verizon", "T-Mobile")? No — see What you don't get above. That data isn't in the open-source library this actor uses, and this actor won't guess it from the prefix.