# Phone Number Validator & Formatter (offline, E.164) (`ensorcelling_melilot/phone-validator`) Actor

Check phone numbers in bulk: valid or not, E.164 / international / national format, line type, country, original carrier, location and time zones. Offline on Google libphonenumber data: no API keys, no rate limits. $0.50 per 1,000 numbers.

- **URL**: https://apify.com/ensorcelling_melilot/phone-validator.md
- **Developed by:** [ensorcelling \_melilot](https://apify.com/ensorcelling_melilot) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.50 / 1,000 phone number checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

Check **phone numbers in bulk**: is it valid, what is the clean international format, what kind of line is it, which country, which carrier originally had the number, and which time zone. Paste a list, get a table.

It runs **offline** on Google's libphonenumber data (the library behind Android's dialer), so there are no API calls, no keys, no rate limits and no random "service unavailable" failures. That also makes it cheap.

### What you get for each number

| Field | Example |
|---|---|
| `isValid` | `true` (a real, assigned number pattern for that country) |
| `isPossible` | `true` (length is right, even if the pattern isn't) |
| `e164` | `+442083661177` (what CRMs, dialers and Twilio want) |
| `international` | `+44 20 8366 1177` |
| `national` | `020 8366 1177` |
| `rfc3966` | `tel:+442083661177` |
| `country`, `countryCallingCode` | `GB`, `44` |
| `numberType` | `mobile`, `fixed_line`, `fixed_line_or_mobile`, `toll_free`, `premium_rate`, `voip`, `shared_cost`... |
| `carrier` | `China Telecom` (see the honest note below) |
| `location` | `London` |
| `timezones` | `["Europe/London"]` |
| `extension` | `12` |
| `error` | why a number failed, in plain words |

### Input

- **Phone numbers**: one per line, any common way of writing them.
- **Default country**: two-letter code (`US`, `GB`, `DE`) for numbers written without a `+` country code. Numbers that start with `+` ignore it.
- **Add carrier, location and time zones**: on by default.
- **Language**: language for place and carrier names (`en`, `de`, `fr`, `es`, `ja`, `zh`...).
- **Remove duplicates**: on by default; duplicates are free.
- **Only output valid numbers**: drop the invalid ones from the table.

### Pricing

**$0.0005 per number checked** ($0.50 per 1,000). Empty lines and duplicates are free. No start fee. A list of 10,000 numbers costs $5.

### What this can and can't tell you (read this)

This checks numbers against **numbering plans**, not against live phone networks.

- **Valid** means the number matches the format of an assigned range in that country. It does **not** mean someone answers it, or that it is currently connected.
- **Carrier** is the carrier the number's prefix was **originally assigned to**. If the owner ported their number to another carrier (common in the US, UK and EU), this will be out of date. For the US, Canada and several other countries libphonenumber has no carrier data at all, so `carrier` is empty.
- **Line type** comes from the numbering plan. In the US and Canada fixed lines and mobiles share ranges, so you'll see `fixed_line_or_mobile`.
- **Location** is the region of the area code; for mobiles it is usually empty.

If you need live "is this number reachable" or "which network is it on now" (HLR lookups), that takes a paid network service. This Actor is for cleaning, formatting and sorting big lists cheaply before you do that.

### Use it from code

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('YOUR_USERNAME/phone-validator').call({
    phoneNumbers: ['020 8366 1177', '+1 650 253 0000'],
    defaultCountry: 'GB',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

### Example output

```json
{
  "input": "020 8366 1177",
  "isValid": true,
  "isPossible": true,
  "e164": "+442083661177",
  "international": "+44 20 8366 1177",
  "national": "020 8366 1177",
  "rfc3966": "tel:+442083661177",
  "countryCallingCode": "44",
  "country": "GB",
  "numberType": "fixed_line",
  "nationalNumber": "2083661177",
  "extension": null,
  "carrier": null,
  "location": "London",
  "timezones": ["Europe/London"],
  "error": null
}
```

# Actor input Schema

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

The numbers to check, one per line. Any common way of writing them works: +44 20 8366 1177, (415) 555-2671, 020 8366 1177 ext 12. Numbers without a country code use the default country below.

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

Two-letter country code (US, GB, DE...) used for numbers written without a +country code. Numbers that start with + ignore it. Leave empty if all your numbers already have a country code.

## `addCarrierAndLocation` (type: `boolean`):

Looks up the carrier the number was first assigned to, the city or region, and the time zones. Carrier data is the ORIGINAL carrier from the number's prefix. It does not know about numbers that were ported to another carrier. Many countries (including the US) have no carrier data.

## `language` (type: `string`):

Language code for the location and carrier text, like en, de, fr, es, ja, zh. Falls back to English where a language isn't available.

## `removeDuplicates` (type: `boolean`):

If the same value appears more than once in your list, check it once. Duplicates are not charged.

## `outputOnlyValid` (type: `boolean`):

Drops invalid numbers from the results. Invalid numbers are still counted in the run summary and still charged, since they were checked.

## Actor input object example

```json
{
  "phoneNumbers": [
    "+1 650 253 0000",
    "020 8366 1177",
    "+49 30 1234567",
    "+86 199 1234 5678",
    "12345"
  ],
  "defaultCountry": "GB",
  "addCarrierAndLocation": true,
  "language": "en",
  "removeDuplicates": true,
  "outputOnlyValid": false
}
```

# Actor output Schema

## `numbers` (type: `string`):

One row per number: valid or not, E.164, international and national format, line type, country, carrier, location and time zones.

## `allFields` (type: `string`):

Every row with all fields.

## `summary` (type: `string`):

How many numbers were checked, valid, invalid and skipped.

# 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 650 253 0000",
        "020 8366 1177",
        "+49 30 1234567",
        "+86 199 1234 5678",
        "12345"
    ],
    "defaultCountry": "GB"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ensorcelling_melilot/phone-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 650 253 0000",
        "020 8366 1177",
        "+49 30 1234567",
        "+86 199 1234 5678",
        "12345",
    ],
    "defaultCountry": "GB",
}

# Run the Actor and wait for it to finish
run = client.actor("ensorcelling_melilot/phone-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 650 253 0000",
    "020 8366 1177",
    "+49 30 1234567",
    "+86 199 1234 5678",
    "12345"
  ],
  "defaultCountry": "GB"
}' |
apify call ensorcelling_melilot/phone-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ensorcelling_melilot/phone-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/8qwAx5FsoSFs0AwIF/builds/dc7dDkQ0SLLwnBGvL/openapi.json
