Phone Number Validator & Enrichment (bulk, 200+ countries) avatar

Phone Number Validator & Enrichment (bulk, 200+ countries)

Pricing

from $0.80 / 1,000 number validateds

Go to Apify Store
Phone Number Validator & Enrichment (bulk, 200+ countries)

Phone Number Validator & Enrichment (bulk, 200+ countries)

Clean a phone list in one run: validity, formatting in three styles, number type, country, region, carrier and timezones for 200+ countries, plus optional discovery of phone numbers on company websites. No API keys needed. Built for CRM hygiene, lead enrichment and SMS prep.

Pricing

from $0.80 / 1,000 number validateds

Rating

0.0

(0)

Developer

Paul Vasquez

Paul Vasquez

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Phone Number Validator and Enrichment

Normalize phone lists, inspect numbering-plan validity, and discover telephone numbers on public homepages and contact pages. This Python 3.12 Apify actor uses the offline phonenumbers port of libphonenumber. List processing requires no network, API key, provider account, or paid lookup service. Optional website discovery uses HTTP requests and HTML parsing without a browser.

What validation means

valid means that a parsed number matches the library's numbering-plan metadata. possible primarily checks whether its length is plausible. A possible number can still be invalid. A valid number can be unassigned, disconnected, or unable to receive messages. This actor performs no HLR lookup and makes no “is active” claim. It does not call numbers, send SMS, identify subscribers, or verify ownership. Metadata may lag numbering-plan changes.

Carrier information describes the original allocation where available. Number portability means it may not identify the current carrier. Geographic descriptions refer to numbering areas, not a person's present location. Timezones are candidate zones from metadata, not a device location. Missing enrichment is returned as null or an empty array instead of an invented value.

Input

phoneNumbers accepts up to 10,000 strings. List order and duplicates are preserved, so each input has a corresponding result unless a charging limit prevents additional paid output. defaultRegion defaults to US; use an ISO region such as GB, DE, or IN for national numbers. International numbers starting with + carry their own country calling code.

websiteUrls optionally accepts up to 100 HTTP(S) URLs. Each URL is normalized to its origin homepage, followed by the origin's /contact path. Credentials in URLs are rejected. Repeated normalized sites are scanned once. The actor follows up to five redirects, but does not discover alternative contact links, execute JavaScript, solve access challenges, or crawl a site's other pages.

outputFormat is e164, international, or national, defaulting to e164. It selects the additional formatted field; all three explicit format fields remain present. includeCarrier defaults to true. includeGeo defaults to true and controls geographic description and timezones; country and region remain available. timeoutSecs bounds each complete page attempt, from 1 to 60 seconds. The supplied daily input uses five seconds and 15 mixed numbers plus Python.org and Apify, requiring no keys and completing comfortably under two minutes in the recorded validation.

Results

Number rows contain input, source, valid, possible, e164, international, national, formatted, countryCode, region, regionName, numberType, carrier, location, timezones, isMobile, isTollFree, isVoip, and error. countryCode is numeric; region is a library region code. Non-geographic numbers may use region 001. Descriptions are English. Types include mobile, fixed line, fixed-line-or-mobile, VoIP, toll-free, premium rate, and unknown. isMobile includes the ambiguous fixed-line-or-mobile type; consult numberType when the distinction matters.

Website number rows additionally include websiteUrl, foundOn, and context. Context contains the matched text with up to 40 characters on either side. Scripts, styles, and noscript content are excluded; visible text and telephone links are matched with PhoneNumberMatcher using POSSIBLE leniency. E.164 deduplication applies within each website across both pages, retaining the first occurrence. Extensions sharing the same E.164 number collapse together. Numbers from separate websites or the explicit list remain separate results.

Filter rowType=number when exporting only telephone results. Each attempted unique website also produces an uncharged website-summary row with fetched-page count, discovered-number count, failures, and timing. SUMMARY in the key-value store records aggregate counts and eligible billing events. A successful fetch with zero matches is an ordinary empty result, not proof the business has no phone.

Pricing and failures

number-validated costs $0.0008 per parseable number row, whether valid or invalid. Empty and unparseable strings produce uncharged error rows. website-scanned costs $0.002 once per website with at least one successfully fetched HTML page, including websites with zero matches. It is not charged per page. Discovered parseable numbers also incur the number event. Summary rows themselves are always free; completely failed websites incur no website event.

HTTP 429, server errors, and transport failures receive two retries with one- and two-second backoff. Other HTTP errors are not retried. Responses exceeding two megabytes or non-HTML responses are rejected. Partial website results survive page failures. Charging limits stop further events of that type. Charging occurs before persistence, so storage failures cannot be automatically rolled back.

Running and verification

Create a Python 3.12 virtual environment, install requirements.txt, then run:

apify validate-schema .actor/input_schema.json
.venv/Scripts/python.exe -m unittest discover -s tests -v
powershell -NoProfile -ExecutionPolicy Bypass -File validation/run_live.ps1

The live harness creates isolated local storage and records results and timings under validation/. Local SDK charges are ignored, not actual billing. Before deployment, configure both custom events from .actor/pay_per_event.json in Console and disable synthetic charges. See VALIDATION.md for measured evidence and remaining platform checks. Library behavior is documented in the upstream project; charging uses the Apify SDK.

Example output

Recorded local validation output from validation/results.json, the first item in rows. Fields are omitted for brevity; retained values are unchanged. This is a historical example, not a current-source claim.

{
"rowType": "number",
"input": "+1 202-555-0123",
"source": "list",
"valid": true,
"possible": true,
"e164": "+12025550123",
"region": "US",
"numberType": "FIXED_LINE_OR_MOBILE",
"carrier": null,
"error": null
}

Use cases

  • A CRM administrator normalizes imported telephone strings to E.164 while routing unparseable records to a cleanup queue.
  • A customer support operations manager separates toll-free, fixed-line, and ambiguous mobile classifications before reviewing contact-routing rules.
  • A data quality consultant compares valid and possible flags in a client-supplied list to prioritize manual record correction.
  • A business directory editor scans supplied public websites for contact numbers and reviews the retained page context before updating listings.

Pricing example

1,000 parseable number rows and 100 successfully scanned websites cost (1,000 x $0.0008) + (100 x $0.002) = $1.00 in declared events. The 1,000 includes any discovered numbers; extra discovered parseable rows add $0.0008 each. Rates come from .actor/pay_per_event.json. This calculation is an event subtotal, not a measured invoice; local validation does not bill.

Limitations

The saved example comes from the validation input list, not a verified subscriber. A true validity flag establishes neither reachability nor ownership. National-format results depend on the selected region. Website discovery covers only the homepage and /contact; zero matches do not establish absence of a telephone number.