---
title: "Stop Using Regex! Build World-Class International Phone Number Validation with Google libphonenumber 套件"
description: "Struggling with the complex rules and regular expressions (Regex) for international phone number validation? This article shows how to use Google's libphonenumber library and easily implement it with React-phone-number-input (frontend) and libphonenumber-csharp (backend). Say goodbye to maintenance nightmares and provide an excellent user experience."
canonical_url: "https://blog.markkulab.net/en/post/google-libphonenumber-international-phone-validation"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2026-06-07 20:02:25 +0800"
category: "AI"
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# Stop Using Regex! Build World-Class International Phone Number Validation with Google libphonenumber 套件

## Introduction: The Nightmare of Handling International Phone Numbers

Any engineer who has worked on a product for international markets knows the feeling: phone number validation seems simple, but it's actually a bottomless pit. Countries have varying number lengths and convoluted formatting rules. Some countries even allow variable lengths (Indonesia is 10–13 digits). Just listing out the rules is enough to make your head spin. The traditional approach is to brute-force it with a pile of regular expressions (Regex), but as the number of supported countries grows, the Regex quickly balloons into a monster nobody dares to touch. This post shares our team's solution—standing directly on Google's shoulders and using the `libphonenumber` ecosystem to solve it for both frontend and backend in one go.

## Why Maintaining Your Own Regex is a Road to Ruin

### Extremely High Maintenance Costs

If you lay out the phone number specifications for various countries, you'll find this is definitely not a "write once and forget" task. Japanese mobile numbers are 11 digits, while landlines are 10. Malaysian mobile numbers are 10–11 digits. Indonesia is even more extreme, where anything from 10 to 13 digits is valid. Stuffing all these rules into Regex not only causes the line count to explode, but if a country changes its rules, making a precise change in that mess of Regex is as difficult as defusing a bomb.

### Can't Keep Up with Global Changes

Global telecommunication regulations change more frequently than you might think. Between 2025–2026 alone, the UK updated its National Numbering Plan, Canada implemented Thousands-Block Pooling, and Spain blocked internationally spoofed domestic calls. If you rely on manually updating Regex for these changes, it's not only labor-intensive but also easy to miss updates, leading to validation failures in production—a user enters a perfectly valid number, but the system shows a red error message and blocks them.

### Inability to Handle Hidden Details

The most classic example is the "leading zero" problem. Many countries have a local dialing convention that starts with a `0` (e.g., `0912-345-678` in Taiwan, `090-1234-5678` in Japan), but when converted to international format, this `0` must be removed (`+886 912345678`, `+81 9012345678`). If you build the input field yourself, users are often confused about "whether or not to include the 0." As a result, the backend receives a bunch of incorrectly formatted data, and downstream systems (like SMS gateways and KYC verification) all fail as a result.

## The Industry Standard: Google's libphonenumber Ecosystem

### The Core: Google's Commitment

