Free MRZ generator

This free MRZ calculator generates ICAO 9303-compliant Machine Readable Zone strings with valid check digits for passports, ID cards and visas, and previews them as a mock document image — entirely in your browser. Test image dataset mode builds a seeded set of synthetic documents with blur, motion, rotation, perspective, glare, noise and JPEG degradations, keeps the ground-truth fields for every image, and exports the whole thing as a ZIP your MRZ reader can be scored against.

For testing only. Every value on this page is randomly generated sample data. The output is not a valid travel document, is not machine verifiable against any government registry, and must not be used to impersonate anyone. Use it to test an MRZ reader, not as identification.

Document Configuration

Generated MRZ Code

Document Preview

What this MRZ generator writes

It builds the machine-readable zone of an ICAO 9303 travel document — two or three fixed-width lines of OCR-B text — from the fields you type, and computes every check digit the layout calls for, including the composite one. The result is drawn on a mock data page at the character pitch the standard specifies. The second mode turns the same writer into a seeded image set with ground truth.

The five layouts, and why the line length is not a detail

An MRZ is not free-form text. Every layout fixes how many lines there are, how many characters each line holds, and which field sits in which character position — so a string written for one layout cannot be read as another, even when the fields are identical. This generator covers the five ICAO 9303 layouts:

Check digits in the last column are the ones this page computes; "composite" is the final digit of the lower line, which covers several fields at once.
Layout Printed on Lines × characters Name field Check digits
TD3 Passport booklet (ID-3) 2 × 44 Line 1, 39 characters Document number, birth date, expiry date, optional data, composite
TD2 ID card (ID-2) 2 × 36 Line 1, 31 characters Document number, birth date, expiry date, composite
TD1 ID card (ID-1, credit-card size) 3 × 30 Line 3, 30 characters Document number, birth date, expiry date, composite
MRV-A Visa, full-page sticker 2 × 44 Line 1, 39 characters Document number, birth date, expiry date — no composite
MRV-B Visa, smaller sticker 2 × 36 Line 1, 31 characters Document number, birth date, expiry date — no composite

Values are padded to their field with the filler character <, and the separator between the primary and secondary identifier is two of them — NELSON<<CALLIE. A value longer than its field is cut, not wrapped: TD1 gives the name 30 characters, so a long surname loses its tail. One code is not ISO 3166: ICAO prints Germany as D, and this generator normalizes DEU to D so the field reads D<<, as a German document does.

Worked example: one passport, digit by digit

The record in the screenshot is a synthetic passport: NELSON, Callie, document 422016774, born 17 October 1988, expires 23 December 2027, optional data 572615374<5859. Written as TD3 it comes out as two 44-character lines:

P<USANELSON<<CALLIE<<<<<<<<<<<<<<<<<<<<<<<<<<<
4220167749USA8810171F2712239572615374<585990

The lower line is a fixed set of slices, and reading it means reading those slices rather than splitting on anything visible:

TD3 lower line. The six digits of a date are YYMMDD, so 881017 is 17 October 1988 — the century is not in the string.
Positions Field In this example
1–9Document number422016774
10Check digit over positions 1–99
11–13NationalityUSA
14–19Date of birth881017
20Check digit over positions 14–191
21SexF
22–27Date of expiry271223
28Check digit over positions 22–279
29–42Optional data572615374<5859
43Check digit over positions 29–429
44Composite check digit0

Every check digit uses the same arithmetic. Each character is given a value — 0–9 keep their value, A is 10 through Z is 35, and the filler is 0 — then multiplied by the repeating weights 7, 3, 1 and the total taken modulo 10. For the document number:

The weights restart at 7 for every field the digit covers; they are not carried over from the previous field.
Character 4220 1677 4
Value422016774
Weight731731731
Product286203649214

The products add to 119, and 119 modulo 10 is 9 — the character at position 10. The composite digit at the end is the same sum over a longer input: the document number with its check digit, the birth date with its check digit, the expiry date with its check digit and the optional data with its check digit, 39 characters in all, which gives 0. Nationality and sex are not in that input, which is why a wrong nationality can pass a composite check.

