How to Parse an AAMVA Driver's License Barcode (PDF417)
The barcode on the back of a US or Canadian driver's license is a PDF417 that encodes the holder's identity data in the AAMVA format. Reading it sounds simple — it's just text — but the spec has enough quirks that "parse the license barcode" eats days of developer time. This guide explains the format, the traps, and how to extract and validate it reliably.
This is about reading existing licenses for legitimate verification (age-gating, KYC, account matching). It is not about creating or altering credentials.
What's actually in the barcode
After you decode the PDF417 to text, you get an AAMVA record with three parts:
- A compliance header — starts with
@, control characters, thenANSIfollowed by the Issuer Identification Number (6 digits), the AAMVA version, the jurisdiction version, and the number of subfiles. - Subfile designators —
DL(driver license) orID, with offsets/lengths. - Data elements — three-letter codes, each followed by its value, newline-separated.
The fields you usually want:
| Code | Field | Code | Field |
|---|---|---|---|
| DCS | family name | DBB | date of birth |
| DAC | first name | DBA | expiration date |
| DAD | middle name | DBD | issue date |
| DAQ | license number | DBC | sex |
| DAG | street address | DAU | height |
| DAI | city | DAJ | state |
| DAK | postal code | DCG | country |
The gotchas that cost you a day
- Date formats differ by country. US jurisdictions use
MMDDYYYY; Canadian ones useYYYYMMDD. Parse the wrong order and a January DOB becomes a day-of-month. - Subfile prefixes leak into elements. The first element line is often
DLDAQ1234567— theDLdesignator glued toDAQ. Strip it or you'll mis-key the field. - Control characters. The payload contains
@, line feed (LF), record separator (RS,0x1E), and segment terminator (CR) — splitting naively breaks the header. - Version drift. Element availability and truncation flags (
DDE/DDF/DDG) vary across AAMVA versions; older cards useDCTinstead ofDACfor first name. - Validation. A real parser should confirm the
ANSIheader, a numeric IIN, and the presence of required elements before trusting the data.
The privacy-first move: derive, don't store
If your actual question is "is this person 21?", you do not need to keep their name,
DOB, or address — you need a boolean. The compliant pattern is to parse the barcode, derive
is21Plus / isExpired from the dates, and discard the PII. That turns an ID scanner
(a breach liability) into an age check (almost none).
Do it with one API call
POST /api/aamva/parse handles the header, the subfile prefixes, the date formats, and the
validation, and returns clean JSON. Set redactPII: true to get the derived signals with
the personal fields masked:
bash
curl -X POST https://YOUR-DOMAIN/api/aamva/parse \
-H "Content-Type: application/json" -H "X-API-Key: pdf417_live_…" \
-d '{ "imageBase64": "<DL barcode image>", "redactPII": true }'
json
{
"compliant": true,
"parsed": { "familyName": "[REDACTED]", "dateOfBirth": "[REDACTED]", "addressState": "VA" },
"validation": { "errors": [], "warnings": [] },
"derived": { "ageYears": 33, "is21Plus": true, "isExpired": false }
}
See the API docs for the decoded-text input, full field list, and limits.
FAQ
- US and Canada? Yes — both
MMDDYYYYandYYYYMMDDdates are handled. - Can I check expiry? Yes —
derived.isExpiredcompares the expiration date to today. - Do you store the data? No. Payloads are parsed to produce the response and not retained.
- Is this legal? Reading a license you're authorized to verify is a routine, lawful operation. This tool parses and validates; it does not generate or modify credentials.
Stop fighting the spec
Read the API docs → and parse a license barcode in one request — header, subfiles, dates, and validation handled.