Phone Number Validator & Formatter – E.164, Country, Line Type avatar

Phone Number Validator & Formatter – E.164, Country, Line Type

Pricing

$0.50 / 1,000 validated phone numbers

Go to Apify Store
Phone Number Validator & Formatter – E.164, Country, Line Type

Phone Number Validator & Formatter – E.164, Country, Line Type

Validate and format phone numbers offline with Google libphonenumber metadata: E.164, international and national format, country, line type (mobile, fixed, toll-free, premium...). Clean CRM lists before an import or an SMS send. No live carrier lookup.

Pricing

$0.50 / 1,000 validated phone numbers

Rating

0.0

(0)

Developer

Francesco Antonio Russo

Francesco Antonio Russo

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

14 days ago

Last modified

Categories

Security

Limited permissions

Share

Clean a list of phone numbers before you import it into a CRM or send an SMS or WhatsApp campaign. Give it numbers written any way people write them – (212) 555-0123 x55, 0044 20 7946 0958, +39 06 6982 – and get back one tidy row per number: valid or not (with the reason), the E.164, international, national and RFC 3966 forms, the country, and the line type (mobile, fixed line, toll-free, premium rate, VOIP…).

Everything is computed offline from the numbering-plan metadata of Google's libphonenumber, packaged in libphonenumber-js 1.13.15. There is no call to any phone network, carrier or third-party service: the result is the same every time, it is fast, and it is cheap.

Who it is for

  • CRM and spreadsheet cleanup. Normalise a messy phone column to E.164 so that duplicates match and imports do not fail.
  • SMS / WhatsApp campaign preparation. Drop numbers that cannot exist, keep mobiles, flag premium-rate and special numbers before you pay to send to them.
  • Form and lead data. Check what people typed in a sign-up form, with the country they picked.
  • Data pipelines. Run it on a dataset from another Actor (a scraper, a lead list) and get a clean dataset back.

What it does NOT do (read this first)

  • No live lookup. It does not ask any carrier or network. It cannot tell you whether a number is connected, active, reachable, ported or disconnected (that is what an HLR lookup does). "Valid" here means: the number has the right length and matches a pattern of the numbering plan of its country.
  • Line type is deduced from the numbering plan, not looked up. In the USA, Canada and a few other countries, fixed-line and mobile numbers share the same ranges and cannot be told apart: you get FIXED_LINE_OR_MOBILE. A number that was ported to another type of line keeps the type of its original range.
  • No owner, no name, no carrier, no location beyond the country.
  • It does not find numbers in free text. Each entry must be one phone number (with an optional extension). A sentence with a number inside is reported as CONTAINS_LETTERS.

What you get

For every number that gets a result, one row in the dataset. Every row has the same 22 fields, in the same order; a field that does not apply is null.

