mrkeyoor.com_
Sun 20 Sept 11:45 UTC
npmUtilsupdated 20 Sept 2026

libphonenumber-js review

libphonenumber-js 1.13.11 converts national or international phone input into a `PhoneNumber` carrying an E.164 value, country calling code, national number, optional extension, formatters, and possibility or validity checks. It also formats partial input through `AsYouType` and finds phone numbers in prose. The package deliberately omits emergency numbers, SMS short codes, alphabetic vanity numbers, geographic lookup, carrier lookup, and mobile-dialing formatting from Google's broader library. Its min, max, mobile, and core entry points trade numbering metadata against validation and type detection. Version 1.13.11 updates its source metadata to Google's 9.0.37 data, including phone-plan changes for 17 listed regions.

Verdict

libphonenumber-js 1.13.11 installed in 0.9 seconds with 0 audit findings, while our full browser import measured 190.2 KB minified and 44.4 KB gzipped. It earns that cost for international parsing and live formatting; choose the metadata entry deliberately and keep strict-validation data updated.

We installed it

Lab card: what happened when we installed libphonenumber-jsScreenshot of libphonenumber-js documentation
Install✓ · 0.9s6 packages on disk · 13 MB
ImportESM import works · require() works · ESM package with exports map
Browser44.4 KBgzipped (190.2 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does libphonenumber-js install cleanly?

Yes. In a fresh container with an empty cache, npm install libphonenumber-js finished in 0.9s, leaving 6 packages and 13 MB on disk. npm audit reported no known vulnerabilities.

How much does libphonenumber-js add to a browser bundle?

44.4 KB gzipped (190.2 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does libphonenumber-js work with both ESM and CommonJS?

Yes. Both import 'libphonenumber-js' and require('libphonenumber-js') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does libphonenumber-js include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

libphonenumber-js or google-libphonenumber: which should you use?

google-libphonenumber: Choose it when closer coverage of Google's larger JavaScript port is worth more code and metadata. libphonenumber-js 1.13.11 installed in 0.9 seconds with 0 audit findings, while our full browser import measured 190.2 KB minified and 44.4 KB gzipped.

When should you not use libphonenumber-js?

A trusted upstream already sends one enforced E.164 format. Re-parsing international numbering plans adds little in that pipeline.

API stability5/5The package remains on major version 1, and the current README still centers `parsePhoneNumber`, `PhoneNumber`, formatting methods, possibility and validity checks, `AsYouType`, text search, and metadata-specific subpaths. Releases such as 1.13.11 replace numbering data without asking application call sites to change. Legacy functions are documented as legacy instead of disappearing without a migration trail.
Docs4/5The README gives concrete input and output examples for parsing, E.164 formatting, national display, extensions, strict extraction, errors, validation, number type, partial input, text search, non-geographic plans, and custom metadata. Its comparison with Google's implementation names missing features directly. The document is very long, and the min versus max consequences are repeated across sections, which makes a single deployment decision slower than it should be.
Maintenance4/5npm published version 1.13.11 on August 14, 2026 with Google's metadata 9.0.37, following several metadata releases in July. The GitHub mirror is unarchived and showed 2,991 stars, 38 open issues and pull requests, and a June 18 push. Active development and issue handling live primarily on GitLab, where the project recorded activity on August 14, so GitHub timestamps alone understate current maintenance.
Ecosystem5/5npm recorded 25,079,398 downloads in the latest completed week. Version 1.13.11 has 0 declared runtime dependencies or peers, includes TypeScript declarations, and exports both ESM and CommonJS targets for its min, max, mobile, and core variants. React input components and server normalization code can share its E.164 and `PhoneNumber` conventions, though careless mixed metadata imports can repeat a large payload.

Use it if

  • Users enter national phone numbers from several countries and the application stores one E.164 representation.
  • An input needs country-aware formatting after each keystroke through `AsYouType`.
  • Phone numbers must be located inside messages with their start and end character positions.
  • The bundle can choose min, max, mobile, or custom metadata according to its validation and number-type needs.
Skip it if

Setup reality

We installed libphonenumber-js 1.13.11 in a fresh Node 22 Bookworm sandbox in 0.9 seconds. The run left 6 packages and 13 MB on disk, with 0 known vulnerabilities from npm audit. The package itself declares 0 direct dependencies and 0 peers and is 12,576 KB unpacked. It ships TypeScript types, uses an ESM package declaration with an exports map, and loaded successfully through both require() and ESM import.

There are no credentials or config files. The import path is the configuration. The bare package aliases /min, whose smaller metadata favors parsing, formatting, and length checks. /max carries digit patterns for stricter validation and type detection. /mobile keeps detailed mobile rules and can reject or fail to type non-mobile numbers. /core bundles no ready metadata; every relevant call needs your generated metadata argument. Avoid mixing entry points or multiple metadata JSON files in one client bundle.

A national string needs defaultCountry or defaultCallingCode. An input beginning with + supplies its own calling code, so defaultCountry: 'US' does not restrict the result to the United States. Compare phone.country after parsing when a product permits one country. Non-geographic plans intentionally leave country undefined; isNonGeographic() distinguishes that outcome from a failed parse. Use extract: false on form fields so surrounding prose is rejected.

Our full browser import measured 190.2 KB minified and 44.4 KB gzipped. isPossible() checks numbering-plan length; isValid() also depends on digit patterns and the chosen metadata set. Version 1.13.11 embeds metadata 9.0.37, so strict checks age with the deployed package. AsYouType accumulates characters across calls. Recreate it when a controlled component passes the complete input value each time rather than only the new character.

Patterns

Interpret a national number parse-national-input

import parsePhoneNumber from 'libphonenumber-js';

const phone = parsePhoneNumber('020 7946 0018', 'GB');
if (!phone) throw new Error('cannot parse phone');
console.log(phone.number); // +442079460018

National input has no calling code, so version 1.13.11 needs a default country or default calling code to interpret it.

Normalize a possible number store-e164-number

function toE164(input, country) {
  const phone = parsePhoneNumber(input, {
    defaultCountry: country,
    extract: false,
  });
  return phone?.isPossible() ? phone.number : undefined;
}

`phone.number` is the E.164 form. `extract: false` refuses labels or prose surrounding the field value.

Catch a specific parse reason explain-parse-failure

import { parsePhoneNumberWithError, ParseError } from 'libphonenumber-js';

try {
  return parsePhoneNumberWithError(value, { defaultCountry: 'US', extract: false });
} catch (error) {
  if (error instanceof ParseError) return { error: error.message };
  throw error;
}

ParseError messages include `NOT_A_NUMBER`, `INVALID_COUNTRY`, `TOO_SHORT`, and `TOO_LONG` in the documented API.

Use a possibility check check-number-length

import { isPossiblePhoneNumber } from 'libphonenumber-js';

const possible = isPossiblePhoneNumber('(213) 373-4253', 'US');

isPossiblePhoneNumber checks the permitted length for the plan and depends less on newly assigned digit prefixes than strict validation.

Validate with max metadata apply-strict-validation

import { isValidPhoneNumber } from 'libphonenumber-js/max';

const valid = isValidPhoneNumber('+1 213 373 4253');

The max entry includes the detailed digit patterns required for strict `isValidPhoneNumber()` checks across countries.

Create labels and a tel URI format-phone-number

const phone = parsePhoneNumber('+12133734253');
if (phone) {
  console.log(phone.formatInternational());
  console.log(phone.formatNational());
  console.log(phone.getURI());
}

For this E.164 input, formatting follows the detected numbering plan and `getURI()` produces the telephone link value.

Format the current field value format-controlled-input

import { AsYouType } from 'libphonenumber-js';

function displayPhone(value, country) {
  return new AsYouType(country).input(value);
}

An AsYouType instance appends each call to prior state. Recreate it when `value` is the entire controlled field on every render.

Read a number type detect-phone-type

import parsePhoneNumber from 'libphonenumber-js/max';

const phone = parsePhoneNumber(value, 'US');
const type = phone?.getType();
if (type === 'MOBILE') sendSms(phone.number);

Use max or mobile metadata for type patterns. Some plans return `FIXED_LINE_OR_MOBILE` because digits do not distinguish the service.

Reject another country's international number enforce-selected-country

const phone = parsePhoneNumber(value, {
  defaultCountry: selectedCountry,
  extract: false,
});
const allowed = Boolean(phone && phone.country === selectedCountry && phone.isPossible());

defaultCountry interprets national input; a leading plus sign overrides it, so the country comparison enforces the product rule.

Recognize a global service number handle-non-geographic-plan

const phone = parsePhoneNumber(value);
if (phone?.isNonGeographic()) {
  console.log(phone.country); // undefined
  console.log(phone.countryCallingCode);
}

Non-geographic numbering plans have no ISO country, and version 1.13.11 leaves `country` undefined by design.

Locate phone spans in text find-numbers-in-prose

import { findPhoneNumbersInText } from 'libphonenumber-js';

for (const hit of findPhoneNumbersInText(message, 'US')) {
  console.log(hit.number.number, hit.startsAt, hit.endsAt);
}

Each match carries character offsets plus a parsed PhoneNumber, which is enough to build linked text without reparsing.

Use a country-trimmed metadata file call-core-with-metadata

import parsePhoneNumber from 'libphonenumber-js/core';
import metadata from './phone-metadata.json' with { type: 'json' };

const phone = parsePhoneNumber(value, 'US', metadata);

Core functions do not include default metadata; pass the generated data as the final argument to every call that needs it.

Alternatives

PackageRegistryPick it when
google-libphonenumbernpmChoose it when closer coverage of Google's larger JavaScript port is worth more code and metadata.
awesome-phonenumbernpmChoose it for a wrapper API built on the Google phone-number implementation.
libphonenumbernpmChoose it only to support an existing application already coupled to that older npm package.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.