MRZ generator document preview: a synthetic US passport data page with a drawn portrait, holder signature, security rosette and the two 44-character MRZ lines P<USANELSON<<CALLIE… and 4220167749USA8810171F2712239572615374<585990
The same record rendered by this page in Chrome on 4 November 2026. The MRZ uses OCR-B at the pitch the standard specifies; the portrait is drawn on the canvas from the record's own fields — it is not a photograph of anyone, and the same record always draws the same face.

What a valid check digit does not prove

It proves the characters were copied without a transcription error. It does not prove the document is genuine: the algorithm is public, so a forgery carries correct digits too, and a reader that reports "MRZ check digits valid" has said nothing about security features, the chip, or whether the issuing state ever printed that number. That distinction matters when a demo like this one offers to produce a valid string from any input — the string is arithmetic, not authority.

Supported and not supported

Capability This tool
Layouts TD1, TD2, TD3, MRV-A and MRV-B, with the check digits each one defines. Not a template for any specific country's document — no national field layout, no document-specific optional-data convention.
Character set A–Z, 0–9 and the filler <. Input is uppercased and spaces become fillers; accented letters are not transliterated, so MÜLLER stays invalid instead of becoming MUELLER.
Document preview A mock data page on an HTML5 canvas — 900 × 640 for a passport, 900 × 580 for an ID card or visa — with the MRZ in OCR-B, a drawn portrait, a signature and a security rosette. It is a stand-in for a document, not a reproduction of one.
Test image dataset Up to 100 images from one seed, mixed or single document type, twelve degradations with per-image ranges, ground truth for every image, ZIP plus annotations.json in the mrz-benchmark/1.0 schema.
Scoring a reader Not here — the ZIP is scored in the MRZ scanner benchmark, which reports accuracy per field and per image.
Reading an MRZ Not offered. This page writes strings and images; it does not recognise anything, and it does not check that a string it wrote would be read back correctly.
Chip, barcode, MRZ on a real template Not offered. The preview draws a generic data page; there is no RFID data group, no PDF417 or QR symbol, and no document-template library.
Privacy and network No SDK and no license key: the page is plain JavaScript. Nothing you type is uploaded, and there is no server to upload it to. The page fetches its own CSS, fonts and demo analytics only.

Use the tool, or build it into your app

Use the free hosted tool

Open the page and type. There is no account, no key and no installation, because the generator needs no SDK at all.

Integrate it in your application

The generator is arithmetic and a canvas — it carries no license of its own. The reader you point at its output does.

Limits worth knowing before you rely on it

Is a generated document number a real one?
No. Every value is drawn from fixed lists and a seeded random number generator, and no register anywhere knows the number. A correct check digit makes the string well-formed, not genuine — see the note above.
Why was my long surname cut in half?
Because the field is a fixed width and the generator pads or truncates to fit. ICAO wants the truncation done by removing whole name components and ending on a letter, so that a reader can tell a name was shortened; this page does not implement that rule, so a truncated name looks complete. Type a shorter name if you are testing truncation detection.
Why does an accented name produce a string that no reader accepts?
Because nothing is transliterated. The standard allows A–Z, 0–9 and the filler only, and Ü is none of those — it is written through as-is. Type the ASCII form (MUELLER) for a string that will read back.
Why is the date written 881017 rather than 1988-10-17?
That is the encoding: six digits, YYMMDD, no century. Which century a reader assumes is its own convention, which is why the dataset benchmark compares dates inside the century the MRZ encodes instead of inventing one.
Is the accuracy measured on the dataset a production number?
No. The images are synthesised, not photographed: the degradations model blur, glare, rotation, perspective, noise and JPEG loss, but a real camera adds sensor behaviour, print texture and operator error that this set does not contain. What it measures reliably is which conditions a reader survives, and where it starts losing characters.
Whose face is in the preview?
Nobody's. The portrait is drawn from primitives on the canvas — skin, hair, eyes and shoulders composited per record — so there is no photograph and no likeness of a real person anywhere in the page or in the exported images.