Phone Number Validation Regex: Patterns That Work, and Why to Use a Library
The standard regex for an E.164 phone number is:
^\+[1-9]\d{1,14}$
A +, a first digit 1–9, and at most 15 digits in total. It checks the shape of an international number, and that's all a regex can do. It'll happily accept +999999999999, which isn't a number anywhere. For real validation, use a numbering-plan library like Google's libphonenumber; regex is for filtering obvious garbage.
Patterns you can use
E.164 (storage format)
^\+[1-9]\d{1,14}$
Use it to check values after you've normalised them, for example before writing to a database. It rejects spaces, dashes and a leading 0 country code.
North American numbers (US, Canada, Caribbean)
^\+1[2-9]\d{2}[2-9]\d{6}$
E.164 form only. Enforces that both the area code and the exchange start with 2–9, which catches (212) 123-4567. It still accepts unassigned area codes like 555 and doesn't know whether +1 876 is Jamaica.
Loose input filter (any country, any formatting)
^\+?[0-9\s().\-]{7,20}$
For a form field while the user types. It lets through (415) 555-2671, +44 20 7946 0958 and 0412 345 678, and blocks letters and obvious junk. Don't treat a match as valid.
What each pattern lets through
We ran inputs through these patterns and through libphonenumber (version 9.0.41, Python port) to compare:
| Input | E.164 regex | NANP regex | libphonenumber |
|---|---|---|---|
+14155552671 |
Match | Match | Valid, US |
+15551234567 |
Match | Match | Invalid (555 isn't an area code) |
+12121234567 |
Match | No match | Invalid |
+442079460958 |
Match | No match | Valid, GB landline |
+4402079460958 |
Match | No match | Parsed and normalised to +442079460958 |
+999999999999 |
Match | No match | Rejected (there is no country code 999) |
+18765550123 |
Match | Match | Valid, Jamaica, mobile |
The pattern of failures is the point. Every row where regex and the library disagree needs data: which area codes are assigned, which country codes exist, which ranges are mobile. That data changes as regulators allocate new ranges, which is why libphonenumber ships frequent metadata updates and a regex never gets them.
Why not write a better regex?
People try. The result is a pattern per country, each with:
- different lengths (Germany alone has variable-length numbers);
- trunk prefixes to strip, except where they aren't stripped (Italy keeps its
0after+39); - mobile, landline, toll-free and premium ranges;
- shared country codes (
+1covers around 20 countries;+44includes Jersey, Guernsey and the Isle of Man); - changes every time a regulator opens a new range.
That's what libphonenumber's metadata is: the numbering plans of every country, kept current. Reimplementing it in regex means maintaining a worse copy.
The library version
JavaScript (libphonenumber-js):
import { parsePhoneNumberFromString } from "libphonenumber-js";
const phone = parsePhoneNumberFromString("(415) 555-2671", "US");
phone?.isValid(); // true
phone?.number; // "+14155552671"
phone?.country; // "US"
Python (phonenumbers):
import phonenumbers
n = phonenumbers.parse("020 7946 0958", "GB")
phonenumbers.is_valid_number(n) # True
phonenumbers.format_number(n, phonenumbers.PhoneNumberFormat.E164) # '+442079460958'
Fuller walkthroughs: validate phone numbers in JavaScript and in Python.
A sensible setup
- On the input: the loose regex, or no regex, plus a country picker so numbers without a
+can be parsed. - On submit / on the server: parse with a numbering-plan library, reject invalid numbers, store E.164.
- Before SMS or calling campaigns: a carrier lookup where line type matters. See mobile vs landline lookup.
The same split applies to email: a regex catches typos, a mailbox check proves the address exists. See email validation regex.
Validating a file instead of an input
For a CSV export rather than a form, you don't need any code. Upload the file on the SimpleVerifier verifier. Every row with a phone number gets phone_status, phone_e164, phone_country and phone_type, computed with libphonenumber's metadata. It's included on paid plans; see pricing.
Related: how to check if a phone number is valid · E.164 format explained
Common questions
What is the regex for an E.164 phone number?
^\+[1-9]\d{1,14}$ matches the E.164 shape: a plus sign, a first digit from 1 to 9, and up to 15 digits in total. It confirms the format, not that the country code or number exists.
Can regex validate phone numbers?
Regex can check shape: allowed characters, length, and simple rules like a US area code starting 2 to 9. It can't know which prefixes are allocated in each country, which ranges are mobile or toll-free, or how long numbers are in a given region. That needs numbering-plan data.
What library should I use for phone validation?
Google's libphonenumber or one of its ports: libphonenumber-js for JavaScript, phonenumbers for Python, and official or community ports for Java, C#, PHP, Go and others. They ship the numbering-plan metadata that regex can't encode.
Should I use a regex on a phone input field?
A loose one, yes, to stop obvious garbage while the user types. Then validate properly with a library on submit or on the server. A strict regex on the input field mostly rejects real numbers written in a format you didn't anticipate.
Check your list before you send
Real mailbox checks over SMTP, and nothing is sent to the address. Sign in with Google and your first 100 email checks are free, no card. Plans for bigger lists are on the pricing page.