FieldTypeWhat it holds
inputIndexnumberPosition of the row in your input, counting from 0: first the "phones" list, then the items of the dataset. Use it to join the result back to your own rows (duplicates and skipped rows leave gaps).
inputstringThe text exactly as you gave it (cut at 300 characters).
countryHintstring or nullThe country used to read numbers written without "+": the row's own country, else defaultCountry. Null when none was given. A number written with "+" ignores it.
isValidbooleanTrue when the number matches the numbering plan of its country (right length AND a known pattern). This is what the metadata can tell; it does not mean the number is connected to anyone.
isPossiblebooleanTrue when the length is possible for the country, even if the number is not valid. A valid number is always possible.
invalidReasonstring or nullWhy the number is not valid: NOT_A_NUMBER, CONTAINS_LETTERS, MISSING_COUNTRY (written without "+" and no country known: free of charge, set defaultCountry), MULTIPLE_NUMBERS (several numbers in one cell: free of charge, split them), INVALID_COUNTRY (an unknown calling code), TOO_SHORT, TOO_LONG (also an extension of more than 10 digits), INVALID_LENGTH (a length the country does not use), INVALID_NUMBER (a possible length but no numbering-plan pattern matches). Null when valid.
e164string or nullThe number in E.164 form, "+" and digits only, without extension. Null when the number is not valid.
internationalstring or nullHuman-readable international format, with the extension if there is one. Null when not valid.
nationalstring or nullHuman-readable national format of its own country, with the extension if there is one. Null when not valid.
rfc3966string or nullThe tel: URI (RFC 3966), with ";ext=" when there is an extension. Null when not valid.
extensionstring or nullThe extension found after "ext", "x", "#", ";ext=", "int", "interno", "anexo" or "ramal", digits only. Null when none.
countryCodestring or nullISO 3166-1 alpha-2 code of the country the number belongs to (some codes are shared: +1 is US, CA, PR...; the area code decides). Null when the metadata cannot tell, and for non-geographic numbers such as +800.
countryNamestring or nullEnglish name of that country.
callingCodenumber or nullThe international calling code as a number (1, 39, 44...). Known even for some invalid numbers; null when the number could not be read at all.
lineTypestring or nullMOBILE, FIXED_LINE, FIXED_LINE_OR_MOBILE (USA, Canada and others do not tell them apart), TOLL_FREE, PREMIUM_RATE, VOIP, SHARED_COST, PERSONAL_NUMBER, PAGER, UAN, VOICEMAIL, or UNKNOWN (valid but the plan does not say). Deduced from the numbering plan, not looked up live. Null when not valid.
isPremiumOrSpecialboolean or nullTrue for lines that are not ordinary subscriber lines: PREMIUM_RATE, SHARED_COST, UAN, PERSONAL_NUMBER, PAGER, VOICEMAIL. Toll-free and VOIP are not flagged. Null when not valid.
hasLettersbooleanTrue when the number part had letters (a vanity number such as 1-800-FLOWERS). Letters in an extension marker (ext, x) do not count.
vanityConvertedbooleanTrue when the letters were turned into digits with the phone keypad (only with convertVanityLetters on). Without it a number with letters is not valid (CONTAINS_LETTERS).
labelStrippedbooleanTrue when a label in front of the number ("Tel.", "Phone:", "Mobile", "Cell", "Cellulare", "Telefono") or a note in brackets after it ("(mobile)") was taken off before the number was read. "Fax" is not removed.
matchesCountryHintboolean or nullTrue when the number's calling code is the one of the country hint, false when it is another (a UK number in a column that says Italy). Null when there is no hint or the number could not be read.
normalizedstring or nullThe key to deduplicate and join on: the E.164 number, plus ";ext=NN" when it has an extension (two extensions of one switchboard are two different contacts). Null when not valid.
metadataVersionstringThe library and metadata that produced the row. Numbering plans change; this tells you which snapshot answered.

Reasons a number is not valid (invalidReason): NOT_A_NUMBER, CONTAINS_LETTERS, MISSING_COUNTRY, MULTIPLE_NUMBERS, INVALID_COUNTRY, TOO_SHORT, TOO_LONG, INVALID_LENGTH, INVALID_NUMBER.

Two of them are free of charge (the row is still delivered, so you can see it and fix it): MISSING_COUNTRY (the number is written without + and neither the row nor defaultCountry gives a country, so the number could not even be tried: this is a missing setting, not a bad number) and MULTIPLE_NUMBERS (several numbers in one cell, such as 347 1234567 / 06 1234567). INVALID_COUNTRY is a + or 00 number whose calling code does not exist.

Line types (lineType): MOBILE, FIXED_LINE, FIXED_LINE_OR_MOBILE, TOLL_FREE, PREMIUM_RATE, VOIP, SHARED_COST, PERSONAL_NUMBER, PAGER, UAN, VOICEMAIL, UNKNOWN.

Real example

This is the output of a real run (not edited) on the numbers below. They are fictitious or public numbers: the 555-01xx range reserved for fiction, Ofcom's drama range 020 7946 0xxx, the Vatican switchboard, Google's published example mobile numbers for each country, and a Swiss number from libphonenumber's own documentation examples. The Actor's default country was IT.

{
"phones": [
{ "phone": "(212) 555-0123 x55", "country": "US" },
"+39 06 6982",
{ "phone": "020 7946 0958", "country": "GB" },
"0044 20 7946 0958",
"+1 800 555 0199",
"+1 900 555 0123",
{ "phone": "312 345 6789", "country": "IT" },
{ "phone": "01512 3456789", "country": "DE" },
{ "phone": "06 12 34 56 78", "country": "FR" },
{ "phone": "612 34 56 78", "country": "ES" },
{ "phone": "(11) 96123-4567", "country": "BR" },
{ "phone": "081234 56789", "country": "IN" },
{ "phone": "0412 345 678", "country": "AU" },
{ "phone": "222 123 4567", "country": "MX" },
{ "phone": "06 12345678", "country": "NL" },
{ "phone": "090-1234-5678", "country": "JP" },
"+41 44 668 18 00",
{ "phone": "07400 123456", "country": "UK" },
{ "phone": "555-0123", "country": "US" },
{ "phone": "347 1234567", "country": "US" },
"+999 12345",
{ "phone": "1-800-FLOWERS", "country": "US" },
"not a phone",
"",
null,
"+39 06 6982 interno 12",
"12345",
"+39 347 1234567 1234567890",
"39 312 345 6789",
"+800 1234 5678"
],
"defaultCountry": "IT"
}

