Blog Post

Tags

Phone numbers in JavaScript using E.164, libphonenumber and Microdata

When you’re collecting data from users, there are two key challenges; collecting that information, and validating it. Some types of information are straightforward – someone’s age, for example, couldn’t really be simpler to collect and to validate. Names aren’t as straightforward as they sound, but provided you cater for edge cases and international variations – for example patronymics, the mononymous, or even just people with hyphenated surnames – you can’t go too far wrong (although plenty of applications and services do!). Email addresses, while theoretically very easy to validate, have their own challenges – yet nevertheless, there are plenty of regular expressions in the wild that aren’t quite right.

And then there are telephone numbers. These are hard. Really hard. In this article I’ll discuss some of the challenges around collecting, validating, and displaying telephone numbers.

Why Telephone Numbers are Different

Perhaps you’re thinking that since telephone numbers tend to follow a pretty rigid format, such as this:

202-456-1111

...that it ought to be simple to construct a simple regular expression to validate them. In fact, here’s one:

^(\([0-9]{3}\)|[0-9]{3}-)[0-9]{3}-[0-9]{4}$

Well, stop right there. For starters, here are just some variations of the number above, all of which are perfectly valid:

So based on that, we know that the regular expression apparoach isn’t as simple as we first thought – but that’s only the half of it. These examples are just for a US-based number. Sure, if you know that the number you’re collecting is going to be for a specific country, you may be able to use a regular expression. Otherwise, this approach won’t cut it.

Let’s look at some of the other issues around telephone numbers, and why they make our job even harder.

Numbers Changes

All sorts of external factors can have implications for telephone numbering. Whole countries come and go, introducing new country prefixes. New classifications of numbers introduce new numbering systems – premium-rate, local-rate, toll-free, and so on. When a carrier runs out of one set of numbers – like, sadly, premium-rate – they simply introduce a new prefix.

Some changes have enormous implications; in the United Kingdom some years ago, for example, the entire regional numbering system underwent a drastic change, with virtually every area code getting an additional “1” inserted. Even then, the capital had a subtly different system. It was probably a decade before signage was changed across the country to reflect the changes.

Then, of course, there was the enormous and unprecedented growth in mobile. No longer was the number of telephone numbers required largely limited to the number of households, but many times over. The continued strain on the pool of available numbers can only increase the likelihood of further changes.

International Dialing Codes

It’s often important to capture a number’s international dialling code. In some cases, the context might mean they aren’t required. For example if you operate in a single country, and telephone numbers are captured to be used by a human operator, you might not need them. But for anything remotely automated – such as sending SMS messages – or to validate them effectively, you’ll need to capture the country prefix.

The countries library contains a bunch of geographical information which includes international dialling codes. Here is an excerpt from countries.json from that library:

Even international dialling codes, however, aren’t as straightforward as you may think. The format can vary – 1, 43, 962 1868 are all valid codes. There isn’t necessarily a one-to-one mapping; 44 for example, is used not just for the United Kingdom but for the Isle of Man, Guernsey and Jersey.

Numbers must also be altered according to where you’re dialing from. From abroad, to call a UK number you need to drop the leading zero and prefix with the dialing code 44:

020 7925 0918

...becomes...

+44 20 7925 0918

You can also replace the “+” with a double zero:

0044 20 7925 0918

To complicate things even further, some numbers vary when called from outside of a country depending on which country you’re dialing from. In the US, for example, numbers must also be prefixed with the US exit code 011 , so the example above becomes:

011 44 20 7925 0918

Thankfully, there is a format we can use which enable us to get around these variations.

E.164

Luckily for developers there is an unambiguous, internationally recognized standard for telephone numbers anywhere in the World called E.164. The format is broken down as follows:

A telephone number can have a maximum of 15 digits

The first part of the telephone number is the country code

The second part is the national destination code (NDC)

The last part is the subscriber number (SN)

The NDC and SN together are collectively called the national (significant) number (source)

Here’s the number from earlier, in E.164 format:

+12024561111

We can use the same format for, as an example, a London-based UK number:

+442079250918

We can represent any valid telephone number using the E.164 format. We know what country it refers to, and it’s unabmiguous – making it the ideal choice for storage. It’s also commonly used for telephony based services such as SMS providers, as we’ll see a little later.

There’s a catch, of course. The E.164 standard might be great for storage, but terrible for two things. First, virtually no one would type or read out their number in that format. Second, it’s hopeless in terms of its readability. Later though, when we look at libphonenumber , we’ll see that there are ways of formatting numbers for humans.

