How to Read a Passport MRZ Line by Line (Position Map)
A complete map of all 88 MRZ positions on a passport: what every character of both lines contains, how names are encoded, why the dates carry no century, and how to decode one by hand.
A passport's MRZ isn't free text — it's a fixed-width format where every position is defined by the ICAO 9303 standard. Once you know what sits where, you can decode a passport by hand, with no software at all.
This is the complete map of those 88 positions. It's the reference worth keeping open when you're debugging an integration and need to know why field 7 came back empty.
The TD3 format
Passports use TD3: two lines of exactly 44 characters each, printed at the foot of the data page. The alphabet is restricted to A-Z, 0-9 and < (the filler character). No lowercase, no accents, no spaces.
We'll work from this real, valid example:
P<MEXGOMEZ<VELAZQUEZ<<MARGARITA<<<<<<<<<<<<<
G123456786MEX8007050F3307054<<<<<<<<<<<<<<08
Line 1: document, country and name
| Positions | Contents | In the example |
|---|---|---|
| 1 | Document type — P for passport | P |
| 2 | Subtype, at the issuer's discretion; almost always filler | < |
| 3-5 | Issuing country, 3-letter code | MEX |
| 6-44 | Name field, 39 characters | GOMEZ<VELAZQUEZ<<MARGARITA<<<... |
How the name is encoded
The name field causes more integration bugs than anything else in the MRZ, because its structure isn't obvious:
- Surnames come first.
- A double
<<separates surnames from given names. - A single
<separates words within either block. - The remainder is padded with
<out to 39 characters.
So GOMEZ<VELAZQUEZ<<MARGARITA reads: surnames Gomez Velazquez, given name Margarita.
Two practical consequences:
Accents and non-English letters disappear. ICAO 9303 permits only A-Z, so transliteration is mandatory: Velázquez → VELAZQUEZ, Müller → MUELLER, Ø → OE. If you compare an MRZ name against your database character by character, every name with a diacritic will fail. Normalize both sides first.
Long names get truncated. 39 characters run out fast with two surnames and two given names. When it doesn't fit, the issuer truncates — and the truncated name is the official MRZ data, not a misread. This is one reason to read the visual inspection zone (VIZ) as well, where the full name appears.
Line 2: the data that matters
| Positions | Contents | In the example |
|---|---|---|
| 1-9 | Passport number | G12345678 |
| 10 | Passport number check digit | 6 |
| 11-13 | Nationality, 3-letter code | MEX |
| 14-19 | Date of birth, YYMMDD | 800705 |
| 20 | Date of birth check digit | 0 |
| 21 | Sex — M, F, X or < | F |
| 22-27 | Date of expiry, YYMMDD | 330705 |
| 28 | Expiry check digit | 4 |
| 29-42 | Personal number, 14 characters | <<<<<<<<<<<<<< |
| 43 | Personal number check digit | 0 |
| 44 | Composite check digit over all of the above | 8 |
Decoded: passport G12345678 issued by Mexico, holder born 5 July 1980, sex F, valid until 5 July 2033.
The dates carry no century
YYMMDD is six digits: 800705 is 5 July — but of 1980 or 2080? The MRZ doesn't say. The working convention:
- Expiry: always in the future, so always
20xx. - Date of birth: if the two digits exceed the current year's, it's
19xx; otherwise20xx.
The heuristic fails in exactly one realistic case: people over 100. If your system serves the very elderly, resolve the century against the expiry date rather than assuming it.
The personal number is a free field
Positions 29-42 are the most misread part of the MRZ. Each country decides what goes there, and many put nothing at all — hence the fourteen < in the example. Never assume that field carries a national identifier.
One hard limit worth knowing: the field is 14 characters, which is shorter than a good many national ID numbers. Whatever your source country puts on the data page, don't count on finding it here. A serious extraction reads the visual zone too, not just the two lines at the foot.
The < padding is not optional
A common mistake when building test MRZs: trimming the trailing <. A 41-character line is not a valid MRZ, and any standards-respecting validator will reject it before looking at the contents. Both lines are exactly 44 characters, always.
Reading goes the other way: < becomes a space or is discarded depending on the field. Inside a name, a single < is a word separator; at the end of a field, it's just padding.
The four digits that verify everything
You'll have noticed four check digits on line 2. They're what makes the MRZ the most trustworthy field on any identity document: they let you detect a misread before you store it, using arithmetic alone, with no external lookup.
The algorithm is public and fits in ten lines of code. We work through it completely, with the arithmetic on this same example, in ICAO 9303 check digits: how they're calculated.
Try it on a real MRZ
You can paste any MRZ into our free MRZ validator: it decodes the fields, recomputes all four check digits and points at exactly the one that doesn't add up. No account needed, and it runs the same code as our extraction engine — so what you see there is literally what we apply in production.
If you'd rather have an API return the fields already structured and verified from a photo, the free demo processes a passport with no signup, and the documentation shows full integration in JavaScript, Python and PHP.
Need to extract passport data automatically?
Try our API with 20 free extractions. Integrate in minutes, get results in seconds.
Start for free