Result for each of the 30 entries (— means null; the rows themselves have all the fields above):

#InputCountryValidType / reasonE.164ISO
0(212) 555-0123 x55USyesFIXED_LINE_OR_MOBILE+12125550123US
1+39 06 6982ITyesFIXED_LINE+39066982VA
2020 7946 0958GByesFIXED_LINE+442079460958GB
4+1 800 555 0199ITyesTOLL_FREE+18005550199US
5+1 900 555 0123ITyesPREMIUM_RATE+19005550123US
6312 345 6789ITyesMOBILE+393123456789IT
701512 3456789DEyesMOBILE+4915123456789DE
806 12 34 56 78FRyesMOBILE+33612345678FR
9612 34 56 78ESyesMOBILE+34612345678ES
10(11) 96123-4567BRyesMOBILE+5511961234567BR
11081234 56789INyesMOBILE+918123456789IN
120412 345 678AUyesMOBILE+61412345678AU
13222 123 4567MXyesFIXED_LINE_OR_MOBILE+522221234567MX
1406 12345678NLyesMOBILE+31612345678NL
15090-1234-5678JPyesMOBILE+819012345678JP
16+41 44 668 18 00ITyesFIXED_LINE+41446681800CH
1707400 123456GByesMOBILE+447400123456GB
18555-0123USnoTOO_SHORT—US
19347 1234567USnoINVALID_NUMBER—US
20+999 12345ITnoINVALID_COUNTRY——
211-800-FLOWERSUSnoCONTAINS_LETTERS——
22not a phoneITnoCONTAINS_LETTERS——
25+39 06 6982 interno 12ITyesFIXED_LINE+39066982VA
2612345ITnoTOO_SHORT—IT
27+39 347 1234567 1234567890ITnoTOO_LONG——
29+800 1234 5678ITyesTOLL_FREE+80012345678—

Things to notice in this table:

  • Entries 3 and 28 are not in the table: 0044 20 7946 0958 is the same number as entry 2, and 39 312 345 6789 is the same as entry 6, so they were skipped for free (dedupe is on by default). Entries 23 and 24 are empty ("" and null) and also free.
  • +39 06 6982 is reported as VA (Vatican City): in libphonenumber's numbering plan, +39 06 698… belongs to the Vatican, not to Italy, although both use calling code 39.
  • A number with + keeps its own country whatever the default country says: +1 800 555 0199 is US even though the default country is IT; its matchesCountryHint is false, which is how you spot a UK number in a column that says Italy.
  • 347 1234567 read as a US number is INVALID_NUMBER: the length is possible, but no US pattern matches. Read as an Italian number (the default country) it is a valid mobile.
  • +800 1234 5678 is an international toll-free number that belongs to no country: countryCode is null and callingCode is 800.

A valid row, with an extension (exactly what the dataset contains):

{
"inputIndex": 0,
"input": "(212) 555-0123 x55",
"countryHint": "US",
"isValid": true,
"isPossible": true,
"invalidReason": null,
"e164": "+12125550123",
"international": "+1 212 555 0123 ext. 55",
"national": "(212) 555-0123 ext. 55",
"rfc3966": "tel:+12125550123;ext=55",
"extension": "55",
"countryCode": "US",
"countryName": "United States",
"callingCode": 1,
"lineType": "FIXED_LINE_OR_MOBILE",
"isPremiumOrSpecial": false,
"hasLetters": false,
"vanityConverted": false,
"labelStripped": false,
"matchesCountryHint": true,
"normalized": "+12125550123;ext=55",
"metadataVersion": "libphonenumber-js@1.13.15 (max metadata, from Google libphonenumber)"
}

A valid mobile number whose country came from the row's own country:

