npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

mrz-fast

v1.0.7

Published

Zero-dependency TypeScript library for parsing, validating, and generating passport MRZ codes (TD3 / ICAO 9303) with built-in error correction

Readme

MRZ Fast

A high-performance, zero-dependency TypeScript library for parsing and generating passport MRZ codes (TD3 format).

Supports the ICAO 9303 TD3 specification - the standard machine-readable zone format used in international passports.

MRZ Format Explained

Features

  • Zero Dependencies: Pure TypeScript, no external packages required
  • Passport-Only: Focused exclusively on TD3 passport format (ICAO 9303)
  • Fast: >200,000 parses/second with optimized algorithms
  • Validation: Full check digit validation and field-level error reporting
  • Error Correction: Built-in OCR/AI error correction for common mistakes (O→0, I→1, S→5, etc.)
  • Parse & Create: Both parse MRZ strings and generate valid MRZ from data
  • Type-safe: Full TypeScript support with strict types

Installation

npm install mrz-fast

Quick Start

Parsing MRZ

import { parseMRZ } from 'mrz-fast';

const mrz: [string, string] = [
  'P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<',
  'L898902C36UTO7408122F1204159ZE184226B<<<<<10'
];

const result = parseMRZ(mrz);
{
  "valid": true,
  "fields": {
    "firstName": "ANNA MARIA",
    "lastName": "ERIKSSON",
    "documentNumber": "L898902C3",
    "nationality": "UTO",
    "birthDate": "740812",
    "sex": "female"
  }
}

Creating MRZ

import { createMRZ } from 'mrz-fast';

const data = {
  documentCode: 'P',
  issuingState: 'UTO',
  lastName: 'ERIKSSON',
  firstName: 'ANNA MARIA',
  documentNumber: 'L898902C3',
  nationality: 'UTO',
  birthDate: { year: 1974, month: 8, day: 12 },
  sex: 'female',
  expirationDate: { year: 2012, month: 4, day: 15 },
  personalNumber: 'ZE184226B'  // optional
};

const [line1, line2] = createMRZ(data);
[
  "P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<",
  "L898902C36UTO7408122F1204159ZE184226B<<<<<10"
]

Error Correction for OCR/AI

One of the most powerful features is automatic error correction, especially useful for:

  • OCR systems that may confuse similar-looking characters
  • AI models that generate MRZ codes with common mistakes
  • Damaged or unclear scans of physical documents

MRZ Error Correction Example

import { parseMRZ } from 'mrz-fast';

// MRZ with common OCR/AI errors: O→0, I→1 confusion
const messyMrz: [string, string] = [
  'P<UTOERIKSSON<<ANNA<MARIA',  // Too short (will be padded)
  'L8989O2C36UTO74O8I22FI2O4I59ZEI84226B<<<<<IO'  // Multiple O/0 and I/1 errors
];

const result = parseMRZ(messyMrz, { errorCorrection: true });
{
  "valid": true,
  "corrected": true,
  "fields": {
    "documentNumber": "L898902C3"
  },
  "correctionMetrics": {
    "attemptNumber": 42,
    "totalAttempts": 42,
    "totalCombinations": 16384,
    "correctionApplied": true
  }
}

What error correction handles:

  • Character confusion: O↔0, I↔1↔l, S↔5, B↔8, Z↔2, G↔6
  • Length issues: Automatically pads short lines or truncates long ones
  • Leading padding: Removes invalid leading < characters
  • Smart search: Tests up to 2 million combinations, trying most likely fixes first

This makes the library extremely robust for real-world applications where input quality varies.

API Reference

parseMRZ(mrz, options?)

Parses a TD3 passport MRZ.

Parameters:

  • mrz: [string, string] - Tuple of 2 MRZ lines
  • options: Optional settings
    • errorCorrection?: boolean - Enable OCR/AI error correction (default: false)

Returns: ParseResult with parsed fields and validation status

createMRZ(data)

Creates a valid TD3 passport MRZ.

Parameters:

  • data: Object with required fields:
    • documentCode: string (e.g., 'P', 'PA')
    • issuingState: string (3-letter country code)
    • lastName: string
    • firstName: string
    • documentNumber: string
    • nationality: string (3-letter country code)
    • birthDate: { year: number, month: number, day: number }
    • sex: 'male' | 'female' | 'unspecified'
    • expirationDate: { year: number, month: number, day: number }
    • personalNumber?: string (optional)

Returns: [string, string] - Tuple of two 44-character MRZ lines with correct check digits

Available Fields

interface ParseResult {
  format: 'TD3';
  valid: boolean;           // Overall validation status
  corrected: boolean;       // Whether corrections were applied
  fields: {
    documentCode: string | null;
    issuingState: string | null;
    lastName: string | null;
    firstName: string | null;
  documentNumber: string | null;
    nationality: string | null;
    birthDate: string | null;        // YYMMDD
    sex: string | null;              // 'male', 'female', or 'unspecified'
    expirationDate: string | null;   // YYMMDD
    personalNumber: string | null;
    // ... and check digits
  };
  lines: {
    line1: string;  // Actual MRZ line 1 (corrected if errorCorrection was used)
    line2: string;  // Actual MRZ line 2 (corrected if errorCorrection was used)
  };
  details: Details[];  // Per-field validation details
  correctionMetrics?: {  // Only when errorCorrection: true
    attemptNumber: number;
    totalAttempts: number;
    totalCombinations: number;
    correctionApplied: boolean;
  };
}

Performance

  • Clean parsing: ~0.005ms per parse (>200,000 ops/sec)
  • With error correction: ~0.006-0.009ms per parse (>100,000 ops/sec)
  • Batch processing: 156,760+ MRZs/second

Optimizations:

  • Precomputed lookup tables
  • Smart ordering (tries likely fixes first)
  • Fast check digit validation
  • Minimal memory allocations

TD3 Passport Format (ICAO 9303)

This library only supports TD3 format - the two-line machine-readable zone used in international passports according to the ICAO 9303 specification.

TD3 format consists of 2 lines of 44 characters each:

Line 1:

  • Document code (2 chars): P, PA, PO, PT
  • Issuing state (3 chars): Country code
  • Names (39 chars): LASTNAME<<FIRSTNAME

Line 2:

  • Document number (9 chars) + check digit
  • Nationality (3 chars)
  • Birth date (6 chars, YYMMDD) + check digit
  • Sex (1 char): M, F, or <
  • Expiration date (6 chars, YYMMDD) + check digit
  • Personal number (14 chars, optional) + check digit
  • Composite check digit

Check digits use ICAO 9303 algorithm with weights [7, 3, 1].

Development

npm install      # Install dependencies
npm run build    # Build TypeScript
npm test         # Run tests

License

MIT

Credits

Inspired by the excellent @mrz library by Zakodium.