# Phone Number Validator & Formatter | Carrier Data (`arjun_code/phone-number-validator`) Actor

Validate and format phone numbers in bulk from lists or CSV URLs with Google's libphonenumber metadata. Get E.164, country, number type, original carrier, location and time zones. Export valid and invalid results to JSON, CSV or Excel—no external lookup API or proxy required.

- **URL**: https://apify.com/arjun\_code/phone-number-validator.md
- **Developed by:** [Arjun AI](https://apify.com/arjun_code) (community)
- **Categories:** Lead generation, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 phone number processeds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Phone Number Validator & Formatter | Carrier Data

Turn inconsistent phone lists or CSV files into structured records for CRM imports, contact cleanup and reporting. Validate numbering patterns, normalize formats, and enrich each entry with available country, number-type, original-carrier and numbering-area metadata.

Phone-number processing runs locally inside the Actor using Google's libphonenumber metadata through its Python port. No phone-lookup API key, proxy, phone call or SMS is required. CSV URLs are downloaded over the network, and Apify storage and exports are used to deliver your results.

### What you get

- **Number validation:** separate `valid` and `possible` flags, with readable reason codes for entries that do not pass validation.
- **Standard formats:** E.164, international, national and RFC3966 `tel:` URI, with extensions preserved separately.
- **Number classification:** mobile, fixed line, fixed-line-or-mobile, VoIP, toll-free, premium-rate and other supported types.
- **Available metadata:** country/region, calling code, numbering-area label, original carrier and possible time zones.
- **Flexible batch input:** use a number list, a CSV download URL, or both. Select the CSV column and optionally cap the combined result count.
- **Complete validation output:** one row per selected entry, including invalid numbers. Input order and duplicate entries are preserved; empty CSV phone cells are skipped.
- **Clear metadata availability:** carrier availability, a note when carrier metadata is missing, and a UTC processing timestamp for every result.
- **Apify exports:** JSON, CSV and Excel through the Dataset, plus a separate run summary.

**Validation is not a live verification.** A valid number matches the library's numbering-plan rules; it does not prove that the number is assigned, active, reachable or owned by a particular person. Carrier and location fields are offline metadata, not a live carrier query or device location.

### Common use cases

- Clean and standardize phone columns before CRM or contact-database imports.
- Convert international and national inputs into consistent E.164 values for APIs and automation workflows.
- Separate mobile, fixed-line, VoIP, toll-free and other supported number types for routing or list review.
- Audit CSV lead lists without dropping invalid rows, so every processed input keeps a visible validation result.
- Add country, calling-code, numbering-area, original-carrier and time-zone metadata to internal data pipelines.

### Quick start

1. Enter one phone number per item in **Phone numbers**, or provide a **CSV file URL** and its phone-number column name.
2. Use `+` and the country calling code for international numbers. For national numbers, set the corresponding **Default region**, such as `CN`, `US` or `GB`.
3. Run the Actor and open **Phone validation results**. Download the full Dataset in your preferred format.

```json
{
  "phoneNumbers": ["+44 20 7946 0958", "+1 202 555 0100"],
  "language": "en"
}
```

These are example entries, not customer data or a claim that the numbers are active. To parse a UK national number, pass `"defaultRegion": "GB"` and an entry such as `"020 7946 0958"`.

### Input

| Field | Required | Meaning |
| --- | --- | --- |
| `phoneNumbers` | One source required | Array of strings, one number per item. Optional when `csvUrl` is supplied. Spaces, parentheses, extensions and other library-supported formatting are handled by the parser. |
| `csvUrl` | One source required | Direct HTTP or HTTPS download URL for a UTF-8, comma-separated CSV file with a header row. Optional when `phoneNumbers` is supplied. The URL must work without a separate login. |
| `csvColumn` | No | Exact, case-sensitive CSV header containing the numbers. Defaults to `phone`; used only with `csvUrl`. Other CSV columns are not copied to the output. |
| `defaultRegion` | No | Two-letter region code for numbers without a `+` country code. Empty by default: the Actor does not assume a country. Use `GB`, not `UK`, and `US`, not `USA`. |
| `maxResults` | No | Positive integer limiting the combined number of entries to process. Omit it to process all entries. Invalid entries and duplicates also count toward the limit. |
| `language` | No | Preferred language for country, area and original-carrier labels. Defaults to `en`; `zh` selects Chinese labels where available. Missing selected-language labels fall back to available English metadata. It does not change validation or number formats, and does not translate JSON field names, status values, reason codes or explanatory notes. |

For mixed-country lists, use `+` international numbers. Dialing prefixes such as `00` and `011` depend on the default region; the Actor does not globally replace them with `+`. Short codes and emergency numbers are not part of this full-length phone-number validator.

Provide `phoneNumbers`, `csvUrl`, or both. When both are supplied, inline entries are processed first, followed by CSV entries in file order. If the inline list already fills `maxResults`, the CSV is not downloaded. Otherwise, CSV reading stops when the remaining result limit is reached. Empty or whitespace-only CSV phone cells are skipped; non-empty but invalid entries still produce a result.

#### CSV example

```json
{
  "csvUrl": "https://example.com/phones.csv",
  "csvColumn": "phone",
  "maxResults": 1000,
  "language": "en"
}
```

Replace the placeholder URL above with your own CSV download URL. A matching file could contain:

```csv
phone
+44 20 7946 0958
+1 202 555 0100
```

CSV files must use UTF-8 (with or without a BOM), commas as separators, and a header row. A webpage or file-sharing preview link is not a direct CSV download. This Actor does not parse Excel files, extract numbers from website text or paragraphs, remove duplicates, or filter out invalid entries.

Invalid run-level settings fail with a clear message before results are treated as complete. This includes a missing input source, unsupported `defaultRegion` or `language`, a non-HTTP(S) or inaccessible CSV URL, non-UTF-8 CSV content, and a `csvColumn` header that is not present. Missing phone metadata inside an otherwise valid result still follows the output rule and uses `""`.

### Output

The main table shows the original number, validation status, E.164, country/region, number type, numbering area, original carrier and reason. The **Formats and metadata** view shows additional formats, time zones, carrier availability and processing time. Full JSON contains all 20 fields below.

| Field | Meaning |
| --- | --- |
| `input` | Original input entry. |
| `status` | `valid`, `possible` or `invalid`. `possible` means it passes a length-based possibility check but not full validation. |
| `valid` | Whether the number matches supported numbering-plan validation rules. |
| `possible` | The library's length-based possibility result; it can also be true for locally dialable numbers missing an area code. |
| `reason` | `""` for valid numbers; otherwise a reason such as `too_short`, `possible_but_invalid`, `possible_local_only`, `not_a_number` or `missing_or_invalid_country_code`. |
| `e164` | Normalized `+` international form; extensions are not included. |
| `international` | Readable international format. |
| `national` | Readable national format. |
| `rfc3966` | `tel:` URI, including an extension when present. |
| `extension` | Parsed extension, or `""`. |
| `countryCode` | Detected region code; `001` denotes a non-geographic calling service, not a country. `""` if undetermined. |
| `countryCallingCode` | Integer international calling code, such as `44`, or `""` when unavailable. |
| `countryName` | Available country name for a valid number, or `""`. |
| `location` | Available numbering-area or country label for a valid number, not the subscriber's current location. |
| `numberType` | Lowercase library classification, such as `mobile`, `fixed_line` or `fixed_line_or_mobile`. `unknown` is an explicit classification, not a missing value. |
| `originalCarrier` | Available original carrier associated with the number range, not necessarily the current carrier after number portability. |
| `timeZones` | Array of possible time-zone names from metadata for valid numbers; `""` when unavailable. |
| `carrierAvailable` | Boolean indicating whether `originalCarrier` contains metadata. `false` does not mean the number is inactive. |
| `carrierLookupNote` | Short explanation when carrier data is unavailable, validation was skipped, or the displayed carrier uses an English fallback. Usually `""` when the selected-language carrier label is available. |
| `validatedAt` | UTC timestamp in ISO 8601 format for this entry's processing. It is not a live network-verification timestamp. |

Missing values are returned as `""`, not `null` or an empty array. Meaningful `false` flags, numeric `0` counts and populated arrays retain their types. Unparseable inputs keep the same field structure with empty-string formats. A parseable but invalid number may still have formatted candidate values: filter on `valid: true` before treating a formatted number as a validated entry.

The **Validation summary** record includes selected input and processed counts, valid/possible-only/invalid totals, number-type counts, selected region/language and the library version used. Counts include duplicates. Its `inputSelection` section records inline entries supplied and selected, CSV rows actually read, CSV numbers loaded, empty CSV cells skipped, the chosen limit and whether the CSV was skipped because inline entries filled that limit. When reading stops early, these CSV counts are not totals for the entire file. `limitReached` means the selected count reached `maxResults`; it does not prove that more entries existed.

### Billing unit

Under pay-per-event pricing, each selected phone entry successfully written to the Dataset creates one `phone-number-processed` event. The current flat price is $0.0005 per result, or $0.50 per 1,000 processed numbers. Valid, possible-only and invalid results are all billable because each receives validation and formatting analysis. Empty CSV phone cells, entries not processed because the run charge limit was reached, and runs that fail during input or CSV validation do not create this event. Apify shows the active event and Actor-start prices before a paid run starts.

### Common questions

#### Can it identify the owner or check WhatsApp registration?

No. It does not look up names, accounts, messaging-app registration, subscriber records or breach data.

#### Does “valid” mean a number can receive SMS or calls?

No. The Actor performs offline numbering-plan validation. It does not contact the number or verify service availability. A number type is not a delivery guarantee.

#### Why is the type `fixed_line_or_mobile` or the carrier empty?

Some numbering plans do not distinguish fixed and mobile services by prefix. Carrier metadata is also not available for every number range. The Actor preserves this uncertainty.

#### Why did a national number fail?

Set `defaultRegion` to the region the national number belongs to, or provide the `+` international form. The Actor does not guess missing country or area codes.

#### Does `language` translate every result field?

No. It selects the best available language for `countryName`, `location` and `originalCarrier`. Translation coverage varies by country and number range. When a selected-language label is unavailable, available English metadata is returned; `carrierLookupNote` identifies an explicit carrier fallback. A localized area may fall back to a localized country name when no translated city or region label exists. Validation fields, formats and Actor explanations stay in English.

#### Do invalid numbers disappear from the output?

No. They are useful data-cleaning results and remain in the Dataset with a reason. A run can succeed even when some or all input numbers are invalid.

### Use with the Apify API

Use an Apify API token with access to this Actor. Phone validation itself does not need a separate provider key.

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arjun_code/phone-number-validator").call(
    run_input={
        "phoneNumbers": ["+44 20 7946 0958", "+1 202 555 0100"],
        "language": "en",
    }
)
for result in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(result)
```

### Open-source attribution

Powered by [Google libphonenumber](https://github.com/google/libphonenumber) via [python-phonenumbers](https://github.com/daviddrysdale/python-phonenumbers), an independently maintained Python port listed by the upstream project. This Actor wraps the library without modifying it. Third-party licenses and attribution are retained with the packaged dependencies and documented in `THIRD_PARTY_NOTICES.md`.

Use phone data you are authorized to process. Input and output are stored in your Apify run and storages; manage their sharing permissions in your account.

# Actor input Schema

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

One phone number per item. Optional when csvUrl is provided. Inline entries are processed before CSV rows; invalid entries and duplicates count toward maxResults. Use + and the country code, or set defaultRegion for national numbers.

## `csvUrl` (type: `string`):

Direct HTTP or HTTPS URL to a UTF-8, comma-separated CSV with a header row. Select its phone-number column using csvColumn. Can be used alone or after phoneNumbers. Empty phone cells are skipped. The URL must be downloadable without a separate login.

## `csvColumn` (type: `string`):

Exact, case-sensitive header of the CSV column containing phone numbers. Used only with csvUrl. Other CSV columns are not included in results.

## `defaultRegion` (type: `string`):

Two-letter region code, for example CN, US, GB or DE. Applies to numbers without a + country code and to region-specific international dialing prefixes such as 00 or 011. Leave empty if every number starts with +. The Actor does not guess a country.

## `maxResults` (type: `integer`):

Maximum number of entries to validate across phoneNumbers and CSV combined, including invalid entries and duplicates. Leave empty to process all available entries. If inline entries fill the limit, the CSV is not downloaded.

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

Preferred language for country, area and original-carrier labels. When the selected translation is unavailable, the Actor uses an available English label; a carrier fallback is explained in carrierLookupNote. Number validation, formats, JSON field names, status values and notes are not translated.

## Actor input object example

```json
{
  "phoneNumbers": [
    "+44 20 7946 0958",
    "+1 202 555 0100"
  ],
  "csvColumn": "phone",
  "defaultRegion": "GB",
  "maxResults": 1000,
  "language": "en"
}
```

# Actor output Schema

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

One result per selected inline entry or non-empty CSV phone cell, up to maxResults. Includes invalid numbers, carrier availability and validation time. Missing values are empty strings.

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

Processed counts, validation and number-type totals, inline/CSV selection counts, result limit, input region, language, billing events and metadata library version.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("arjun_code/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 = {}

# Run the Actor and wait for it to finish
run = client.actor("arjun_code/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 '{}' |
apify call arjun_code/phone-number-validator --silent --output-dataset

```

## MCP server setup

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