{
"inputIndex": 6,
"input": "312 345 6789",
"countryHint": "IT",
"isValid": true,
"isPossible": true,
"invalidReason": null,
"e164": "+393123456789",
"international": "+39 312 345 6789",
"national": "312 345 6789",
"rfc3966": "tel:+393123456789",
"extension": null,
"countryCode": "IT",
"countryName": "Italy",
"callingCode": 39,
"lineType": "MOBILE",
"isPremiumOrSpecial": false,
"hasLetters": false,
"vanityConverted": false,
"labelStripped": false,
"matchesCountryHint": true,
"normalized": "+393123456789",
"metadataVersion": "libphonenumber-js@1.13.15 (max metadata, from Google libphonenumber)"
}

A number that is not valid (isPossible is true: the length is fine, the pattern is not):

{
"inputIndex": 19,
"input": "347 1234567",
"countryHint": "US",
"isValid": false,
"isPossible": true,
"invalidReason": "INVALID_NUMBER",
"e164": null,
"international": null,
"national": null,
"rfc3966": null,
"extension": null,
"countryCode": "US",
"countryName": "United States",
"callingCode": 1,
"lineType": null,
"isPremiumOrSpecial": null,
"hasLetters": false,
"vanityConverted": false,
"labelStripped": false,
"matchesCountryHint": true,
"normalized": null,
"metadataVersion": "libphonenumber-js@1.13.15 (max metadata, from Google libphonenumber)"
}

The run summary (SUMMARY record of the key-value store) has only counts, never a number. This is the one of the run above, without the two time stamps:

{
"status": "finished",
"stopReason": null,
"statusNotice": null,
"settings": {
"defaultCountry": "IT",
"dedupe": true,
"onlyValid": false,
"onlyNew": false,
"convertVanityLetters": false,
"maxItems": null,
"seenStoreName": null,
"source": {
"phones": 30,
"dataset": false
}
},
"metadata": {
"library": "libphonenumber-js",
"version": "1.13.15",
"metadata": "max",
"description": "libphonenumber-js@1.13.15 (max metadata, from Google libphonenumber)"
},
"totals": {
"rows": 30,
"looked": 30,
"emptyOrNotText": 2,
"duplicates": 2,
"alreadySeen": 0,
"notDelivered": 0,
"alreadyDelivered": 0,
"delivered": 26,
"deliveredFree": 0,
"notProcessed": 0,
"valid": 19,
"invalid": 7,
"uncharged": 0
},
"results": {
"valid": 19,
"invalid": 7,
"withExtension": 2,
"vanityConverted": 0,
"countryHintMismatch": 4
},
"byCountry": {
"US": 3,
"GB": 2,
"VA": 2,
"+800": 1,
"AU": 1,
"BR": 1,
"CH": 1,
"DE": 1,
"ES": 1,
"FR": 1,
"IN": 1,
"IT": 1,
"JP": 1,
"MX": 1,
"NL": 1
},
"byLineType": {
"MOBILE": 10,
"FIXED_LINE": 4,
"FIXED_LINE_OR_MOBILE": 2,
"TOLL_FREE": 2,
"PREMIUM_RATE": 1
},
"byInvalidReason": {
"CONTAINS_LETTERS": 2,
"TOO_SHORT": 2,
"INVALID_COUNTRY": 1,
"INVALID_NUMBER": 1,
"TOO_LONG": 1
},
"billing": {
"event": "phone",
"billableRows": 26,
"note": "One event per delivered row, except the free ones: rows without a country to read them with (MISSING_COUNTRY), cells with several numbers (MULTIPLE_NUMBERS), empty rows, duplicates, rows skipped by onlyNew and invalid rows left out by onlyValid."
},
"warnings": [
"2 row(s) were empty or not text and were skipped for free. Send phone numbers as text: a JSON number loses its leading zeros."
]
}

How to use it

Input

