Skip to content

Extracting Data From a Driver's License Across Different State Formats

9 min read · updated August 11, 2026

There are more than sixty issuing jurisdictions in North America, each with its own card design, several current designs per jurisdiction, and a vertical variant for under-21 holders. Building a template per layout is a maintenance treadmill with no end. The way out is that the back of the card is standardised even though the front is not.

Why the front defeats a template

A template-matching extractor assumes that a field lives at a known position relative to a known anchor. On driver’s licences the assumption fails on four independent axes at once, and each of them multiplies against the others.

  • Jurisdiction. Every state, territory and province designs its own card. Field order, label wording and the presence of fields differ. Some print a middle name, some an initial, some nothing.
  • Design generation. Cards are valid for years, so several designs from one jurisdiction are simultaneously in circulation. A template built against the current design silently fails on a card issued four years ago and still valid.
  • Orientation. Many jurisdictions issue a portrait-oriented card to holders under 21, which is a different layout, not a rotation of the same one.
  • Compliance marking. A REAL ID compliant card carries a marking that a non-compliant one does not, and the marking’s presence changes the surrounding layout on some designs.

The labels are not stable enough to anchor on either. The same fact appears as “DOB”, “Date of Birth” and a language-neutral numeric code depending on the card. Extracting from the face with a general vision model and a field schema works better than templates, but it inherits every problem in vision hallucination and gives you nothing to check the answer against.

The back is standardised

AAMVA — the American Association of Motor Vehicle Administrators — publishes the DL/ID Card Design Standard, whose Annex D specifies a mandatory PDF417 barcode carrying the cardholder data in a defined encoding. Every jurisdiction that follows the standard encodes the same facts under the same three-character element identifiers, regardless of what the front of the card looks like. That barcode is the layout-agnostic schema, and it already exists.

The encoded stream begins with a header describing what follows: a compliance indicator, separator characters, the literal ANSI , a six-digit issuer identification number, the AAMVA version the card was encoded against, a jurisdiction version, and a count of subfiles. Each subfile is then declared by a designator giving its type — DL for a driver licence, ID for an identification card, a jurisdiction-specific type beginning Z — with its byte offset and length. Inside a subfile, each data element is a three-character identifier followed by its value, terminated by a line feed.

The single most important operational consequence: branch on the version. The standard has been revised repeatedly, most recently in 2020 and 2025, and the element set and header details differ between versions. Slicing the header at fixed offsets without reading the version number is the defect that makes a parser work on cards from one era and produce garbage on another. The authority for every offset is the DL/ID Card Design Standard published by AAMVA, and the versions you must support are decided by which cards are still valid, not by which version is current.

Reading a barcode that the cardholder has presented to you is ordinary document processing. Nothing on this page concerns producing, altering or evaluating the security features of a card; those are matters for the issuing authority, and a barcode read tells you what was encoded, not whether the card is genuine.

The element dictionary

The identifiers are three characters and mnemonic only by accident, so a parser needs the table. The commonly present ones:

DAQ  customer identifier (the licence or ID number)
DCS  family name                 DAC  first name
DAD  middle name(s)              DCU  name suffix
DBB  date of birth               DBA  document expiry date
DBD  document issue date         DBC  sex
DAU  height                      DAY  eye colour
DAG  street address 1            DAH  street address 2
DAI  city                        DAJ  jurisdiction code
DAK  postal code                 DCG  country
DCA  jurisdiction vehicle class  DCB  restriction codes
DCD  endorsement codes           DCF  document discriminator
DDE  family name truncation      DDF  first name truncation
DDG  middle name truncation

Two of these are more useful than they look. DCF, the document discriminator, uniquely identifies the physical card as distinct from the person — so a renewal produces a new discriminator against the same DAQ, which is exactly the distinction you need to tell “same person, new card” from “different person”.

And the truncation indicators are the field almost every parser ignores. Names longer than the encoded field are truncated, and DDE, DDF and DDG record whether each name component was truncated. A pipeline that compares the barcode name against a name on file will produce false mismatches on long names unless it reads those flags — and when the flag says truncated, the correct comparison is a prefix match, not an equality test.

The date format depends on the country field

This is the specific failure worth carrying away from the page. Dates in the barcode are eight digits with no separator, and the field order differs by country: United States jurisdictions encode MMDDCCYY and Canadian jurisdictions encode CCYYMMDD. The country is itself a data element, DCG.

DBB09121987     # DCG = USA  ->  12 September?  no: MMDDCCYY -> 1987-09-12
DBB19870912     # DCG = CAN  ->  CCYYMMDD          -> 1987-09-12

Read DCG before you parse any date, and refuse to parse a date if DCG is absent or unrecognised rather than falling back to a default. A US-format date misread as Canadian usually produces an absurd year and fails loudly; the dangerous direction is a value that parses to a plausible date under the wrong rule, which then flows downstream as a silently wrong date of birth. Verify with a second assertion: date of birth must precede issue date, and issue date must precede expiry. Those three inequalities are an ordinary date field validation rule and they catch almost every ordering error without needing to know which format was intended.

A related trap is the class, restriction and endorsement codes. DCA, DCB and DCD are jurisdiction-defined, not national. A restriction code B does not mean the same thing in two states, so the code must always be stored with its DAJ jurisdiction and never interpreted against a single lookup table.

Reading both sides and reconciling them

  1. Decode the PDF417 first. If it decodes, you have structured data with no layout problem and no model call.
  2. Read the header, take the AAMVA version, and select the element map for that version before parsing any subfile.
  3. Parse elements into a dictionary keyed by the three-character id. Keep unknown identifiers rather than discarding them — jurisdiction-specific subfiles carry real data and a future version adds elements you have not seen, which is exactly what schema design for unseen variants is for.
  4. Read DCG, then parse the dates, then assert the ordering inequalities.
  5. Extract the card face separately with a vision model and a field schema, and treat it as an independent observation of the same facts.
  6. Reconcile. Where both sides carry a field, agreement is strong evidence; disagreement is a review case. Where only one side carries it, record which side it came from.

Step 6 gives a driver’s licence roughly the property a passport gets from having its data printed twice, though it is weaker: the barcode and the face are encoded from the same record at issue, so they agree by construction on a card that has not been tampered with, and a disagreement means either a read error or something a human should see. Either way it belongs in a queue, and the queue is small because most cards reconcile cleanly.

If the barcode does not decode at all — a scuffed card, a photograph at a bad angle, a scan at too low a resolution for the module size — do not silently fall through to the face. Record that the barcode was unreadable, because a face-only extraction has a materially different error profile and downstream consumers should know which one they have. This is the same principle as recording the source section on a sample size: the provenance is part of the datum.