FreeToGenerate.com

Paste a tel: URI and see what the grammar makes of it — whether it is valid, what the parts mean, and the canonical spelling. It also compares two URIs by the standard's own five rules, which do not agree with comparing the strings. Nothing is uploaded.

Try one:

Paste one, or type a number and watch what the grammar makes of it. The scheme name is case-insensitive.

This is not a valid tel: URI.

A local number must carry a phone-context. The grammar puts it inside local-number, so a bare local number is not a tel: URI at all — add ;phone-context= with a domain or a global number prefix, or write the number in global form starting with +.

Are two URIs the same number?

RFC 3966 gives a five-rule algorithm for this, and it does not agree with comparing the strings. Two URIs that look different can be the same number, and two that differ by one parameter are not.

Equivalent — the same number.

Everything here runs in your browser. Nothing you enter is uploaded.

Also available in: Español · Português · Français · العربية

tel: link generator, and why tel:555-1234 is not a valid URI

Build a conforming tel: link, and compare two of them by RFC 3966's own equality algorithm.

What is a tel: link?

A tel: URI is how a web page hands a phone number to whatever on the reader's device makes calls. Put it in an href and a tap dials; that much is well known. What is much less known is that tel: has a real grammar, defined by RFC 3966, and that the spelling nearly every tutorial shows does not match it.

The grammar has two forms. A global number starts with a plus and is decimal digits only — tel:+15550100 — and stands on its own anywhere in the world. A local number does not start with a plus, and the grammar requires it to carry a phone-context parameter saying where it is valid: tel:863-1234;phone-context=+1-914. That parameter is not optional decoration. It sits inside the local-number production itself, so a bare tel:555-1234 is not an incomplete tel: URI, it is not a tel: URI.

This page parses what you give it against that grammar, says which form it is and what each part means, writes the canonical spelling, and — separately — answers whether two URIs are the same number according to the standard's own comparison rules.

How to use it

  1. Paste a tel: URI, or type a number and watch the verdict change. The five sample buttons load real cases, starting with the invalid one everybody writes. The scheme name is case-insensitive, so TEL: parses too.
  2. Read the details and the notes. The details panel separates the number as written from the number used for comparison, and says whether a phone-context is a domain or a number — which changes how it is compared. The notes are things that are valid but worth knowing, never errors.
  3. Use the comparison panel for the question strings cannot answer. Paste two URIs and it applies RFC 3966's five rules. Its samples include two that look different and are the same number, and one pair that differs by a single parameter and therefore is not.

Why tel:555-1234 fails, and what to write instead

The relevant ABNF is three lines. The subscriber part is either a global-number or a local-number; global-number is just digits with optional parameters; and local-number is written as local-number-digits, then parameters, then context, then more parameters. Because context appears there unconditionally, and context is defined as the string ";phone-context=" followed by a descriptor, a local number without one simply has no derivation.

There are two fixes and the spec prefers one of them. Section 5.1 says all phone numbers must use the global form unless they cannot be represented as such — so the first answer is to write the number as +, country code, and the rest. Only when a number genuinely cannot be expressed globally, which is the case for extensions inside a private branch exchange, short codes, and emergency numbers, do you fall back to the local form and attach a context: either a domain name that identifies the numbering plan, or a global number prefix like +1-914.

It is worth being clear about what breaks and what does not. A phone will usually dial tel:555-1234 anyway, because a dialler is not a validator and it does the obvious thing. The cost is that the URI carries no information about which numbering plan the digits belong to, so anything that has to interpret it rather than dial it — a directory, a CRM, a click-to-call gateway, anything comparing two records — is guessing. The grammar exists precisely to remove that guess.

The comparison rules, which strings get wrong

RFC 3966 section 4 defines when two tel: URIs are equivalent, and it is a real algorithm rather than a string match. Both must be the same form. The digits must be equal after removing all visual separators — the hyphen, full stop and brackets are part of the grammar and exist to be readable, so tel:+1-555-0100 and tel:+15550100 are the same number. The phone-context is compared as a host name when it is a domain and digit by digit when it is a number, which means EXAMPLE.COM. and example.com match while the numeric case is compared with separators stripped. Parameters are compared by name regardless of the order they appear in. And the whole comparison is case-insensitive.

One rule surprises people: if a parameter appears in only one of the two URIs, they are not equal. So tel:+15550100 and tel:+15550100;ext=1 are different numbers, which is right — an extension identifies a different endpoint — but it means you cannot strip parameters you do not understand and compare what is left.

There is also a normative ordering rule almost nothing follows. The extension or ISDN subaddress must come first, then phone-context, then every other parameter in alphabetical order. The spec gives its reason in the same paragraph: it is so that a tel: URI can be compared character by character, which is how SIP compares them. The canonical form this page prints applies that order.

Honest limitations

This checks the URI grammar and nothing else. It has no idea whether a number exists, whether the country code is real, or how many digits that country's numbering plan uses — that is a different job, done by dedicated phone number libraries with a dataset behind them, and it is deliberately not attempted here. A URI can be perfectly conforming and still be a number nobody answers.

It also cannot tell you whether a local number's context is the right one, only that it is a syntactically valid domain or global prefix. And the equality answer is RFC 3966's, which is about URIs: two different URIs can reach the same telephone in the real world through routing that no comparison of text could know about.

One thing worth knowing about the platform: none of this comes for free from the browser. Because tel is not one of the URL Standard's special schemes, new URL hands back the entire subscriber part as an opaque path, validates none of it — it accepts tel:555-1234 without complaint — and comparing two URL objects by href reports tel:+1-555-0100 and tel:+15550100 as different. That is not a fault; a generic URI parser is answering a generic question. It does mean every claim on this page has to be computed rather than borrowed.

Why is it free?

It is a grammar and a five-rule comparison, and your browser runs both as you type. No server is involved, so there is nothing to meter and no account to create.

Nothing is uploaded. The numbers you paste stay in this tab.