Collecting Telephone Numbers

First though, let’s look at the issue of collecting telephone numbers.

HTML5 and the tel input

HTML5 introduced a new “tel” input type. However, because of the issues around the variations in format, it doesn’t actually place any restrictions on what the user can type, nor does it perform any validation in the same way as, say, the email element. Nevertheless, there are some advantages – when used on a mobile site a user’s telephone keypad will usually be displayed, rather than a conventional keyboard layout.

You can use a single element to collect a number:

Alternatively, you can break a number down into separate elements:

() -

Browser support is pretty good (e.g. Chrome 6+, Firefox 4+, Safari 5+, IE 10+), but even in an older browser it will simply fall back to a plain old text field.

Should we decide that a regular expression is sufficient – and remember, there are issues – then we can use the pattern attribute to add some validation:

Masked Inputs

Masked inputs are a common technique for restricting user input or providing hints as to the expected format. But again, unless you can be confident that numbers will always be for a particular country, it’s very difficult to cater to international variations. However, it’s one thing to annoy users by making assumptions – asking a non-US user to provide a state and a zip-code. It’s quite another to make a form completely unusable, for example by forcing people to provide numbers in a certain country’s format.

Nevertheless, they can be effective if you know that certain numbers will be within a particular range. Here is an example of a masked input for US telephone numbers.

A Better Way

There is a better and more flexible way to collect telephone numbers, in the form of an excellent jQuery plugin. It’s illustrated below.

Usage is simple – make sure you’ve included jQuery, the library, and the CSS file, and that the flag sprite is available and properly referenced from the CSS – you’ll find it in build/img/flags.png.

Next, create an element:

Finally, intialize it as follows:

$("#number").intlTelInput();

For a full list of configuration options, consult the documentation. Later, we’ll look at the option, but first, we need to delve into another useful library.

Introducing liphonenumber

Luckily, there’s a solution to many of our validation and formatting woes. Originally developed for the Android operating system, Google’s libphonenumber library offers all sorts of methods and utilities for working with telephone numbers. Better still, it’s been ported from Java to Javascript, so we can use it in web or Node.js applications.

Installation

You can download the library from the project homepage on – as you might expect – Google Code.

You can also get it via npm. Here’s the project page, and to install from the command-line:

npm install google-libphonenumber

You can also install it using Bower:

bower install libphonenumber

If you’re thinking of using it in a front-end project, be warned though – even when minified and compressed, it comes in at over 200Kb.

This is because without explicitly telling it what country the number is for, it’s impossible to interpret. The parse() method takes an optional second parameter, which is the ISO 3166-1 alpha-2 (i.e., two character) country code.

If you try the line again, but this time passing “US” as the second argument, you’ll find that the results are as before:

var tel = phoneUtil.parse('2024561111', 'US');

You can also play around with the formats; all of these will work, too:

console.log(phoneUtil.isValidNumber(phoneUtil.parse('573 1234 1234', 'US')));
// => outputs false
console.log(phoneUtil.isValidNumber(phoneUtil.parse('555-555-5555', 'US')));
// => outputs false (this is often used as a placeholder, but it's not a valid number)
console.log(phoneUtil.isValidNumber(phoneUtil.parse('295-123-1234', 'US')));
// => outputs false (there is no 295 area code in the US)

Be warned, however, as an invalid number can throw an exception:

console.log(phoneUtil.isValidNumber(phoneUtil.parse('NOT-A-NUMBER', 'US')));
// => throws exception "Error: The string supplied did not seem to be a phone number"

Determining a Number’s Type

Sometimes, it’s useful to know the type of a telephone number. For example, you may wish to ensure that you’ve been provided with a mobile number – perhaps you plan to send SMS messages, for example to implement two-factor authentication – or attempt to weed out premium rate numbers.

The library’s getNumberType() function does just that. Let’s take a look.

As seems to be the theme of the topic, naturally there’s a catch. Sometimes, even the libphonenumber library can’t be sure. US numbers, for example, cannot be easily distinguished; hence the constant PNT.FIXED_LINE_OR_MOBILE .

We’ll just have to change our example code to reflect this uncertainty:

There are a number of other possibilities, too. Here is the full list currently:

PNT.FIXED_LINE

PNT.MOBILE

PNT.FIXED_LINE_OR_MOBILE

