Phone Number Formatter
Writes a phone number as E.164 to store and nationally to display, in twenty countries, and says why a length check is not validation.
Country United Kingdom, +44
Numbers in 3
Parsed 3
020 7946 0958
E.164, to store +442079460958
national, to show 020 7946 0958
international +44 20 7946 0958
in a link tel:+442079460958
dropped the trunk prefix 0
07700 900123
E.164, to store +447700900123
national, to show 07700 900123
international +44 7700 900123
in a link tel:+447700900123
dropped the trunk prefix 0
0121 496 0000 x24
E.164, to store +441214960000
national, to show 0121 496 0000
international +44 121 496 0000
in a link tel:+441214960000;ext=24
extension 24, which no carrier dials for you
dropped the trunk prefix 0
How United Kingdom numbers are built
country code +44
trunk prefix 0, dialled at home and dropped in E.164
digits after it 9 or 10
structure area codes of two, three or four digits, plus the 7 range for mobiles
Store E.164 and nothing else: a plus, the country code, the number, no
spaces. It is unambiguous, it is what every gateway and CRM accepts, and
it sorts and compares correctly. Store the national format and you have
thrown away the country.
Display the national format. `020 7946 0958` is how a British reader
recognises a number and `+442079460958` is not, so the two exist for
different jobs and the conversion is cheap in both directions.
The leading 0 is a dialling instruction rather than part of the number,
which is why E.164 has no room for it. Italy is the country where that
is not true, and it catches people out.
A length check is not validation. A number of the right length can be
unassigned, disconnected, a landline that cannot receive a text, or a
VoIP number in a different country to the one it looks like. The only
real check is sending a code to it.
In HTML use `tel:` with the E.164 value, not the pretty one: `<a
href="tel:+442079460958">020 7946 0958</a>`. Punctuation in the href is
tolerated by most dialers and not by all of them, and a leading zero in
an international context is dialled as a zero.
An extension is not part of the number. It belongs in its own field, the
`;ext=` parameter exists for a link, and no carrier dials it for the
caller: an IVR has to hear it as tones after the call connects.
Store what the person typed as well. If the parse turns out to be wrong,
the original is the only way to recover, and a form that silently
rewrites a number to something undeliverable is a support ticket nobody
can trace.
The table here covers the common ranges in each country. The complete
one is libphonenumber, which is about a megabyte and is updated when a
regulator opens a new range. Anything charging money per message should
use it rather than a length check.
Output is valid and updates as you type.
Fix the highlighted fields to update the output.
There are two phone number formats and they do different jobs. E.164 is for storing: a plus, the
country code, the number, no punctuation. The national format is for reading: 020 7946 0958.
Storing the national one throws away the country. Displaying the E.164 one makes the number unrecognisable to the person it belongs to. So the answer is to store E.164, keep what the person typed alongside it, and format for display.
The interesting part is the leading zero. In most countries it is a trunk prefix, a domestic
dialling instruction, and it does not belong in the number: 020 7946 0958 is +442079460958
with no zero anywhere. In Italy the zero is part of the number and is kept. In North America the
trunk prefix is 1, which is also the country code, which is why 1 555 010 0199 and
+1 555 010 0199 are the same number.
How to use
- Paste a number, or a list one per line.
- Pick the country the number belongs to. That is what tells the parser how to read a leading zero or a leading 1.
- Copy the E.164 column into your database and the national column into your page.
Example
Three British numbers, one with an extension:
Country United Kingdom, +44
Numbers in 3
Parsed 3
020 7946 0958
E.164, to store +442079460958
national, to show 020 7946 0958
international +44 20 7946 0958
in a link tel:+442079460958
dropped the trunk prefix 0
0121 496 0000 x24
E.164, to store +441214960000
national, to show 0121 496 0000
international +44 121 496 0000
in a link tel:+441214960000;ext=24
extension 24, which no carrier dials for you
dropped the trunk prefix 0
The extension is not part of the number. It has its own parameter in a tel: link, and no
carrier dials it for the caller: an IVR has to hear it as tones after the call connects.
Pitfalls
A length check is not validation. A number of exactly the right length can be unassigned, disconnected, a landline that cannot receive a text, or a VoIP number registered in a different country to the one its code suggests. This tool will happily format a nine-digit British number that does not exist. The only real check is sending a code to it.
Italy keeps its leading zero. Rome is +39 06 6982, with the zero, in E.164. Strip it the way
the rest of Europe needs and the number stops working. It is the exception worth remembering
because every generic “remove the leading zero” rule breaks it.
The North American 1 is both a trunk prefix and a country code. Eleven digits starting with 1 and ten digits are the same number. No area code in the plan starts with 1, which is what makes stripping it unambiguous.
Do not store the formatted number. Formatting is presentation and it changes: Mexico dropped its trunk prefixes in 2019 and Brazil added a ninth digit to mobiles. E.164 does not change, and reformatting from it is cheap.
Use E.164 in a tel: link. <a href="tel:+442079460958">020 7946 0958</a>. Punctuation in
the href is tolerated by most dialers and not by all, and a leading zero without a country code is
dialled as a zero from abroad.
Never reject a number for looking unusual. Area codes vary from one digit to five, subscriber numbers from six to eleven, and regulators open new ranges regularly. A form that refuses a valid number loses the customer and never hears why.
Comparing numbers means comparing E.164. Two rows holding 020 7946 0958 and
+44 20 7946 0958 are the same customer and no query will tell you that.
Compatibility
Everything runs in the browser: nothing is uploaded and nothing is stored, which matters because a list of phone numbers is personal data under most privacy law.
Twenty countries are covered, each with its country code, trunk prefix, the lengths it uses and the grouping that country writes. Every case in the test suite is a number written the way a person in that country writes it, checked against the E.164 a gateway expects: British mobiles and the two-, three- and four-digit area codes, German mobiles against Berlin, Tokyo’s one-digit area code, Brazil’s ninth digit, Italy’s kept zero, and the North American 1 in all three of its positions.
The complete data set is Google’s libphonenumber. It is about a megabyte, it is updated whenever a regulator opens a range, and it is the right choice for anything that charges money per message. The table here covers the common ranges and says which ones, rather than implying it covers everything.
Extensions are recognised after x, ext, ext., extension or #, and are reported
separately rather than being glued onto the number.
Frequently asked questions
Which field should I store in the database?
Why does the parser want to know the country?
06 12345678 is a Dutch mobile, an Italian Rome
landline and a French number depending on where it was written, and the three give different
E.164 values.