Every US state issues driver's license numbers in a different format, and international licenses add dozens more. Learn how PII Detection API finds, classifies, and locates license numbers in claims, tickets, HR files, and transcripts — with offsets, confidence scores, and optional masking.
The driver's license is the identity document Americans actually carry. It gets photographed at car rental counters, typed into insurance claim forms, read aloud to call center agents, photocopied by HR departments, and pasted into support tickets whenever someone needs to prove who they are. As a result, driver's license numbers leak into unstructured text at a rate that surprises most compliance teams the first time they run a scan: claim narratives, onboarding emails, background-check correspondence, chat transcripts, even calendar invites ("bring DL# D1234567 to the appointment").
Detecting these numbers automatically is harder than it sounds, because there is no such thing as the driver's license number format. Each of the 50 US states — plus DC and the territories — defines its own scheme, ranging from plain 8-digit numbers to 14-character codes that algorithmically encode the holder's surname and birth date. International licenses multiply the variety further. PII Detection API addresses this with the DRIVERS_LICENSE_NUMBER entity type: a context-aware detector that recognizes the full catalog of state and national patterns and, crucially, uses the surrounding language to decide whether a matching string really is a license number rather than a policy number, VIN, or employee ID.
For every hit, the API returns the entity type, the exact matched text, its start and end character offsets, and a confidence score — and can optionally rewrite the text with the value masked. That structure is what lets you build precise redaction, alerting, or quarantine logic instead of blunt keyword filters.
You can watch the detector work on your own sample text in the interactive demo before writing any code; the sections below cover the risk profile, the formats, and complete integration examples against the detection API.
A driver's license number is a government-issued identifier tied to a verified legal identity, a photograph, a home address, and a date of birth. That combination makes it one of the most useful single artifacts for impersonation.
License numbers are a staple of full-identity "fullz" packages traded after breaches, and they play a specific role in synthetic identity fraud: a real license number lends credibility to an otherwise fabricated identity when fraudsters open accounts, pass knowledge-based verification, or file fraudulent unemployment and insurance claims. Because a license number changes only when a person moves states or the state redesigns its scheme, a leaked number stays exploitable for years — much like the bank account identifiers covered in our financial account detection guide.
The DPPA (18 U.S.C. §2721) is one of the few US federal privacy statutes aimed at a single record type: it prohibits state DMVs — and anyone who obtains data from them — from disclosing personal information from motor vehicle records outside a list of permissible uses. Insurers, employers running motor vehicle record checks, tow companies, and data resellers all inherit DPPA obligations when DMV-sourced data flows into their systems. Once that data lands in free-text fields, proving you control it requires finding it first, which is precisely the discovery problem automated detection solves.
Nearly every US state's breach-notification statute enumerates "driver's license number or state identification card number" as a data element whose exposure, in combination with a name, triggers mandatory notification. California's CCPA/CPRA goes further, both defining license numbers as personal information subject to consumer rights and creating a private right of action when they are breached due to unreasonable security. In practical terms: a support database that silently accumulates license numbers in ticket bodies is a latent notification event. The CCPA/CPRA compliance guide covers how detection supports rights-request fulfillment and breach-scope analysis.
Rule of thumb: if a text store contains names, assume it also contains license numbers wherever your business touches vehicles, claims, employment screening, or age verification. Scan before an incident forces you to.
Social Security numbers have one format. Credit cards have a checksum. Driver's licenses have neither luxury: the number is whatever each issuing jurisdiction decided, often decades ago, sometimes with logic that actively resembles other data.
Consider what a detector must accept as potentially valid: 12345678 (Texas or Pennsylvania), D1234567 (California), T520-4839-2210-01 (a hyphenated Illinois-style rendering), WDLABCD456DG (Washington's legacy name-derived format), and 999123456 (New York's plain nine digits — which is also the shape of an SSN and an ABA routing number). Some states encode personal data directly into the number: Florida and Illinois derive leading characters from a Soundex encoding of the surname plus coded birth-date digits, and Washington's older format embedded chunks of the holder's name. That means two things: first, the number itself can leak name and birth-date information; second, the character mix varies so widely that no single expression can describe "a license number".
The practical consequence is that license detection is a classification problem, not a pattern-matching problem. The engine treats format plausibility as one signal among several — label vocabulary ("DL#", "lic. no.", "driver's license", "CDL"), state references ("CA license", "issued by Ohio BMV"), document genre (claim form vs. purchase order), and co-occurring entities like names, addresses, and dates of birth — and only then commits to the DRIVERS_LICENSE_NUMBER label with a confidence score you can threshold against. The complete list of identity-document entities is on the entities page.
Detection is a single POST request. Send the text plus the entity types you care about; for license-bearing documents the natural companions are PERSON_NAME and DATE_OF_BIRTH, since the three travel together on every license and claim form.
curl -X POST https://piidetectionapi.com/api/moderate.php \ -H "Content-Type: application/json" \ -d '{ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": "Driver James Okafor, TX DL 38291045, DOB 09/23/1990, cleared the MVR check.", "entities": ["DRIVERS_LICENSE_NUMBER", "PERSON_NAME", "DATE_OF_BIRTH"], "mask_mode": "replace" }'
import requests resp = requests.post( "https://piidetectionapi.com/api/moderate.php", json={ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": "Driver James Okafor, TX DL 38291045, DOB 09/23/1990, " "cleared the MVR check.", "entities": ["DRIVERS_LICENSE_NUMBER", "PERSON_NAME", "DATE_OF_BIRTH"], "mask_mode": "replace", }, timeout=30, ) data = resp.json() for e in data["detected_entities"]: print(e["type"], e["text"], e["start"], e["end"], e["confidence"])
const resp = await fetch("https://piidetectionapi.com/api/moderate.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ api_key: "YOUR_API_KEY", api_type: "pii_detection", text: "Driver James Okafor, TX DL 38291045, DOB 09/23/1990, " + "cleared the MVR check.", entities: ["DRIVERS_LICENSE_NUMBER", "PERSON_NAME", "DATE_OF_BIRTH"], mask_mode: "replace" }) }); const data = await resp.json(); data.detected_entities.forEach(e => console.log(e.type, e.text, e.start, e.end, e.confidence));
The response carries the structured entity list plus the masked text:
{
"detected_entities": [
{"type": "PERSON_NAME", "text": "James Okafor", "start": 7, "end": 19, "confidence": 0.97},
{"type": "DRIVERS_LICENSE_NUMBER", "text": "38291045", "start": 27, "end": 35, "confidence": 0.94},
{"type": "DATE_OF_BIRTH", "text": "09/23/1990", "start": 41, "end": 51, "confidence": 0.96}
],
"anonymized_text": "Driver [PERSON_NAME], TX DL [DRIVERS_LICENSE_NUMBER], DOB [DATE_OF_BIRTH], cleared the MVR check.",
"entities_detected": 3,
"processing_time_ms": 156,
"mask_mode_used": "replace",
"status": 200
}
Note that the bare 8-digit number was classified as a license because of "TX DL" and the surrounding driver-record context; the same digits in an invoice would have been left alone. If you only need discovery — flagging documents for review without altering them — omit mask_mode and read just detected_entities. Full parameter semantics live in the API documentation.
The table below samples the diversity a detector must handle. It is not exhaustive — several states have issued multiple schemes over the years, and old numbers remain valid identifiers in historical records — but it shows why "match a license number" cannot be a single expression.
| State | Format | Example | Notes |
|---|---|---|---|
| California | 1 letter + 7 digits | D1234567 | Letter is sequential, not personal |
| Texas | 8 digits | 38291045 | Collides with order and invoice numbers |
| Florida | 1 letter + 12 digits | T520483922100 | Leading letter + digits Soundex-encode the surname and birth date |
| Illinois | 1 letter + 11 digits | T52048392210 | Encodes name and DOB; often written with hyphens |
| New York | 9 digits | 999123456 | Same shape as SSN and ABA routing numbers |
| New Jersey | 1 letter + 14 digits | O123456789012345 | Longest common US format; encodes name/DOB elements |
| Washington | 12 alphanumeric | WDLABCD456DG | Legacy format derived from holder's name; newer licenses use WDL + 9 alphanumeric |
| Wisconsin | 1 letter + 13 digits | T5204839221001 | Soundex-based like Illinois/Florida |
| Michigan | 1 letter + 12 digits | T520483922100 | Same shape as Florida — state context disambiguates |
| Ohio | 2 letters + 6 digits | TL545796 | Compact format; BMV correspondence is a common source |
| Pennsylvania | 8 digits | 99123456 | Identical shape to Texas |
| Virginia | 1 letter + 8 digits | T12345678 | Also accepts SSN-derived legacy numbers in old records |
| Maryland | 1 letter + 12 digits | T520483922100 | First letter matches surname initial |
| Georgia | 9 digits | 053815396 | Another nine-digit collision case |
Two structural facts stand out. First, at least five populous states use plain 8- or 9-digit numbers, indistinguishable by shape from SSNs, routing numbers, ZIP+4 codes, and internal record IDs — classification must come from context. Second, the Soundex-encoding states (Florida, Illinois, Wisconsin, Maryland, Michigan share the family) mean a license number can itself be a partial disclosure of name and birth date, which is worth remembering when you decide whether last-four-style partial masking is acceptable for your use case.
It is tempting to concatenate fifty state patterns into one giant alternation and call it a detector. Teams who try this discover three failure modes within the first week.
This is the textbook case for transformer-based NER over rules: the model reads "policy HX-4483920 covers driver, MI license T520483922100" and labels only the second token, because it has seen millions of claim-like sentences and learned what role each token plays. The NER vs regex comparison guide quantifies the precision gap on identifier-heavy text if you want the benchmark detail.
Anti-pattern: running a broad license regex first and "confirming" hits with the API doubles your cost and halves your precision — the regex pre-filter discards the context the model needs. Send the raw text; let the model see the whole sentence.
Global operations — ride-share platforms, rental fleets, multinational HR — meet license formats from every jurisdiction their drivers hold. A few of the most common:
| Country | Format | Example | Notes |
|---|---|---|---|
| United Kingdom | 16 characters | TORRE704129MJ9AB | Encodes first 5 letters of surname, DOB digits, initials — the number itself leaks identity data |
| Canada | Per province | T1234-56789-01234 (ON) | Ontario 15 alphanumeric encoding name/DOB; Quebec 13; BC 7 digits |
| Germany | 11 alphanumeric | B072RRE2I55 | Issuing-authority prefix + serial + check character |
| Australia | State-based, 6–10 alphanumeric | 12345678 (NSW) | Victoria up to 10 digits; some states now issue letters+digits |
| India | 15 characters | MH12 20240012345 | State code + RTO code + issue year + serial (SS-RR-YYYYNNNNNNN) |
The UK format deserves special mention: because it embeds the surname fragment and coded date of birth, a leaked UK license number is effectively a leaked name-plus-DOB pair under GDPR analysis — treat it with the same severity as the underlying attributes. Detection works across 60+ languages, so a German claim narrative or Hindi onboarding form is parsed with native context rather than translation; see the supported languages page for coverage.
Knowing where license numbers concentrate tells you where to point your first scans.
The densest source by far. First notice of loss (FNOL) narratives, adjuster notes, quote requests, and subrogation correspondence routinely contain the license numbers of every driver involved in an incident — policyholder and third parties alike, meaning you hold license data for people who are not even your customers. The insurance industry guide walks through claim-pipeline integration patterns.
Employment verification, commercial fleet onboarding, and ride-share/delivery driver applications all collect license numbers, and they leak from structured fields into recruiter emails, background-check follow-ups, and applicant-tracking notes. CDL numbers in trucking and logistics carry the same risk with an additional federal overlay. See the HR & recruiting guide for the employment-context view.
DMV letters quoted into CRM tickets inherit DPPA obligations. Car rental agreements and damage disputes capture licenses at the counter. Traffic incident and police reports pasted into legal or claims files bring license numbers of drivers, witnesses, and owners. Age-verification flows (car sharing, alcohol delivery) add a steady drip through customer support channels.
Across all of these, the pattern is identical: a structured system collected the number legitimately, and free text carried it somewhere ungoverned. Detection at the ingestion boundary of each free-text store is the fix.
Claims text mixes license numbers with names, addresses, and birth dates; scanning them together produces a complete redaction in one call:
import requests claim_text = open("fnol_narrative.txt").read()[:50000] resp = requests.post( "https://piidetectionapi.com/api/moderate.php", json={ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": claim_text, "entities": ["DRIVERS_LICENSE_NUMBER", "PERSON_NAME", "ADDRESS", "DATE_OF_BIRTH", "NATIONAL_ID"], "mask_mode": "replace", "threshold": 0.5, }, timeout=30, ) data = resp.json() print(data["anonymized_text"]) print(f"{data['entities_detected']} identifiers masked " f"in {data['processing_time_ms']}ms")
Fraud analytics needs to link the same driver across claims without storing the license number itself. mask_mode: "hash" substitutes a consistent token per unique value, so joins and repeat-claimant detection keep working on sanitized data:
// Sanitize claim notes before loading into the analytics warehouse async function sanitizeClaim(note) { const resp = await fetch("https://piidetectionapi.com/api/moderate.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ api_key: process.env.PII_API_KEY, api_type: "pii_detection", text: note, entities: ["DRIVERS_LICENSE_NUMBER", "PERSON_NAME"], mask_mode: "hash" // same license => same token across claims }) }); const data = await resp.json(); return data.anonymized_text; }
If your policy numbers happen to look license-shaped (a common complaint in insurance), tell the API in plain English instead of fighting thresholds:
curl -X POST https://piidetectionapi.com/api/moderate.php \ -H "Content-Type: application/json" \ -d '{ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": "Policy A98213345 renewed. Insured driver holds FL license T520483922100.", "entities": ["DRIVERS_LICENSE_NUMBER"], "mask_mode": "replace", "custom_instruction": "Our policy numbers start with a letter followed by 8 digits and are labeled Policy; never classify them as driver license numbers." }'
Only the Florida license is masked; the policy number survives intact. For audit sweeps of historical archives, pair this with a lowered threshold (0.35–0.4) and human review of mid-confidence hits, exactly as you would for account numbers; for inline masking of agent-visible text, keep the threshold at 0.6 or higher so legitimate reference numbers are not mangled.
Breach statutes trigger on name plus license number. Detecting DRIVERS_LICENSE_NUMBER together with PERSON_NAME, ADDRESS, and DATE_OF_BIRTH lets you score documents by combination risk — a bare license-shaped token is low priority; the full cluster is an incident-in-waiting.
If your pipeline knows the record's jurisdiction (a state field on the claim, the DMV the letter came from), keep that metadata adjacent to the text you send. Phrases like "TX DL" or "Ontario licence" measurably sharpen classification of the format-ambiguous states.
Always cut using the returned start/end positions. License numbers recur in documents with different framing, and a digit string may be a substring of a longer identifier; find-and-replace will eventually corrupt something a regulator later asks about.
UK, Florida, Illinois, and similar numbers embed surname and birth-date material. When you report breach scope or answer a CCPA deletion request, count these as carrying those attributes, not just an opaque ID.
A sub-200ms synchronous check on the ticket webhook, claim-intake API, or transcript pipeline keeps license numbers out of the store permanently; retroactive lake scans are for the backlog, not the steady state. Median processing time comfortably fits inline budgets — verify against your own payloads via the demo or a free key from the get started page, with volume tiers on the pricing page.
People transcribe licenses with hyphens (T520-4839-2210), spaces, dots, or in lowercase; Illinois numbers in particular are conventionally hyphenated. The detector normalizes separators before format assessment while returning offsets against the original text, so masking stays exact.
Uploaded license images run through OCR arrive with classic confusions — O/0, I/1, B/8 — and jumbled field order (the number adjacent to height, class, and expiry fields). The model tolerates common substitutions inside otherwise coherent license contexts and uses the card's field vocabulary ("DL", "CLASS", "EXP", "DOB") as strong evidence. For full document workflows, the document scanning guide covers the OCR pipeline end to end.
Abbreviated labels ("DL#", "CDL:", "lic no", "OLN" on police reports) are learned vocabulary, not hardcoded triggers — they raise confidence but their absence does not prevent detection when the discourse context is strong, as in a DMV letter.
Plate numbers ("7ABC123") appear in the same incident reports and are frequently confused by naive matchers. The model separates them: plates attach to vehicles and phrases like "plate", "tag", "registration", while license numbers attach to persons. If you need both flagged, add plate-bearing text to your review flow via custom_instruction; if you need plates ignored, no action is required — they are not classified as DRIVERS_LICENSE_NUMBER.
Nine-digit ambiguity: New York and Georgia licenses share their shape with SSNs. When scanning mixed HR files, request both DRIVERS_LICENSE_NUMBER and SSN; each hit is labeled by its own context, and you avoid the failure mode where an SSN-only scan silently absorbs license numbers or vice versa.
When the text names the state ("CA license", "issued in Ohio") the classification uses it, and the surrounding text keeps that attribution readable for your reviewers. The API does not guess a state from format alone — as the format table shows, several states share identical shapes, so a definitive attribution without context would be false precision.
Through role classification: VINs appear near vehicle descriptors and are 17 characters; policy and claim numbers carry their own labels and document positions. The model assigns each token the role the sentence gives it. Where your internal identifiers are genuinely license-shaped, a one-line custom_instruction describing them eliminates the residual overlap.
Yes. CDLs use the same state numbering systems, so they are detected identically; "CDL" labeling in fleet and logistics text is recognized vocabulary that raises confidence.
Old-format numbers (Washington's name-derived codes, Virginia's SSN-based legacy numbers) remain in archives and remain sensitive — Virginia's legacy numbers doubly so, since they may literally be SSNs. Legacy formats are in the training distribution and are detected; for SSN-derived ones, scan with both entity types enabled.
Only when context supports it. A bare 38291045 in an invoice is ignored; the same number after "TX DL" or inside an MVR report is flagged with high confidence. This context dependence is deliberate — it is what keeps precision usable on identifier-dense business text.
Yes — detection spans 60+ languages, including the label vocabulary around license numbers ("Führerscheinnummer", "numéro de permis", "número de licencia"). Coverage details are on the supported languages page.
Paste representative samples into the live demo — it runs the production models and shows each entity with type and confidence. Then take a free API key from get started and run a pilot batch; the pricing page lists volume tiers when you scale up.
Test all 50 state formats against your own claims, tickets, and transcripts — no code required to start.
Try the Live Demo View Pricing