Phone Number Validator
Validate phone numbers in bulk, offline. Get E.164 and national formats, country, mobile or landline, region, original carrier and time zones for each number.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
phoneNumbers,defaultCountry,datasetId(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.00026 per number checked = $0.26 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Number checked | One distinct phone number checked and returned in the dataset, valid or not. Blank entries and repeats in the same run are never charged. | $0.00026 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-09-14, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
phoneNumbers | One number per line, written any way: +44 20 7946 0018, (201) 555-0123, 0033 6 12 34 56 78 or tel:+81-3-1234-5678. Numbers without + or 00 in front need the default country below. Leave this empty to check a dataset instead. | array |
defaultCountry | The country for numbers written without + or 00, the way people write local numbers. (201) 555-0123 checks out as a US number with United States here and fails with most other countries. Numbers that start with + or 00 carry their own country and ignore this. | string |
datasetId | Check the numbers in one of your Apify datasets, for example the results of a business-listing or lead scraper. Pick it here, or pass its ID as datasetId through the API. Works together with the list above. | string |
datasetField | The field in each dataset item that holds the number: phone unless you change it. Use dots for a nested field (contact.phone). A field holding a list checks every number in it. | string |
addRegionAndCarrier | For valid numbers, add the place the number range belongs to (for landlines usually a town or city), the carrier the range was first given to, and its time zones. Switch it off for just the check and the formats. | boolean |
language | Names that don't exist in the chosen language come in English. | string |
onlyValid | Return only the numbers that pass the check. The others are left out and aren't charged. | boolean |
numberTypes | Return only valid numbers of these types, mobile for example. Leave it empty for every type. Numbers left out aren't charged. In the US and Canada most numbers come back as "landline or mobile", so pick that too for those. | array |
countries | Return only numbers that belong to these countries. Leave it empty for every country. Numbers left out aren't charged. | array |
maxNumbers | The most numbers checked in one run. Only distinct, non-blank entries count, and each one checked is charged. | integer |
What you get
A structured dataset — each result includes fields like:
inputvalidreasone164nationalcountrynumberTypesmsCapableregioncarriertimeZonesExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in Developer & Research Tools
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
GitHub Scraper
Search GitHub repos and users: stars, forks, language, topics, licence, plus user bio, company and followers. No token needed. $0.90 per 1,000 rows.
Stack Overflow / Stack Exchange Scraper
Search Stack Overflow and Stack Exchange by keyword or tag. Score, answer count, views, reputation and body text. $2 per 1,000 questions.
Package Registry Scraper (npm + PyPI)
Get npm and PyPI package metadata as JSON. Version, license, author, repo, keywords and npm monthly downloads. $2 per 1,000 packages.
arXiv Scraper
Search arXiv papers by title, author, abstract or category. Get full abstracts, authors, categories, DOI, dates and PDF links. $2 per 1,000 papers.
OpenAlex Scholarly Works Scraper
Search 250M+ OpenAlex papers with no API key. Get titles, authors, venue, year, citations, DOI, OA links and full abstracts. $2.00 per 1,000 papers.
Crossref Scholarly Works Scraper
Search 150M+ papers on Crossref: DOI, title, authors, journal, publisher, date, citations and abstract. No API key. $1.00 per 1,000 works.
Where this tool sits
- Categories
- Developer & Research Tools
Phone Number Validator
Paste phone numbers, or point it at a dataset of leads, and get one row for each number. The row tells you whether the number is valid and, if not, why. It gives the number in E.164, international and national form, the country, and what kind of line it is: mobile, landline, toll-free, VoIP and so on. Valid numbers also get the place their number range belongs to, the carrier the range was first given to, and the time zones it covers.
Everything happens inside the run. No number is called, texted or looked up on a phone network, and nobody on your list notices anything.
What it doesn't do
- It can't tell you whether a number is switched on right now. Valid means the number fits a range the country actually uses. It may still be disconnected, or never handed out. Only a live lookup through a phone network can tell that, and this doesn't do one.
- It doesn't say who owns a number. No names, no addresses.
- The carrier is the original one. People keep their number when they change carrier, so for a moved number the carrier column shows the old one.
- In the US and Canada, mobiles and landlines share the same ranges, so numbers there come back as "landline or mobile". Most other countries keep the two apart.
- No WhatsApp or Telegram check.
Input
Phone numbers. One per line, written any way you like: +44 20 7946 0018, (201) 555-0123, 0033 6 12 34 56 78, tel:+81-3-1234-5678. An extension such as ext. 12 goes into its own column.
Default country. A local number, one without + or 00 in front, only means something with a country. (201) 555-0123 checks out as a US number when this is set to United States, and fails with most other countries. Pick the country your list mostly comes from. Numbers that start with + or 00 carry their own country and ignore this setting.
Dataset and field. To check the results of another actor, a business-listing scraper say, pick its dataset (or pass the ID as datasetId through the API) and give the name of the field that holds the number (phone unless you change it). The actor can read only the dataset you pick, and it never writes to it. Nested fields work with dots, such as contact.phone, and a field holding a list checks every number in it. A dataset and a pasted list can go in the same run.
Add region, carrier and time zones. On by default. Switch it off if you only want the check and the formats.
Language for region and carrier names. English by default, with 32 other languages. A name that doesn't exist in the chosen language comes in English.
Filters. Three optional ones. *Only valid numbers* drops the ones that fail the check. *Only these line types* keeps, say, just mobiles; it leaves out invalid numbers too, since those have no type. *Only these countries* keeps numbers from the countries you pick. A number the filters leave out isn't returned and isn't charged. In the US and Canada most numbers come back as "landline or mobile", so when you filter for mobiles there, pick that type as well.
Maximum numbers. 10,000 unless you change it, and up to 500,000 in one run. Only distinct, non-blank numbers that pass your filters count.
Output
One row per distinct number, in the order they came in.
| Field | Example | Notes |
|---|---|---|
input | (201) 555-0123 | as you wrote it |
valid | true | |
possible | true | the length is right for the country, even when the number itself isn't in use |
reason | wrong length for France | why it isn't valid; empty when it is |
e164 | +12015550123 | the form most systems want |
international | +1 201 555 0123 | |
national | (201) 555-0123 | how people dial it inside the country |
rfc3966 | tel:+12015550123 | the form links and contact cards use |
extension | 12 | when the entry had one |
countryCode | US | two-letter code |
country | United States | |
callingCode | +1 | |
numberType | landline or mobile | one of: mobile, landline, landline or mobile, toll-free, premium rate, shared cost, VoIP, personal number, pager, UAN, voicemail |
smsCapable | true | true for mobiles, false for landlines and special numbers, empty when the numbering plan can't tell (landline or mobile, VoIP) |
region | Mountain View, CA | where the number range belongs |
carrier | Three | the carrier the range was first given to |
timeZones | ["America/Los_Angeles"] | |
source, sourceIndex | list, 2 | the line of your list, or the position of the item in your dataset |
For a landline, region is usually a town or city. Many countries don't tie mobile ranges to a place, so for mobiles it is often empty. A number that isn't tied to one place, such as a US toll-free number, lists every time zone in its country.
When a number isn't valid, reason says why in plain words: too short, wrong length for France, not a number in use in Germany, unknown country code or no country code: start it with + or set a default country. The formatted columns stay empty for those, so an invalid number can't slip into a column you import somewhere else.
The run also writes a report, RUN_REPORT in the key-value store, with counts by verdict, reason, type and country, and a note of what was skipped.
What you pay
Each distinct number checked is one charge, valid or not, because the verdict is what you asked for. Blank entries and repeats of a number already checked in the same run are skipped and never charged. 020 7946 0018 with United Kingdom set and +44 20 7946 0018 count as the same number. If you set a maximum charge for the run, it stops when that is reached, and every row you get has been paid for. The price itself is on the Pricing tab.
Where the rules come from
Validity, line types and formats come from libphonenumber-js, which follows Google's libphonenumber numbering plans; this build uses version 1.13.13, released in September 2026. Region, carrier and time-zone names come from the tables in libphonenumber-geo-carrier 2.0.0, built from the same Google data. Countries open new number ranges from time to time, so a range that went live after this build can show up as "not a number in use" until the actor is updated.
Questions
Why is a number I know works marked "not a number in use"? Either its range is newer than the data, or it was read with the wrong country. Check the default country, or write the number with + and its country code.
Does it change my dataset? No. It only reads the field you name, and writes its own results to its own dataset.
Can it tell me which numbers take text messages? As far as the numbering plan goes, yes: smsCapable is true for mobiles and false for landlines and special numbers. It's empty where the plan can't tell, as with "landline or mobile" numbers in the US and Canada and with VoIP. Whether a mobile is switched on right now needs the live lookup this actor doesn't do.