Quick answer
For E.164 (the canonical international format) use /^\+[1-9]\d{1,14}$/. For human-typed numbers that may include spaces, dashes, and parentheses, normalize first (strip non-digit characters except a leading +) and then validate. Do not try to recognize every country format in one regex.
Phone number validation is harder than email. Country codes vary in length, local formats use different separators, and there is no equivalent to a confirmation email until SMS is involved. The right approach is two passes: a normalize step, then a strict E.164 check.
// Normalize first, then validate against E.164
function toE164(input) {
// Strip everything except digits and a leading +
const cleaned = input.replace(/[^\d+]/g, '').replace(/(?!^)\+/g, '');
return cleaned;
}
const E164 = /^\+[1-9]\d{1,14}$/;
function isValidPhone(input) {
return E164.test(toE164(input));
}
isValidPhone('+41 79 123 45 67'); // true
isValidPhone('(212) 555-0142'); // false (no country code)
isValidPhone('+1 (212) 555-0142'); // true
E.164: the format you want to store
E.164 is the ITU standard for international phone numbers. Format: + followed by a country code (1 to 3 digits), followed by the subscriber number, total length 7 to 15 digits. No spaces, no dashes, no parentheses. Examples:
- +14155552671 (US, 415 area code)
- +41791234567 (Switzerland, mobile)
- +8612345678901 (China, mobile)
If you are storing phone numbers anywhere (database, CRM, SMS provider) E.164 is the only sane representation. Twilio, MessageBird, Vonage, every SMS API expects it. Display formats are a presentation concern; E.164 is the storage format.
The minimal E.164 regex
The pattern /^\+[1-9]\d{1,14}$/ says:
- Start with a literal
+ - First digit is 1 through 9 (no country code starts with 0)
- Followed by 1 to 14 more digits (total 2 to 15 digits after the +)
- End of input
This is intentionally loose. It does not check whether the country code is real, or whether the subscriber number is the right length for that country. That is what libphonenumber is for. The regex is a syntactic guard before you call the heavier validator, not a replacement for it.
Handling human input formats
Real users type numbers with spaces, dashes, parentheses, and inconsistent country code prefixes:
- +41 79 123 45 67 (Swiss spaced format)
- +1 (212) 555-0142 (US with parens)
- 0041 79 123 45 67 (00 prefix instead of +)
- (212) 555-0142 (no country code at all)
The trick is to normalize first. Strip non-digits except a leading +, replace 00 at the start with +, and require a country code. If the input has no + and no 00 after stripping, you have a national-only number and you need to know the user's country to fill it in.
When the regex is not enough
Three cases force you to use a real phone library:
- Country code disambiguation. The number +1 is shared by the US, Canada, and a dozen Caribbean territories. The regex passes them all; only libphonenumber knows the area code mapping.
- Length validation per country. Italian mobile numbers are 9 to 10 digits; Swiss mobiles are 9; Chinese mobiles are 11. The regex accepts any 7 to 15 digit body. If you need exact length, use a library.
- Number type detection. Mobile vs landline vs toll-free vs premium-rate. Critical for SMS routing and cost control. Libphonenumber returns the type; regex cannot.
For a signup form that just wants to send one verification SMS, the regex plus libphonenumber's parsePhoneNumber() is the standard pairing. Regex blocks obvious typos in real time; the library does the country-aware check on submit.
Same pattern in other languages
The regex itself is portable:
- JavaScript:
/^\+[1-9]\d{1,14}$/.test(phone) - Python:
re.fullmatch(r"\+[1-9]\d{1,14}", phone) - PHP:
preg_match('/^\+[1-9]\d{1,14}$/', $phone) - Go:
regexp.MustCompile("^\\+[1-9]\\d{1,14}$").MatchString(phone)
The normalization step changes per language but the logic is the same: strip non-digits except leading +, then test.
Common mistakes
The patterns you will see online but should not copy:
- Hard-coded country prefixes. Patterns like
^(\+1|\+44|\+33)reject valid numbers from any country you forgot. Use\+[1-9]instead. - Allowing letters. Some patterns include
[A-Z]to handle vanity numbers (1-800-FLOWERS). Resolve those server-side; do not let them through validation. - Storing the human format. Always normalize to E.164 before storage, then format for display. Storing +1 (212) 555-0142 means every search and lookup has to handle whitespace.