If you run a car marketplace, classifieds site or dealer tool, the VIN field is your best defense against bad listings, but only if you validate it properly. A check-digit test alone isn't enough. Here's a layered checklist, from cheap input checks to cross-checking the listing.
1. Normalize input
- Trim whitespace, remove spaces and dashes, uppercase everything.
- Don't silently "fix" I, O and Q to 1/0. Flag them instead: they're never valid in a modern VIN, and auto-correcting can hide typos or fraud.
2. Structural checks (instant, client-side)
- Exactly 17 characters for vehicles from model year 1981 onward.
- Allowed alphabet:
A-H J-N P R-Z 0-9. - Position 9 check digit passes (North American VINs). Many non-North-American VINs don't use it, so treat a failure on a non-NA WMI as a warning, not an error.
- Position 10 is a valid model year code (never U, Z or 0).
const VIN_RE = /^[A-HJ-NPR-Z0-9]{17}$/;
export function normalizeVin(raw: string) {
return raw.replace(/[\s-]/g, "").toUpperCase();
}
export function basicVinErrors(vin: string): string[] {
const errs: string[] = [];
if (vin.length !== 17) errs.push("Must be 17 characters");
if (/[IOQ]/.test(vin)) errs.push("Contains I, O or Q");
if (!VIN_RE.test(vin)) errs.push("Invalid characters");
if (/[UZ0]/.test(vin[9] ?? "")) errs.push("Invalid model year code");
return errs;
}
3. Decode on the server
Call NHTSA's vPIC DecodeVinValues endpoint (free, no key). Check:
-
ErrorCodeis0(or only informational codes); otherwise show theErrorText. - Make, Model, ModelYear are populated.
Cache results by VIN; specs don't change.
4. Cross-check against the listing
This is where most fraud is caught:
- Year, make, model in the listing match the decode.
- Body class (sedan vs SUV vs pickup) matches.
- Engine and fuel type match when the seller states them (e.g. "V8" vs a decoded 4-cylinder, "electric" vs gasoline).
- Drive type (AWD/4WD) if advertised.
Auto-fill these fields from the decode and lock or highlight edits that contradict it.
5. Duplicate and reuse detection
- Flag the same VIN appearing in multiple active listings, especially from different sellers or cities.
- Flag VINs previously removed for fraud.
- Watch for listings that reuse a VIN with different photos or colors.
6. Point buyers to external checks (don't overclaim)
You can't verify history from a decode. Link buyers to:
- NHTSA's VIN recall lookup,
- NICB VINCheck (theft and insurance total-loss records),
- an NMVTIS-approved title history provider.
Label clearly that your decode confirms factory specs only.
7. UX details that matter
- Show the decoded summary ("2019 Honda Civic LX sedan, 2.0L") right under the VIN field so sellers catch their own typos.
- Accept pasted VINs from photos/OCR, but always show the result for confirmation.
- Keep pre-1981 vehicles on a separate path: their VINs are shorter and don't follow the 17-character standard.
Summary
Normalize, check structure, decode, cross-check the listing, detect duplicates, and be honest about what a decode can't tell you. That catches most typos and a large share of fake listings before a buyer ever sees them.
Disclosure: I build VIN Lookup, a free VIN decoder based on NHTSA data.
Top comments (0)