Skip to content

Documents · · 3 min read

MRZ check digits, explained

How the 7-3-1 algorithm in ICAO Doc 9303 works, worked through on the specimen passport, and what it can and cannot prove.

The two or three lines of <-filled text at the bottom of a passport or ID card are the machine-readable zone (MRZ), defined by ICAO Doc 9303. They repeat the key fields of the document in a fixed layout and a restricted alphabet, and protect the important ones with check digits. Recomputing those digits is the first thing a document check should do.

The layouts

FormatLines × charactersUsed on
TD13 × 30ID cards, residence permits
TD22 × 36Older ID cards, some permits
TD32 × 44Passports
MRV-A2 × 44Visas, full-page
MRV-B2 × 36Visas, smaller

KYCVerify's parser supports all five, plus the French national ID card (2 × 36, IDFRA), which predates the TD formats and has no expiry date in its MRZ.

The algorithm

  1. Give every character a value: digits are themselves, A-Z are 10 to 35, and the filler < is 0.
  2. Multiply each value by a repeating weight of 7, 3, 1, 7, 3, 1, … from the left.
  3. Add the products and take the remainder modulo 10. That is the check digit.

Worked example

ICAO's specimen passport, issued by the fictional state of Utopia (UTO), has this second line:

MRZ
L898902C36UTO7408122F1204159ZE184226B<<<<<10

P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<

L898902C36UTO7408122F1204159ZE184226B<<<<<10

1-9 Document number
L898902C3
10 Its check digit
6
14-19 · 20 Birth date · check
740812 · 2
22-27 · 28 Expiry · check
120415 · 9
11-13 Nationality
UTO
21 Sex
F
29-42 · 43 Optional · check
ZE184226B · 1
44 Composite check
0
The TD3 specimen. Shaded: the fields each check digit protects. Solid: the five check digits.

The document number is L898902C3, followed by its check digit 6:

CharacterL898902C3
Value21898902123
Weight731731731
Product1472495627014363

The products sum to 316, and 316 mod 10 = 6, which matches. The date of birth 740812 gives 49 + 12 + 0 + 56 + 3 + 2 = 122, check digit 2. The expiry 120415 gives 7 + 6 + 0 + 28 + 3 + 5 = 49, check digit 9. Both match the line.

The composite digit

The last character, 0, is a check digit over the document number, the date of birth, the expiry and the optional data including their own check digits. It catches an edit that was carefully paired with a recomputed field digit, and a swap of whole fields.

OCR and the alphabet

Cameras and OCR confuse 0 and O, 1 and I, 5 and S, 8 and B. Because each MRZ position has a known alphabet (a date is digits, a country code is letters), many of these can be corrected safely. KYCVerify corrects only in typed positions, and reports every correction as (line, column, from, to) so a reviewer can tell a clean read from a repaired one.

Document numbers mix letters and digits, so the type of a position is not known. When a confusion there makes the check digit fail, the parser tries the other readings of the confusable characters that are out of type with their neighbours, and applies one only if it is the single fewest-change reading that makes both the field's and the composite check digit verify.

Long document numbers

TD1 and TD2 have nine positions for the document number. When a number is longer, the ninth position holds <, the remainder continues in the optional-data field, and the check digit after it covers the full number. The parser handles this continuation.

What check digits prove

  • They prove the MRZ is internally consistent: it was read correctly and was not edited carelessly.
  • They do not prove the document is genuine. Anyone can compute a valid check digit; the algorithm is public.
  • That is why a document check also compares the MRZ with the declared type and country, enforces expiry, gates on image quality, and why liveness and face match tie the document to a present person.

Try it with POST /v1/checks/mrz and the two specimen lines: every check digit verifies, and the document expired in 2012.

See it working on your own data.

Every guide describes code you can run in the sandbox today.