I built a free tool that generates valid Polish ID card numbers for software testing. Each number passes the same ICAO 9303 checksum validation used in real passport machine-readable zones worldwide.
Why This Exists
Polish ID card numbers (dowód osobisty) aren't random strings. They have a strict format — three letters, six digits — and the last digit is a checksum. If you're building anything that touches Polish identity data (banks, insurance, government forms, KYC flows), random strings won't pass validation. And you can't use real numbers in test environments because GDPR exists.
The Format
Every Polish ID number looks like this: ABC123456
-
ABC— the series (three uppercase letters) -
12345— serial digits -
6— check digit
Not all 26 letters show up in the series. O and Q are excluded to avoid confusion with 0. So the valid alphabet is 24 letters.
The Interesting Part: ICAO 9303 Checksums
The check digit uses the same algorithm found in passport MRZs globally. It's simple and kind of elegant:
- Convert each character to a number. Digits stay as-is. Letters map to
A=10, B=11, ... Z=35. - Multiply each value by a repeating weight pattern:
7, 3, 1, 7, 3, 1, 7, 3, 1... - Sum everything up.
- The check digit is
sum mod 10.
In JavaScript, the core logic looks roughly like this:
const WEIGHTS = [7, 3, 1];
function charValue(ch) {
const code = ch.charCodeAt(0);
// digits: face value, letters: A=10..Z=35
return code >= 48 && code <= 57
? code - 48
: code - 55;
}
function checkDigit(chars) {
const sum = chars.reduce(
(acc, ch, i) => acc + charValue(ch) * WEIGHTS[i % 3],
0
);
return sum % 10;
}
The generator picks three random letters from the valid set, generates five random digits, concatenates them, runs the checksum over all eight characters, and appends the result as the ninth character. Every output is structurally valid.
Deduplication
One small detail I liked solving: the tool keeps a history set of the last 1,000 generated numbers and rerolls if it hits a duplicate. Overkill for a 24×10⁵ keyspace? Probably. But it means you can generate batches of 100 without worrying about collisions in your test fixtures.
while (attempts < 100) {
const candidate = generateIdNumber();
if (!idHistorySet.has(candidate)) {
idNum = candidate;
break;
}
attempts++;
}
The Stack
The tool runs inside a Phoenix LiveView app. The generation itself is pure client-side JavaScript — no server round-trip needed. The Elixir/Phoenix side handles rendering, i18n (the tool works in both English and Polish), and the colocated hook pattern that wires up the JS behavior to the LiveView DOM.
Everything runs in the browser. No ID numbers are sent to or stored on any server.
Try It
- English: Polish ID Number Generator
- Polish: Generator numeru dowodu osobistego
The tool also supports output formatting (raw ABC123456 vs. spaced ABC 123456) and batch generation of 1, 5, 10, or 100 numbers at a time.
Other Generators
Poland.gg has the same kind of generators for PESEL numbers, NIP tax IDs, and mikrorachunek tax payment accounts — if you're building test data for Polish systems, you probably need more than one of these.
What's Next
I'm considering adding a companion validator tool that breaks down an existing ID number and shows the checksum math step by step. Could be useful for debugging validation logic. Open to suggestions.
Top comments (0)