# Phone Number Validator & Formatter (libphonenumber) (`ailu_studio/phone-number-validator`) Actor

Bulk phone number validation and formatting with libphonenumber, fully offline: valid/possible, E.164, international, national, RFC 3966, country, calling code and line type (mobile, fixed line, toll free, VoIP).

- **URL**: https://apify.com/ailu_studio/phone-number-validator.md
- **Developed by:** [Ailu Studio](https://apify.com/ailu_studio) (community)
- **Categories:** Lead generation, Developer tools, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 phone number checkeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Phone Number Validator & Formatter (libphonenumber): Bulk E.164, Country and Line Type Check

Validate and format phone numbers in bulk with the same numbering-plan metadata that Google's libphonenumber uses (via `libphonenumber-js` with full metadata for 245 countries and territories). For every number you get: possible and valid flags, E.164, international, national and RFC 3966 (`tel:`) formats, ISO country, calling code, national number, extension and the line type (mobile, fixed line, toll free, premium rate, VoIP ...). Everything runs **offline inside the Actor**: no number is sent to any API, results are instant and the price is low. Messy input is accepted: spaces, brackets, dashes, `00` prefixes, `tel:` links, extensions and vanity numbers like `1-800-FLOWERS`.

### Use cases

- Normalise CRM, lead and sign-up lists to E.164 before importing them into a dialer, SMS tool or WhatsApp integration.
- Separate mobile numbers from landlines and toll-free or premium-rate numbers before an SMS campaign.
- Detect the country of international numbers and reject impossible ones in forms and data pipelines.
- De-duplicate contact databases where the same number is written in many formats.
- Give AI agents a reliable, deterministic phone parser.

### Input

| Field | Default | Meaning |
|---|---|---|
| `phoneNumbers` | 8 sample numbers (US, UK, DE, KR, toll free, invalid) | Numbers to check, one per line, in any common format. Exact duplicates are checked once. |
| `defaultCountry` | `"US"` | ISO-2 country used for numbers without `+`/`00`. Leave empty to accept only international numbers. |
| `maxItems` | `1000` | Maximum numbers checked in this run. |

Example: `{ "phoneNumbers": ["030 901820", "+33 6 12 34 56 78", "0151 23456789"], "defaultCountry": "DE" }`

### Output

| Field | Meaning |
|---|---|
| `id` | First 16 hex characters of SHA-1 of the trimmed input |
| `input` | Number as given |
| `isPossible`, `isValid` | Length plausible / matches an assigned number range |
| `e164`, `international`, `national`, `rfc3966` | Formats (null when the number is not possible) |
| `countryCode`, `countryCallingCode`, `nationalNumber` | ISO-2 country, calling code without `+`, significant digits |
| `extension` | Extension when present |
| `type` | `MOBILE`, `FIXED_LINE`, `FIXED_LINE_OR_MOBILE`, `TOLL_FREE`, `PREMIUM_RATE`, `SHARED_COST`, `VOIP`, `PERSONAL_NUMBER`, `PAGER`, `UAN`, `VOICEMAIL` or null |
| `carrier` | Always `null` (see below) |
| `error` | Null for valid numbers, otherwise the reason |
| `fetchedAt` | Time of the check |

Sample row:

```json
{
  "id": "9ca97103e6592409", "input": "+44 7400 123456", "isPossible": true, "isValid": true,
  "e164": "+447400123456", "international": "+44 7400 123456", "national": "07400 123456", "rfc3966": "tel:+447400123456",
  "countryCode": "GB", "countryCallingCode": "44", "nationalNumber": "7400123456", "extension": null,
  "type": "MOBILE", "carrier": null, "error": null, "fetchedAt": "2026-11-04T11:45:00.000Z"
}
```

### How it works and limits

- Parsing, validation and formatting use `libphonenumber-js` (MIT) with its `max` metadata, which includes the per-type number patterns needed for line-type detection. The metadata ships with the Actor build; numbering-plan changes appear when the Actor is rebuilt with a newer library version.
- No network requests at all: privacy-friendly (numbers never leave the run) and instant (thousands of numbers per second).
- `isValid` means the number belongs to an assigned range, not that it is in service or reachable. There is no HLR/live lookup.
- `carrier` is always null: carrier names are not available offline and numbers can be ported between carriers.
- In countries where mobile and fixed numbers share ranges (US, Canada) the type is `FIXED_LINE_OR_MOBILE`.
- Text with several numbers in one line is not split; pass one number per line.

### Pricing

Pay per result: **$0.50 per 1,000 rows** (`result` event). Platform usage is billed separately by Apify. Removed/free rows are not charged.

### Legal

Not affiliated with Google or the libphonenumber project. Uses the open-source libphonenumber-js library (MIT licence) and its bundled metadata, which is derived from Google's libphonenumber (Apache License 2.0); no external API is called. Data licence/terms: https://gitlab.com/catamphetamine/libphonenumber-js. You are responsible for having a lawful basis to process the numbers you check (GDPR, TCPA and similar rules).

### FAQ

**Why is `(415) 555-2671` valid?** It is in an assigned US area code and has the right length. Validation is based on numbering plans; it does not call the number.

**My number without `+` is invalid. Why?** It is read as a number of `defaultCountry`. Set the right country or write it in international format.

**Can it tell me the carrier or whether the line is active?** No, that needs a paid live lookup (HLR/LNP). This Actor is the cheap first step that cleans and classifies numbers.

**Does it support extensions and vanity numbers?** Yes: `ext. 123`, `x55`, `;ext=12` in `tel:` URIs and letters such as `1-800-FLOWERS` are handled.

# Actor input Schema

## `phoneNumbers` (type: `array`):

Numbers to check, one per line, in any common format: "+44 20 7946 0958", "(415) 555-2671", "0049 30 901820", "tel:+1-202-555-0143", "1-800-FLOWERS", with or without an extension. Exact duplicates are checked once.

## `defaultCountry` (type: `string`):

Two-letter country code (e.g. US, GB, DE, KR) used for numbers written without a + or 00 prefix. Numbers with a + prefix keep their own country. Leave empty to accept only international numbers.

## `maxItems` (type: `integer`):

Upper limit on numbers checked (and rows returned) in this run: the first N unique numbers of the list.

## Actor input object example

```json
{
  "phoneNumbers": [
    "+1 202-456-1111",
    "(415) 555-2671",
    "+44 20 7946 0958",
    "+44 7400 123456",
    "+49 30 901820",
    "+82 10-1234-5678",
    "0800 123 4567",
    "12345"
  ],
  "defaultCountry": "US",
  "maxItems": 1000
}
```

# Actor output Schema

## `results` (type: `string`):

All rows in the default dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "phoneNumbers": [
        "+1 202-456-1111",
        "(415) 555-2671",
        "+44 20 7946 0958",
        "+44 7400 123456",
        "+49 30 901820",
        "+82 10-1234-5678",
        "0800 123 4567",
        "12345"
    ],
    "defaultCountry": "US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ailu_studio/phone-number-validator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "phoneNumbers": [
        "+1 202-456-1111",
        "(415) 555-2671",
        "+44 20 7946 0958",
        "+44 7400 123456",
        "+49 30 901820",
        "+82 10-1234-5678",
        "0800 123 4567",
        "12345",
    ],
    "defaultCountry": "US",
}

# Run the Actor and wait for it to finish
run = client.actor("ailu_studio/phone-number-validator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "phoneNumbers": [
    "+1 202-456-1111",
    "(415) 555-2671",
    "+44 20 7946 0958",
    "+44 7400 123456",
    "+49 30 901820",
    "+82 10-1234-5678",
    "0800 123 4567",
    "12345"
  ],
  "defaultCountry": "US"
}' |
apify call ailu_studio/phone-number-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ailu_studio/phone-number-validator"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hSbC2WG8iwavmiNuX/builds/c0RMFfcuNbyapIxAo/openapi.json