[`libphonenumber`](https://github.com/google/libphonenumber) is an open-source phone number handling library maintained by Google, covering the numbering rules for **218 countries/regions** worldwide. The latest version is 9.0.32 (released 2026-06-05). Google has a dedicated team that tracks changes to national numbering plans from the ITU and **updates the metadata every two weeks**. This means as long as you keep your package version updated, Google is essentially shouldering the burden of keeping up with global telecom rules for you.

### The Frontend Weapon: react-phone-number-input

In the React ecosystem, [`react-phone-number-input`](https://www.npmjs.com/package/react-phone-number-input) (v3.4.17) is currently the most popular international phone number input component, with over **2.05 million weekly downloads**. Under the hood, it uses [`libphonenumber-js`](https://github.com/catamphetamine/libphonenumber-js) (v1.13.6), a pure JavaScript rewrite of the original Google library with a bundle size of just **145 KB** (compared to the original's ~550 KB). It has native TypeScript support and is more than sufficient for the validation needs of most business applications.

> 💡 `libphonenumber-js` does not support emergency numbers, short codes, vanity numbers (like `1-800-GOT-MILK`), or number geocoding, but these are rarely needed in typical user registration scenarios.

### The Backend Guardian: libphonenumber-csharp

[`libphonenumber-csharp`](https://www.nuget.org/packages/libphonenumber-csharp/) (v9.0.32) is a direct port of the original Google library by the C# community, with over **92.3 million total downloads** on NuGet. It uses scheduled GitHub Actions to automatically sync updates from Google's upstream, with a delay of usually less than **1 day**. It supports .NET 8.0 and .NET Standard 2.0.

> ⚠️ The official documentation specifically warns: If you don't keep the package updated, `IsValidNumber` might return `false` for new number formats, causing you to mistakenly block legitimate users.

### Architecture Overview

By using packages from the same ecosystem on both the frontend and backend, we create a two-tiered validation architecture—the frontend is responsible for real-time UX feedback, and the backend is responsible for final data gatekeeping:

```
┌─────────────────────────────────────────────────────┐
│                    使用者瀏覽器                        │
│  ┌───────────────────────────────────────────────┐  │
│  │  react-phone-number-input (v3.4.17)           │  │
│  │  ├─ 國旗選擇 + 國碼自動帶入                      │  │
│  │  ├─ 隨打隨格式化                                │  │
│  │  ├─ 自動去零 (Leading Zero)                    │  │
│  │  └─ 底層：libphonenumber-js (v1.13.6, 145KB)  │  │
│  └───────────────────────────┬───────────────────┘  │
│                              │ E.164 格式            │
│                              │ (+886912345678)       │
└──────────────────────────────┼──────────────────────┘
                               ▼
┌──────────────────────────────┼──────────────────────┐
│                         API Server                   │
│  ┌───────────────────────────┴───────────────────┐  │
│  │  libphonenumber-csharp (v9.0.32)              │  │
│  │  ├─ IsValidNumber() 嚴格驗證                    │  │
│  │  ├─ 解析國碼 + 號碼類型 (手機/市話)               │  │
│  │  └─ 自動同步 Google 上游 (GitHub Actions)       │  │
│  └───────────────────────────┬───────────────────┘  │
│                              │                       │
│                              ▼                       │
│                    資料庫 (E.164 格式儲存)             │
└─────────────────────────────────────────────────────┘
```

## Practical Architecture: Frontend Experience and Backend Validation

### Frontend Implementation (React)

Using `react-phone-number-input` is very intuitive. A few lines of code can create an input field with country code selection, real-time formatting, and smart flag switching:

```tsx
import PhoneInput, { isValidPhoneNumber } from 'react-phone-number-input'
import 'react-phone-number-input/style.css'

function PhoneForm() {
  const [phone, setPhone] = useState<string | undefined>()

  const handleSubmit = () => {
    if (phone && isValidPhoneNumber(phone)) {
      // phone 已經是 E.164 格式，例如 "+886912345678"
      api.post('/register', { phone })
    }
  }

  return (
    <PhoneInput
      international
      defaultCountry="TW"
      countries={['TW', 'JP', 'US', 'MY', 'ID', 'SG', 'TH']}
      value={phone}
      onChange={setPhone}
      placeholder="輸入電話號碼"
    />
  )
}
```

The UX improvements from this code are:

- ✅ **As-you-type formatting**: Entering a Japanese number automatically formats it as `090 1234 5678`, which is clean and clear.
- ✅ **Smart paste detection**: When a user pastes `+62 812 3456 7890`, the country flag automatically switches to Indonesia 🇮🇩.
- ✅ **Automatic leading zero removal**: After selecting Taiwan, if a user enters `0912345678`, the component automatically converts it to `+886 912345678`.
- ✅ **Ability to restrict the country list**: Use the `countries` prop to display only the countries your business serves.

> 📊 Live Demo: [https://catamphetamine.github.io/react-phone-number-input/](https://catamphetamine.github.io/react-phone-number-input/)

### Backend Validation (C#)

Frontend validation is primarily for UX; **the backend is the final line of defense**. Use `libphonenumber-csharp` for strict validation:

```csharp
using PhoneNumbers;

public class PhoneValidator
{
    private static readonly PhoneNumberUtil PhoneUtil = PhoneNumberUtil.GetInstance();

    public static bool ValidatePhone(string phoneNumber)
    {
        try
        {
            // 解析號碼（第二個參數為預設國碼區域，傳 null 表示號碼必須包含 "+" 國碼）
            var number = PhoneUtil.Parse(phoneNumber, null);

            // 嚴格驗證：檢查號碼長度、格式是否符合該國規則
            if (!PhoneUtil.IsValidNumber(number))
                return false;

            // 取得號碼類型（手機、市話、VOIP 等）
            var numberType = PhoneUtil.GetNumberType(number);

            // 可依業務需求限制只接受手機號碼
            return numberType == PhoneNumberType.MOBILE
                || numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE;
        }
        catch (NumberParseException)
        {
            return false;
        }
    }
}
```

### Best Practice: Store Everything in E.164 Format

Regardless of the format received from the frontend, **always convert it to E.164 format** (`+國碼號碼`, e.g., `+886912345678`) before storing it in the database. The benefits are:

| Aspect | Advantages of E.164 |
|---|---|
| Format Consistency | Any number from anywhere in the world has the same format, eliminating confusion over "with/without leading zero." |
| Downstream Compatibility | Services like Twilio and AWS SNS all require E.164. |
| Query Convenience | When checking for uniqueness in the database, you don't have to worry about multiple representations of the same number. |
| Length Constraint | A maximum of 15 digits (including country code), making field design straightforward. |

## Business Considerations: Is It Free for Commercial Use?

| Package | License | Commercial Use | Closed Source | Viral (Copyleft) |
|---|---|---|---|---|
| `react-phone-number-input` | MIT | ✅ Fully permitted | ✅ No need to disclose source code | ❌ No |
| `libphonenumber-js` | MIT | ✅ Fully permitted | ✅ No need to disclose source code | ❌ No |
| `libphonenumber-csharp` | Apache 2.0 | ✅ Fully permitted | ✅ No need to disclose source code | ❌ No |

In short, both MIT and Apache 2.0 licenses are very friendly to commercial and closed-source projects. You can freely use, modify, and distribute the code, and even package it within paid software for sale, without any of the "forced open-sourcing" viral risks associated with licenses like GPL. You can confidently integrate them into production products without worrying about licensing issues.

## Conclusion: Say Goodbye to Maintenance Nightmares and Focus on Your Core Business

Let's review the core benefits of adopting the `libphonenumber` ecosystem:

- 🚀 **Maintenance cost approaches zero**: Google updates global telecom rules every two weeks; you just need to run `npm update` / `dotnet update`.
- 📊 **Significant improvement in data quality**: Real-time frontend formatting + strict backend validation prevents junk data from entering your database.
- ✅ **Professional user experience**: Country flag selection, as-you-type formatting, and smart paste detection make your forms look like they belong to a world-class product.

This isn't just a technical choice; it's a strategic decision. Offload the tedious, non-core tasks to Google and the open-source community, allowing your team to focus on the business logic that truly creates value. If your project still has a tangled mess of Regex for different countries, now is the perfect time to refactor.

## References

- [Google libphonenumber 套件 - GitHub Releases](https://github.com/google/libphonenumber/releases)
- [react-phone-number-input - npm](https://www.npmjs.com/package/react-phone-number-input)
- [libphonenumber-js - GitHub](https://github.com/catamphetamine/libphonenumber-js)
- [libphonenumber-csharp - NuGet](https://www.nuget.org/packages/libphonenumber-csharp/)
- [libphonenumber-csharp - GitHub](https://github.com/twcclegg/libphonenumber-csharp)
- [E.164 Phone Format Guide - Sent.dm](https://www.sent.dm/en/resources/sms-pricing/e164-phone-format)
- [Phone Number Validation Best Practices - Twilio](https://www.twilio.com/en-us/blog/best-practices-phone-number-validation-user-enrollment)

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/google-libphonenumber-international-phone-validation)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
