Our phone rule misses German numbers on purpose
We tested nine phone number formats against the rule set. It caught five.
That is not a bug report. It is a decision, and this article is the reasoning, including the case where the decision costs a real user something.
The results
| Format | Example | Result |
|---|---|---|
| US, hyphens | 415-555-2671 | caught |
| US, parentheses | (415) 555-2671 | caught |
| US, dots | 415.555.2671 | caught |
| International, US | +1 415-555-2671 | caught |
| International, UK | +44 20 7946 0958 | caught |
| International, Germany | +49 30 12345678 | missed |
| Bare 10 digits | 4155552671 | missed |
| Bare 11 digits | 14155552671 | missed |
| International, no spaces | +14155552671 | missed |
Why the bare digit runs are missed on purpose
4155552671 is ten digits. So is a Unix timestamp, an order ID, a row count, a product code, and a bank sort code with the dashes taken out. There is no property of that string that says "telephone".
A rule matching any ten-digit run would fire constantly in exactly the documents people paste: logs, exports, spreadsheets. We would be trading a rare miss for a constant nuisance.
To check that the strictness pays for itself, we ran six formats that must never be flagged:
| Input | Phone rule |
|---|---|
version 1.2.3 | no match |
2026-07-24 | no match |
100-200-300 | no match |
2026-07-24 14:23:45 | no match |
113-7782991-4406620 | no match |
127.0.0.1:8642 | no match (caught as an internal host, correctly) |
Six for six. A looser rule would have flagged the date and the order number at minimum.
The German number is a genuine cost
+49 30 12345678 is a real phone number in a real format, and we miss it. That deserves a straight explanation rather than a shrug.
The international pattern requires the country code to be followed by at least two separator-joined groups of digits. +44 20 7946 0958 has three groups after +44. German numbers are commonly written as area code plus one unbroken subscriber number, giving only one group after +49, and the rule does not fire.
We could require only one group. Then +1 4155552671 matches, which is fine, but so does any plus sign followed by digits with a space in the middle, and that shape appears in coordinates, measurements, and diffs.
The honest position: if you handle German, French, or other numbers written as one long block, this rule will not protect you, and you should treat phone numbers as something to check by eye. We would rather tell you that than let you believe in coverage that is not there.
Which way to err
The project's stated principle is that the user keeps control, and that shapes the trade. A missed detection is visible to you: your own phone number is in your own text and you can see it. A false positive is invisible in a different way; it erodes your attention until you stop reading the highlights at all.
So the rules are strict, the misses are documented rather than hidden, and every rule is a switch you can turn off if our judgement does not match your situation.
If you want the loose behaviour, the pattern lives in /js/scrub/rules.js, served in plain text with this page. You can read exactly what it does before deciding whether to trust it.