FieldWhat it does
phonesA list of phone numbers, as text. An entry can also be an object {"phone": "...", "country": "IT"} when that row has its own country. Send numbers as text, not as JSON numbers (a JSON number loses its leading zeros: such entries are skipped for free and counted).
datasetId, phoneField, countryFieldTo clean a list that is already in Apify: the ID or name of one of your datasets, the field that holds the phone (a path such as contact.phone works) and, optionally, the field with the country of each item. The dataset must already exist (a missing one stops the run before it does anything, and is never created); it is read page by page and never changed. You can use phones and a dataset in the same run: the list is read first.
defaultCountryISO 3166-1 alpha-2 code (IT, US, GB…) used for numbers written without + or an international prefix, when the row has no country of its own. UK is accepted for GB. A number with + always keeps its own country. Without a country (no defaultCountry, no country on the row) a number written without + comes back MISSING_COUNTRY: it is delivered, free of charge, and the run says so in a warning and in the status message.
dedupeDefault true: the same number written in different ways is delivered and charged once; the repetitions are free. Numbers that differ only by extension are different numbers. false: every row gets a result.
onlyValidDefault false. true: only valid numbers are delivered and charged; the invalid ones are only counted (by reason) in the summary, for free.
onlyNewDefault false. true: numbers delivered by an earlier run with the same memory are skipped for free. See below.
seenStoreNameName of the key-value store used by onlyNew (default phone-validator-seen-hashes). Use one name per list or campaign.
convertVanityLettersDefault false: a number with letters is not valid (CONTAINS_LETTERS). true: if the number part has 3 or more letters, all between A and Z, they are turned into digits with the phone keypad (1-800-FLOWERS becomes +1 800 356 9377) and the row says vanityConverted: true.
maxItemsStop after this many charged results have been delivered (free rows do not count). Empty = no limit. The spending limit of the run is respected as well.

A row is read like this: the row's own country if it has a valid one, otherwise defaultCountry. A row whose country is not an ISO code gets no country (it is never silently read as another one): numbers with + still work, national numbers get MISSING_COUNTRY (free), and the summary counts these rows in a warning.

What is accepted in a number: spaces, dots, dashes, slashes and brackets; a leading + or 00 (or the international prefix of the default country, such as 011 in the USA); full-width and Arabic-Indic digits; a tel: prefix; extensions written ext, ext., extension, x, #, ;ext=, int, interno, anexo, ramal at the end (up to 10 digits; a longer one is TOO_LONG).

Labels and notes are taken off before the number is read: a label in front (Tel., Phone:, Mob, Mobile, Cell, Cellulare, Telefono) and a note in brackets after it ((mobile), (ufficio)). The row says so with labelStripped: true; input stays as you gave it. Nothing is removed when no digit would be left. Fax is not a label: a fax number is not a number to call or text, so Fax 06 1234567 stays CONTAINS_LETTERS.

Two numbers in one cell (A / B with spaces around the slash, A, B or A; B) are not guessed at: the row is MULTIPLE_NUMBERS, free of charge. Put one number in each cell.

About 00: libphonenumber only understands the international prefix of the default country. When a number written with 00 does not work as written, the Actor tries it as +, so 0044 20 7946 0958 works with any default country. A number that already works is never rewritten.

Output

The dataset has the 22 fields above, in two table views (Clean list and Audit). inputIndex is the position of the row in your input (counting the phones list first, then the dataset): use it to join the results back to your own rows, remembering that duplicates and empty rows leave gaps. input is the text exactly as you gave it, cut at 300 characters.

Results are saved to the dataset in batches of 1000 rows, and the charge for a batch is made right after the rows are saved, so you are never charged for rows you do not have.

Only numbers not seen before (onlyNew)

For recurring jobs (a new export every week), onlyNew skips the numbers you already got. The memory is a named key-value store in your own account. It keeps only salted SHA-256 hashes of the normalized numbers – never a number in clear. The salt is random, made once per store, so the hashes are meaningless outside that store. A hash of a phone number is still pseudonymous personal data (anyone who knows the salt can test a guess), so treat the store like your other data: delete it to forget everything. Numbers are remembered only when their row was delivered. Two runs that use the same store at the same time can overwrite each other's memory; run them one after the other.

How much does it cost?

One event, phone: $0.0005 per number that gets a result – valid, or not valid with the reason. That is $0.50 per 1,000 numbers.

NumbersCost
1,000$0.50
10,000$5.00
100,000$50.00
1,000,000$500.00

You are not charged for: empty rows and entries that are not text, duplicates (with dedupe), numbers skipped by onlyNew, and – with onlyValid – the invalid numbers that are not delivered. Two more kinds of rows are delivered but not charged, because the Actor could not try to read them: MISSING_COUNTRY (written without + and no country known: set defaultCountry) and MULTIPLE_NUMBERS (several numbers in one cell). They are counted in the run summary (totals.deliveredFree, byInvalidReason, billing.billableRows), and the run adds a warning that says what to set; if more than half of the first numbers have no country, the status message of the run says it in capital letters. The run respects the maximum cost per run you set: it stops before the limit, delivers nothing beyond it, and says so in the summary. Platform usage is included in the price.