PNT.TOLL_FREE

PNT.PREMIUM_RATE

PNT.SHARED_COST

PNT.VOIP

PNT.PERSONAL_NUMBER

PNT.PAGER

PNT.UAN

PNT.UNKNOWN

As you can see, the PNT.UNKNOWN reflects the fact that we can’t necessarily glean any information with any certaintly. So in summary, whilst this feature can be useful as a quick initial check, we can’t rely on it.

Is the Number in Service?

There are plenty of telephone numbers which will validate, but which are not in use. They may have been disconnected, not yet allocated, or perhaps a SIM card has been dropped down a toilet.

If you need to ensure that a number is not just valid but also active, there are a number of options open to you.

One approach is to require users’ confirm their number, in much the same way as you might require users confirm their email address. You can use a service such as Twilio to send an SMS, or even place a call.

Here is a very simple code snippet for generating and sending a confirmation code by SMS using Twilio:

Other Issues

Legal

As with any personal information, there are also plenty of legal issues to be mindful of. In the UK, for example, the Telephone Preference Service (TPS) is a national register of telephone numbers which have explictly been registered by people not wishing to receive marketing communications. There are paid services which offer APIs to check a number against this register, such as this one.

Usability Considerations

It’s very common to request up to three different telephone numbers in a single form; for example daytime, evening and mobile.

It’s also worth remembering that asking for telephone numbers over the internet can come across as rather intrusive. If someone is unwilling to provide that information despite you having made it a required field, they will probably do one of two things:

Attempt to “fool” the validation. Depending on the approach, they may type something like “ex directory”, or enter an invalid number – such as one which contains only numbers.

Walk away.

Combining the jQuery Plugin with libphonenumber

You might remember that the jQuery plugin has a rather cryptically named option called utilsScript

This option allows us to take advantage of the validation and formatting features of libphonenumber . Having selected a country – either using the drop-down or by typing the dialing code – it will transform the textfield into a masked input which reflects that country’s numbering format.

The plugin contains a packaged version of libphonenumber; pass the path to this file to the constructor as follows:

As I’ve previously mentioned, do bear in mind that this approach should be used with caution, owing to the file size of the libphonenumber library. Referencing it here in the constructor does however mean that it can be loaded on demand.

Displaying Telephone Numbers

We’ve looked at how we can format numbers when displaying them to be more “friendly”, using formats such as PNF.INTERNATIONAL and PNF.NATIONAL.

We can also use the tel and callto protocols to add hyperlinks to telephone numbers, which are particulary useful on mobile sites – allowing users to dial a number direct from a web page.

To do this, we need the E.164 format for the link itself – for example:

Microdata

Acme Corp, Inc.

Summary

In this article, we’ve opened up the hornets nest that is telephone numbers. It should be pretty apparent by now that there are all sorts of complexities, subtleties and gotchas you need to be aware of if you need to collect, validate and display them.

We’ve looked at a few methods for collecting numbers – the “tel” input type, masked inputs and finally the intl-tel-input jQuery plugin.

We then looked at some of the issues around validation, and why common approaches such as regular expressions are often inadequate, particularly when you go international.

We took a look at Google’s libphonenumber library; using it to parse, validate, display and determine the type of telephone numbers.

We combined the intl-tel-input plugin with libphonenumber for an even better user experience, albeit one which comes at a cost in terms of performance.

Finally we looked at how we might mark up telephone numbers in our HTML.

There are a few recommendations I would make for dealing with telephone numbers:

Unless you only operate in a single country, be aware of the international differences. Use masked inputs with caution.

Be very careful with regular expression-based validation.

Where possible, use E.164 for storage.

Use Google’s libphonenumber library.

When displaying numbers, format them where possible, use the tel: or callto: link type, and use Microdata.

Who Are Ronald James?

We are a leading niche digital & tech recruitment specialist for the North East of England. We Specialise in the acquisition of high-performing technology talent across a variety of IT sectors including Digital & Technology Software Development.

Our ultimate goal is to make a positive impact on every client and candidate we serve - from the initial call and introduction, right up to the final delivery, we want our clients and candidates to feel they have had a beneficial and productive experience.

Contact our Team

If you’re looking to start your journey in sourcing talent or find your dream job, you’ll need a passionate, motivated team of experts to guide you. Check out our Jobs page for open vacancies. If interested, contact us or call 0191 620 0123 for a quick chat with our team.