Scanning PDF417 Barcodes on US Driving Licenses for Age Verification
A step-by-step guide on how to implement a web app that performs an age check by scanning the PDF417 barcode on a US driver’s license using the STRICH Barcode Scanning SDK. Full sample code is available on Github.
Introduction to PDF417
PDF417, standing for Portable Data File 417, is a two-dimensional barcode symbology known for its grid-like appearance. Designed as a stacked barcode, PDF417 appears as several 1D barcodes stacked atop each other. Below is an example PDF417 barcode that encodes the data Hi, I am a PDF417 barcode
.
PDF417 uses Reed-Solomon error correction, ensuring that even if a section of the barcode is damaged, the data remains recoverable. Its robustness, combined with its data capacity, makes it a popular choice for applications that require substantial data storage in a compact form.
Another defining characteristic of PDF417 is that it’s readable with laser scanners that only scan in one direction (horizontally), by making multiple passes in vertical direction.
PDF417 Structure
What does “417” in PDF417 stand for? To understand that, we have to take a closer look at the symbology’s structure. As mentioned previously, PDF417 is a stacked symbology, meaning that it’s composed multiple 1D barcodes (let’s call them rows) on top of each other. Each row is composed of characters:
Start character: denotes the start of a row
Left row indicator: encodes the row number and other metadata
1-N data characters: encode the actual payload
Right row indicator: encodes row number and other metadata
Stop character: encodes end of row
Each character is comprised of a sequence of 4 bars and 4 spaces, with a total width 17 modules. And that’s why it’s called PDF417.
Maybe that was more detail than what you were asking for, but there you have it. Let’s move on to practical applications.
PDF417 in US Driver’s Licenses
One example of PDF417 applications are US driver’s licenses. US driver’s licenses are defined by the AAMVA, for detailed information please refer to the AAMVA DL/ID Card Design Standard (2020).
Here’s an example of a Pennsylvania driving license, with synthetic data:
The barcode encodes a lot of information about the license holder, for instance: name, address, date of birth and more. That is sensitive information and should be handled with care.
Age Verification with an AAMVA PDF417 Barcode
In this example, we would like to perform an age check. We can do that by scanning the PDF417 barcode and comparing it to a reference age, say 21.
If you dig into the AAMVA document, you realize that the driver’s license data is encoded into a long string, separated into groups and fields by control characters. The date of birth is encoded in the DBB field, and it is a mandatory field — which is good, so we can rely on it being there.
This what the AAMVA spec has to say on the DBB field:
The format of the DBB field is F8N
, which is a shorthand for:
(F )ixed length: the field has a fixed length of 8 characters
(N )umeric: the field is comprised of numbers
The example for DBB given in the spec is DBB06061986<LF>
where <LF>
denotes the line feed character (ASCII code 10).
In addition to the date, we might also want to display the license holder’s first (DAC) and last name (DCS), both of which are mandatory variable-length fields with format identifier V40ANS
(variable-length, 40 alphabetic, numeric and special characters).
For simplicity, we will treat the PDF417 data as a string and extract the DBB, DAC and DCS fields using regular expressions and not perform any additional validation. Obviously we are not going to write production code.
Building the App
To keep the app as simple and generic as possible, we will refrain from using any web application frameworks like Next.js, Angular or Vue and just stick to plain JavaScript-based DOM manipulation.
Layout & Styling
The app will consist of a single HTML file, containing a full-screen container element where the barcode scanner will live, and two dialog elements — one for the success case (age equal or above reference age), and one for the failure case (age below reference age). Dialog elements are built-in elements that allow for modal popups without any third-party libraries.
The HTML doesn’t contain any surprises.
We’ll keep the styling to a minimum. The linked CSS makes the success dialog have a green background, the failure dialog have a red one, and makes the OK button “fat finger compatible” (full-width with added padding). We’re not going to win beauty prizes and that's ok.
Building the code
In a nutshell, the JavaScript code does the following:
SDK and BarcodeReader initialization — initialize the SDK for use and provide it with a valid license key. Initialize a BarcodeReader instance and configure it to look for PDF417 barcodes and use the container as its host element.
Barcode data processing — provide the detected hook that parses the PDF417 data, executes the age check, and displays the success or failure dialog.
AAMVA data extraction — regular expression-based parsing of date of birth, last name and first name fields from raw PDF417 data. For details, see aamva.js. In a real application, you would be doing a lot more validation and supporting of older AAMVA specification versions.
Here’s the code:
Typically STRICH SDK is installed via NPM: here we include the strich.js file as an ES6 module and obtain it from jsDelivr, a popular CDN.
Demo
To run the app, all you have to do is serve the files in the sample directory using an HTTP server. There is no build step involved — it’s just plain HTML and JavaScript after all.
If your system has Python installed, which is likely if you are a developer, you already have a barebones HTTP server at your disposal:
Unfortunately, web apps that access the camera need to be served from secure origins — a fancy word for “served over HTTPS or localhost”. We recommend using tools like ngrok or devtunnels to easily expose a local HTTP service through a publicly resolvable hostname and valid TLS certificate. More details on that topic are available in the Deployment Guide.
If you want to peak at the app in action but don’t want to set it up yourself, here’s a short clip:
Wrapping Up
In this article we showed how the PDF417 barcode on a US driver's license can be used to build a simple age verification web app. Full sample code is available on Github.