Methodology & Accuracy
Every barcode this site produces passes through two distinct pieces of software with two distinct jobs, and this page draws the line between them precisely — because knowing who is responsible for what is what makes an error findable.
This page is the summary. Each engine named below also has a guide of its own that walks it through cited reference numbers and fictional inputs to the same build-time standard; read this page first for the boundaries, and a guide when you want to see one engine's every step. The eight are collected on the guides hub alongside the editorial guides:
- How GTIN check digits are computed — the mod-10 walk-through, compute versus verify mode, a corrupted digit caught.
- EAN-13 structure explained — the breakdown engine, its prefix classification, and why the middle nine digits are one region.
- ISBN-10 and ISBN-13 conversion — mod-11 with X, the 978 conversion in both directions, the 979 refusal.
- Code 128 code sets and the Code 39 charset — the character analysis the validator performs and the conversion it discloses.
- Bulk GTIN validation modes — auto versus data-only on an ambiguous digit count, the row statuses, the cap.
- Label-sheet geometry — page sizes, preset arithmetic that must close, sheet counts, custom grids checked rather than clamped.
- ZPL and EPS export explained — the check digit the printer recomputes, the SVG-to-PostScript flip, what the tests pin.
- How the verifier decodes what you see — the independent decode, its two reasons for withholding, the bulk-PDF exception.
The renderer versus the verification layer
Bar rendering — turning a validated payload into the black-and-white module pattern of Code 128, EAN-13, UPC-A, Code 39, or ITF-14 — is done by JsBarcode, an MIT-licensed open-source library, pinned to an exact version and used unmodified (the version and license are recorded in the repository's provenance note, and an automated test fails if the pin ever drifts).
Everything around the rendering is ours, implemented independently from published algorithm descriptions, without reference to the renderer's internals:
- The GTIN mod-10 check digit (weights 3 and 1, anchored at the rightmost data digit) used by EAN-13, UPC-A, and ITF-14 — in compute mode (12/11/13 digits entered) and verify mode (13/12/14 digits entered), with mismatches reported, never repaired.
- The ISBN-10 mod-11 check character (weights 10 through 2, X for ten), and the ISBN-10 → ISBN-13 conversion: verify the mod-11 check, prefix 978, recompute the EAN-13 check. The reverse direction exists for 978 ISBNs and is explicitly refused for 979.
- The Code 39 charset (43 characters), with disclosed uppercase conversion.
- Code 128 code-set analysis — which characters force set A or B, when set C compression applies — as validation and advice; the actual code-set optimization inside the symbol is the renderer's, following the same rules.
Validation before rendering
Before the renderer is called, the site normalizes the input, enforces the selected symbology's length and character rules, and computes or verifies any check digit with independently implemented arithmetic. A mismatch stops the flow and no bars are requested from the renderer. JsBarcode then converts that accepted payload into the module pattern.
How to read what the validator says
The validator returns one of two things. An accepted input comes back as a payload — the exact
string handed to the renderer — together with notes: plain sentences stating what validation did
on the way, because a normalisation applied invisibly would be a silent change. A refused input
comes back as an error with a code and a message, and nothing is rendered. The single-barcode
validator uses 3 codes: empty-input when nothing
usable was entered, invalid-input when the content breaks a length, character
or check-digit rule,
and out-of-range when the content is well formed but exceeds a cap this site imposes.
The message always names the rule and, where there is one, the number involved.
Two habits make the output legible. First, read the note under the barcode before downloading: it is the only place that says whether the check digit was computed for you or verified against what you typed. Second, read an error as a report, not a correction. When a message names the digit a number would need, it is telling you where the arithmetic disagrees; the number it would take to make the arithmetic agree may be the wrong item's number, which is why the validator never puts it in for you.
The verification layer, engine by engine
What follows is each engine's rule beside its own output on a cited reference number or a fictional input, computed when this page was built. Where a sentence quotes a message, it is the engine's message; where it quotes a figure, the figure came out of the function named.
GTIN mod-10, position by position
The rule: write the data digits left to right, weight them alternately 1 and 3 anchored so that the rightmost data digit carries 3, sum the products, and take the difference to the next multiple of ten; a sum already ending in zero takes 0, not 10. One function serves EAN-8, UPC-A, EAN-13 and ITF-14 — the symbology decides the length, not the arithmetic.
Worked example — the cited data digits 400638133393:
4×1 + 0×3 + 0×1 + 6×3 + 3×1 + 8×3 + 1×1 + 3×3 + 3×1 + 3×3 + 9×1 + 3×3 = 89
Next multiple of ten: 90; 90 − 89 = 1; complete EAN-13: 4006381333931.
Engine output at build time: the digits, weights, products and sum are the steps function's own intermediate values, and the check digit is the one the generator appends.
The generator reads its mode off the digit count and says, in its note, which it used:
- Twelve digits in — "You entered 12 digits — the check digit 1 was computed and appended, making 4006381333931."
- Thirteen digits in — "You entered all 13 digits — the check digit 1 was verified against the first 12 and is correct."
Change one data digit of the complete number — a fictional corruption: position
3, a 0, becomes 1, giving 4016381333931
with the check digit left in place — and verification recomputes from the first twelve: expected 0, supplied 1. The generator asks the renderer for nothing and
shows the error instead:
"Check digit mismatch: for 401638133393 the final digit must be 0, but you entered 1. Fix the number, or enter only the first 12 digits to have the check digit computed."
Engine output, computed at build time from the corrupted number above.
A single-digit change always moves the weighted sum off its multiple of ten, so every such error is caught; swapping two adjacent digits changes the sum by twice their difference, so a swap of digits that differ by five escapes — the EAN-13 page demonstrates both at build time.
EAN-13 segmentation: an honest split
The breakdown engine behind the EAN-13 page's structure panel splits a 12- or 13-digit input into the only segments that sit at knowable positions: the first three digits, the middle nine as one region, and the check digit — computed for twelve digits, verified for thirteen. The boundary between company prefix and item reference inside the middle nine depends on a licence length the number does not carry, so the engine reports one region and never a guessed split. Its prefix classification covers only ranges GS1 publishes for the whole symbology; everything else is reported as a standard prefix, with no country of manufacture invented.
Worked examples — cited vectors, with one fictional corruption of the second:
400638133393 (twelve digits): GS1 prefix 400, a standard GS1 member organization prefix; body 638133393, one region; check digit 1 computed; status “computed”; structurally valid completion 4006381333931.
5901234123457 (thirteen digits): GS1 prefix 590, a standard GS1 member organization prefix; body 123412345, one region; check digit 7 supplied, 7 required; status “verified”; structurally valid completion 5901234123457.
5901234123458 (thirteen digits, last digit changed): GS1 prefix 590, a standard GS1 member organization prefix; body 123412345, one region; check digit 8 supplied, 7 required; status “mismatch”; structurally valid completion 5901234123457.
9780306406157 (an ISBN-13): GS1 prefix 978, a Bookland ISBN prefix; body 030640615, one region; check digit 7 supplied, 7 required; status “verified”; structurally valid completion 9780306406157.
The completion is reported beside a mismatch so you can see what the arithmetic would accept; it is never applied to the number you entered.
ISBN-10, ISBN-13, and the direction that is refused
The ISBN-10 check character is mod-11: weights 10 down to 2 on the nine data digits, then the character that brings the sum to a multiple of eleven, written X when that value is ten. Conversion to ISBN-13 verifies that character first, prefixes 978, keeps the nine data digits and computes a fresh EAN-13 check digit with the mod-10 function above; a mistyped ISBN-10 is never converted. Hyphens and spaces are stripped and a trailing x is uppercased before any of this, and the note records every intermediate number.
Worked examples — the cited ISBN-10 and the cited X-check example:
0-306-40615-2 normalises to 0306406152; check character 2 verified (the nine data digits require 2); ISBN-13 9780306406157, with check digit 7 computed afresh; converted back, 0306406152 — the round trip closes.
The validator's note: "ISBN-10 0306406152 verified (check character 2), then converted to ISBN-13 9780306406157: 978 prefix + your 9 data digits + recomputed EAN-13 check digit 7."
0-8044-2957-X normalises to 080442957X; the nine data digits require X, the supplied character is X — verified.
The reverse direction, ISBN-13 to ISBN-10, is defined only for 978 numbers. Hand the engine a
fictional 979 number — 9798112345676, nine invented digits after the prefix with a
check digit computed here — and it refuses rather than invent: "979-prefixed ISBNs have no ISBN-10 equivalent — only 978 ISBNs convert back." The generator
still renders that number, because a 979 ISBN-13 is a complete Bookland EAN; its notes read:
"ISBN-13 9798112345676 verified: the check digit 6 matches its first 12 digits. 979-prefixed ISBNs have no ISBN-10 equivalent."
Code 39 charset and Code 128 code sets
Neither symbology carries a check digit this site computes, so their verification is about characters. The Code 39 engine holds a charset of 43 characters and reports every character outside it, in first-appearance order. The validator applies one disclosed conversion before that check: lowercase letters are uppercased, and the note says so. The input rule shown beneath the field is the engine's own: "Uppercase A–Z, digits, space, and - . $ / + % only. 1–60 characters."
Worked example — the fictional bin-0042:
Tested raw against the charset, it fails on “b”, “i”, “n”.
Passed through the validator, it becomes BIN-0042, with the note "Code 39 has no lowercase letters — your input was converted to uppercase."
A character the conversion cannot rescue is refused: "Code 39 cannot encode “#”. Its character set is A–Z, 0–9, space, and - . $ / + % — for anything richer, use Code 128."
The Code 128 engine analyses rather than encodes. For each input it reports whether every character is printable ASCII and which are not, whether a lowercase letter forces code set B, whether the input is digits only with an even count — pure code set C — and the longest run of consecutive digits, then gives one sentence of guidance. The guidance is advice; the code-set optimisation inside the symbol is the renderer's, following the same rules. Three fictional inputs follow; the rule shown beneath the input field is the engine's own: "Printable ASCII characters (letters, digits, punctuation, space). 1–80 characters."
| Input | Why chosen | Set B forced | Pure set C | Longest digit run | Guidance |
|---|---|---|---|---|---|
SKU-44021
|
uppercase with a run of digits | no | no | 5 | Uppercase text with digit runs — code set B (or A) for the text, switching to code set C where four or more digits run consecutively. |
pallet-07
|
contains lowercase | yes | no | 2 | Contains lowercase letters, which only code set B provides — the encoder will use code set B (switching to C for long digit runs). |
20260001
|
digits only, even count | no | yes | 8 | All digits with an even count — encoded in code set C, two digits per symbol character (the most compact case). |
Characters outside printable ASCII are refused with the reason, in the validator's words — for a fictional input containing a tab: "This tool encodes printable ASCII only — it cannot encode control character U+0009. Full Code 128 can carry control characters and accented text via special conventions, but supporting them halfway would produce codes that scan differently across devices."
Bulk validation: two readings of an ambiguous length
The bulk engine splits pasted text into lines, strips spaces and hyphens, and hands each line to the same mod-10 primitives. Its one judgement is how to read a digit count. Twelve or thirteen digits could be a complete GTIN-12 or GTIN-13, or a data column still waiting for its check digit; in auto mode the complete-number reading wins — this is a validator first — while 7- and 11-digit lines, which have no complete-number reading, are completed. In data-only mode every line is data digits. A wrong check digit is reported with the expected digit and a corrected number in a separate field, never repaired in place.
The table runs a fictional list of 4 lines through both modes: the cited
EAN-13 data digits 400638133393; the cited EAN-8 example with its check digit
removed, 7351353; the cited sample EAN-13 5901234123457, complete; and
the invented line ABC-123, which is not digits.
| Line | Auto mode | Data-only mode |
|---|---|---|
400638133393
|
GTIN-12: Check digit should be 0, not 3. | GTIN-13: Check digit 1 appended. |
7351353
|
GTIN-8: Check digit 7 appended. | GTIN-8: Check digit 7 appended. |
5901234123457
|
GTIN-13: Check digit 7 is correct. | GTIN-14: Check digit 6 appended. |
ABC-123
|
unknown: Contains characters other than digits, spaces, and hyphens. | unknown: Contains characters other than digits, spaces, and hyphens. |
The first line is the cited EAN-13 data digits. In auto mode they are read as a complete
GTIN-12 — "Check digit should be 0, not 3." — and in data-only mode as the data digits of a GTIN-13
— "Check digit 1 appended." — giving 4006381333931, the number the single-barcode
generator computed above. The two modes agree on the 7-digit line, which has only one reading,
and on the line that is not digits. The counts: auto, 1 valid, 1 wrong check digit, 1 completed, 1 invalid;
data-only,
0 valid, 0 wrong check digit, 3 completed, 1 invalid. At most 500 lines are processed per pass, and the report
states when the input was longer.
Label-sheet geometry: the arithmetic must close
The bulk label tool places each validated barcode at a position computed from 9 inputs — the page, label width and height in millimetres, column and row counts, two margins and two gaps in millimetres. Its 3 preset templates are Avery geometries taken from the manufacturer's published templates, and the engine does not trust the transcription: a test asserts that twice the side margin, plus the labels, plus the gaps between them reproduce the page width exactly, and likewise the height, or the test fails. This page repeats that check when it is built, so the table could not render if a preset had drifted. Letter presets are defined in inches and shown in inches; A4 in millimetres.
| Template | Per sheet | Width closes | Height closes |
|---|---|---|---|
| Avery 5160 | 30 | 2 × 0.1875 + 3 × 2.625 + 2 × 0.125 = 8.5 in | 2 × 0.5 + 10 × 1 + 9 × 0 = 11 in |
| Avery 5163 | 10 | 2 × 0.15625 + 2 × 4 + 1 × 0.1875 = 8.5 in | 2 × 0.5 + 5 × 2 + 4 × 0 = 11 in |
| Avery L7651 | 65 | 2 × 4.75 + 5 × 38.1 + 4 × 2.5 = 210 mm | 2 × 10.7 + 13 × 21.2 + 12 × 0 = 297 mm |
Counting follows from the grid: Avery 5160 holds 30 labels per sheet, so a fictional order of 130 labels needs 5 sheets and the input cap of 300 rows needs 10. A custom grid is checked the other way round — the left margin, plus the labels, plus the gaps between them must fit within the page width, and likewise the height — and is never clamped. A fictional A4 grid of 3 columns of 70 mm labels with 5 mm gaps and a 10 mm left margin is refused in the engine's words: "The grid is 230.0 mm wide but the page is only 210.0 mm — reduce columns, label width, gap, or margin."
ZPL and EPS: two exports that are not pictures
The ZPL exporter receives the validated payload, check digit included, and never sees the bars.
For the EAN and UPC symbologies the printer command recomputes the check digit from the data
digits, so the exporter verifies the check digit independently, strips it, and says so. For the
cited EAN-13 4006381333931 the field line reads ^FD400638133393^FS —
12 of the 13 digits travel — and the notes returned with
the file are, in order:
- The ^FD data carries only the data digits — the printer recomputes the check digit and arrives at the same 1 for this EAN-13 that our validator already verified.
- ZPL uses your printer's native barcode engine — the printer draws the bars.
- Preview with a ZPL viewer or run one test label before a production run.
ITF-14 is the exception: the exporter sends the complete number, check digit included, so the
printer is handed exactly the validated payload — for GS1's published example
09506000134352 the field line is
^FD09506000134352^FS. The exporter's contract is independent of its caller: handed only
the data digits, it refuses — a state the download menu cannot reach, because the generator
passes only what the validator accepted:
"EAN-13 ZPL export needs the full 13-digit payload including the check digit, exactly as the generator produced it — received "400638133393" (12 characters)."
The EPS exporter receives the serialised SVG the decoder has just read and restates its
rectangles in PostScript: one SVG pixel to one point, with the y-axis flipped, because SVG
measures y down from the top edge and PostScript up from the bottom, so a rectangle at (x, y, w,
h) lands at (x, height − y − h, w, h). A fictional generated-style SVG of 100 × 50 with a white
background and one black bar at x = 10, y = 5, 3 wide and 35 tall converts to
the bounding box %%BoundingBox: 0 0 100 50 and 1 drawing line,
10 10 3 35 rectfill: 50 − 5 − 35 = 10, cross-checked here at
build time. The white rectangle is skipped — EPS graphics are transparent by convention and the
placing application supplies its own background — and with no caption the conversion carries
0 warnings.
Independent decoding after interactive rendering
The interactive generator does not trust that handoff alone. It rasterizes the actual SVG shown on the page and asks ZXing—an independent decoding engine—to read those pixels. The preview and download controls remain withheld when ZXing cannot decode the image or reads a different payload. PNG export is rendered to its own canvas and decoded again before the file is released. The single-barcode PDF exporter translates the independently decoded SVG's rectangles and caption into native PDF vector geometry rather than embedding a screenshot. This is an end-to-end check of the generated SVG/PNG pixels, not merely another calculation over the source string; the translated PDF itself still needs a test scan after printing.
The Barcode Verifier & Scanner exposes the same independent-reader idea for an uploaded image or camera view. Bulk PDF label sheets are the deliberate exception: each row receives structural and check-digit validation before rendering, but the assembled PDF rows are not individually decoded. No browser check can certify ink, substrate, scaling, contrast, or quiet zones after printing, so a physical production sample must still be scanned.
What the comparison accepts
The decoded text is compared with the validated payload, and the comparison accepts exactly one family of equivalences: a UPC-A read as the zero-prefixed EAN-13, or an EAN-13 beginning with 0 read as the 12-digit UPC-A without that zero — the same printed symbol under two names. Everything else must match exactly. The 4 comparisons below are computed here from the cited vectors and the fictional corruption above:
-
4006381333931read as4006381333931(an exact match): accepted. -
4006381333931read as4016381333931(the fictional corruption): withheld as a payload mismatch. -
036000291452read as0036000291452(the cited UPC-A read as a zero-prefixed EAN-13): accepted. -
4006381333931read as006381333931(the cited EAN-13 read with its first digit dropped): withheld as a payload mismatch.
A withheld barcode is reported under one of 2 reasons, each named in the generator:
-
decode-failed— the independent reader could not read the rendered bars at all. -
payload-mismatch— it read a string the comparison does not accept for the validated payload.
Both withhold the preview and every download. Before any pixels exist, the accepted payload is cross-checked once more — its check digit re-derived with the independent arithmetic and compared with the one validation recorded — and that check returned true for the cited EAN-13 when this page was built. A failure there would show the error and never the barcode.
Tested against cited, published values
Every algorithm is exercised against reference values from sources named in the test files: Wikipedia's EAN-13 walkthrough (400638133393 → check digit 1), its EAN-8 example 73513537, and UPC-A walkthrough (03600029145 → 2), the widely published sample EAN-13 5901234123457, the canonical ISBN example 0-306-40615-2 and its ISBN-13 form 978-0-306-40615-7, the X-check example 0-8044-2957-X, and GS1's published example GTIN 09506000134352 from the GS1 Digital Link documentation. Beyond vectors, property tests confirm the structure — every computed check digit re-verifies, single-digit corruptions are caught, leading zeros do not change GTIN checks. Suspected errors reported through the contact page are fixed in the verification layer and locked in with a new test.
Worked examples cannot drift
The check digits and conversions quoted in page prose are not typed in — they are computed at build time by the same verification code that runs in your browser. If the algorithms changed, the copy would change with them or the build would fail; the documentation cannot silently disagree with the tool.
This page holds itself to the same rule. Every figure above was produced by the function named and unwrapped by a helper that throws on an engine error, so an example that cannot be computed fails the build; and where a sentence rests on a premise — a round trip that must close, a corruption that must be caught, a refusal that must happen, a preset whose margins must reproduce its page — a guard checks the premise at build time and fails the build if it no longer holds. The cited inputs and the fictional inputs are typed; nothing derived from them is.
Constants, interpolated
The caps and page sizes quoted across the site are read from the engines when the pages are built, so a change to a constant changes every page that mentions it. Their current values:
| Constant | Value | What it governs |
|---|---|---|
MAX_BULK_ROWS
|
500 | Lines processed per pass by the bulk check-digit calculator; the report says when the input was longer. |
MAX_LABEL_ROWS
|
300 | Non-blank lines kept per pass by the bulk label tool; lines beyond it are counted and reported, not dropped silently. |
MAX_LABEL_FILE_BYTES
|
1,000,000 bytes | Size of a local file the label tool will import, checked before the file is read so browser memory stays predictable. |
TARGET_DPI
|
300 | The rendering target the label tool sizes its canvas against — a property of the image the PDF embeds, not a statement about any printer. |
PAGE_MM.letter
|
215.9 × 279.4 mm | The Letter page, defined in inches and converted exactly to millimetres. |
PAGE_MM.a4
|
210 × 297 mm | The A4 page, defined in millimetres directly. |
CODE39_CHARSET
|
43 characters | The characters the Code 39 validator accepts; the start/stop asterisk is not among them. |
SYMBOLOGIES
|
7 symbologies | The symbologies the validator knows; the renderer is asked for nothing outside them. |
None of these is a recommendation. The row caps keep a single pass predictable in a browser, and the reports say when they were hit; the rendering target sizes a canvas and says nothing about a printer; the page sizes are the 2 the label tool lays out.
Physical guidance: cited or qualitative
Where pages quote physical figures — EAN-13 quiet zones of 11 and 7 module widths, UPC-A's 9, ITF-14's 10, the 0.264–0.660 mm consumer X-dimension range — they come from GS1 member organization size guides (GS1 Sweden, GS1 Ireland) reflecting the GS1 General Specifications, and are linked where used. Where we could not verify a figure against such a source, the guidance stays qualitative — you will not find an invented DPI table on this site.
The honest limits
- Math, not optics. We verify digits and character sets. Whether a printed symbol scans depends on contrast, size, substrate, and preserved quiet zones — test with your own scanner before production or print use. Every generator page says this because it is true on every page.
- Symbols, not numbers. Generating an EAN/UPC barcode does not allocate or license the GTIN inside it (that is GS1's role), and rendering an ISBN barcode does not register an ISBN (national ISBN agencies). The retail pages state this prominently.
- Deliberate omissions. No control characters or FNC4 Latin-1 in Code 128, no mod-43 optional check or full-ASCII extension in Code 39, no EAN-5 price add-on on ISBN barcodes, no bearer bars on ITF-14 downloads — each stated on its page with the reason.
- Local processing. Inputs never leave your device; there is nothing server-side to verify or log.
Common misreadings
- "Valid" means structurally valid. Right length, right characters, a consistent check digit — a property of arithmetic. Whether the number is licensed is a separate question the math cannot answer; see Do I need a GS1 barcode?
- A check-digit mismatch is a report about the whole number. The message names the digit the arithmetic requires, but the mistake is as likely to be in one of the data digits as in the last one. Fix the number, or enter the data digits alone to have the check digit computed.
- Twelve digits are not always a GTIN-12. In the bulk tool's auto mode a 12- or 13-digit line is read as a complete number; if your column is data digits awaiting a check digit, choose data-only. The table above shows the same line read both ways.
- A zero-led reading is not a mismatch. A UPC-A and the EAN-13 with a leading zero are the same printed symbol, so the comparison accepts that one pair of spellings and nothing else.
- A passed decode is not a scan test. It certifies the generated file — the SVG's pixels, the PNG's canvas — not ink, substrate, scaling, contrast or quiet zones after printing. A physical production sample must still be scanned.
- The code-set guidance is advice. The Code 128 analysis tells you what your characters force; the renderer performs the optimisation inside the symbol.
- The rendering target is not print advice. It sizes the canvas the label tool embeds in its PDF. This site publishes no resolution or size tables beyond the figures cited above.
Every figure on this page is recomputed from the engines each time the site is built.