The example above: 30 entries, 26 results charged = $0.013; 2 duplicates and 2 empty entries cost nothing.

Speed and memory (measured)

Measured on a laptop, Node 22, offline analysis, 21 October 2026: 50,000 numbers analysed in about 0.65 seconds (roughly 75,000 per second, including the duplicate check). A complete local run of 50,000 mixed numbers – 44,837 rows written to local storage after 5,163 duplicates were left out – took 10 seconds and peaked at 204 MB. A complete local run of 100,000 distinct numbers took about 22 seconds in three runs and peaked at 200, 202 and 274 MB (the peak moves with the timing of the memory clean-up). On the platform the analysis is not the bottleneck: the time is set by the dataset writes and the charges, two Apify API calls per batch of 1000 rows.

The duplicate check keeps one short key in memory per distinct number: about 160 bytes each. Measured peak: 241 MB for 1,000,000 distinct numbers and 523 MB for 3,000,000. The Actor starts with 512 MB, about twice the highest peak measured for 100,000 numbers; for several hundred thousand numbers or more, start it with 1 GB or more.

Limits to know

  • The metadata is a snapshot: numbering plans change. Every row carries metadataVersion (the library version that answered). New versions of this Actor update the library.
  • Some calling codes are shared between countries (+1 for the USA, Canada and the Caribbean; +39 for Italy and the Vatican; +44 for the UK, Guernsey, Jersey and the Isle of Man; +7 for Russia and Kazakhstan). countryCode is the country libphonenumber assigns from the number itself.
  • A very long list in phones is limited by the maximum size of an Apify input: for large lists put them in a dataset and use datasetId.
  • Only the first 300 characters of input are echoed back.
  • Letters are never guessed: without convertVanityLetters, text like call me 555 0100 is CONTAINS_LETTERS; with it, only a number with at least 3 letters from A to Z is converted.
  • The Actor never writes a phone number in the run log; numbers appear only in your dataset.

FAQ

Is "valid" the same as "this number works"? No. It means the number fits the numbering plan of its country. It can still be unassigned, disconnected or a landline that does not take SMS. Only a live (HLR) lookup can tell, and this Actor does not do one.

Why is a mobile number reported as FIXED_LINE_OR_MOBILE? In the USA, Canada, Mexico and a few other countries the numbering plan does not separate the two. The honest answer is "can be either".

Why does my Italian number say VA? Numbers +39 06 698… are assigned to Vatican City. They are valid Italian-dialling numbers with country code VA.

A number I know is good comes back INVALID_NUMBER. Check that the country is right (matchesCountryHint) and that the number is complete. Very new ranges can be missing from an older snapshot: metadataVersion tells you which one answered.

Why MISSING_COUNTRY, and why was I not charged? The number was written without + (for example 347 1234567) and no country was known, so it could not be read: a number means different things in different countries. Nothing is wrong with the number, so you are not charged. Set defaultCountry (for example IT) or send a country with each row, and run again.

Why is e164 empty for an invalid number? To stop an unchecked number from slipping into an import. Use input, callingCode and invalidReason to fix it; normalized and the formatted fields exist only for valid numbers.

How does dedupe decide that two numbers are the same? By the E.164 plus the extension. +39 347 123 4567, 0039 3471234567 and 347-123-4567 (default country IT) are one number. Invalid entries are compared by their digits and country hint.

Can I clean a CSV or an Excel file? Upload it with any Apify CSV/Excel importer (or paste the column into phones), then export the dataset. Keep the column as text so that leading zeros survive.

Is it GDPR-safe? Phone numbers are personal data and you decide what to send. The Actor processes them in memory, writes them only to your dataset, and never logs them. It makes no network request about the numbers.

Use it from code

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('far003/phone-number-validator-e164').call({
phones: ['(212) 555-0123 x55', { phone: '020 7946 0958', country: 'GB' }, '+39 06 6982'],
defaultCountry: 'IT',
onlyValid: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((row) => [row.e164, row.lineType]));
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("far003/phone-number-validator-e164").call(run_input={
"datasetId": "<your dataset id>",
"phoneField": "phone",
"countryField": "country",
"defaultCountry": "US",
"dedupe": True,
})
rows = client.dataset(run["defaultDatasetId"]).list_items().items

Credits and licences

Numbering-plan metadata: Google's libphonenumber (Apache License 2.0), through libphonenumber-js (MIT), version 1.13.15. This Actor is not affiliated with, or endorsed by, Google.