Decode verification: how the badge is earned

Every decorated code on this site ends in one of two states: a "Verified scannable" badge with the downloads unlocked, or a warning with the downloads locked. This guide explains the loop that decides between them — what is rasterised, decoded and compared, and how 3 results become one verdict. Every engine figure below is read from the engine at build time; the 3 example runs further down are the real loop, executed when this page was built.

What the badge claims

The badge is a statement about artwork: this exact picture — frame, heart glyphs, photo ring, quiet zone — was turned into pixels, a real QR decoder read a code out of those pixels, and the bytes it read were identical to the content you typed. The rules on the methodology page make a scan failure unlikely; this check makes one visible before anything is downloaded.

The loop: rasterise, decode, compare

After each render, your browser draws the finished SVG artwork onto a white canvas, scaled to fit a square of a fixed size and centred in it. The decoder, jsQR, is then run over that canvas's pixels with inversion attempts switched off, so only a dark-on-light reading can succeed. If the decoder finds a code, its output is compared with the requested content byte for byte. That sequence runs 3 times, once at each of the engine's verification raster sizes: 800, 1200, 1600 px.

Each run ends in one of the engine's statuses. Verified means a code was found and its bytes matched. Undecodable means no code was detected in that raster. Mismatch means a code was found, but it decoded to different content. Error covers the browser-side failures — a canvas that could not be created, an image that failed to load, a raster that could not be drawn — and is reported as "cannot verify", never as a pass.

Why 3 sizes and not one

A single fixed raster can produce a false negative through sampling resonance: a render can fail at exactly one raster size and decode cleanly at the others. The engine measured this on a halftone torture render that failed at exactly one raster size and decoded at the others. One raster cannot be trusted to flip a verdict on its own.

The sizes are spread across the realistic scan-size range: 800 px covers module-level detail for the plain styles, 1200 px keeps the halftone ring's photo noise out of the authoritative cell centres (measured: per-pixel noise that fails at a smaller raster decodes at this one), and 1600 px bounds the fine end. The badge is earned when at least 2 of the 3 rasters decode to an exact byte match — the 2-of-3 rule — and the result names which sizes passed.

The comparison is byte-exact

"Matches" is not a loose word here. When the decoder exposes its raw byte stream, the engine encodes your content as UTF-8 and compares length and every byte; only when no byte stream is available does it fall back to string equality. There is no trimming, no case folding and no tolerance. The table shows the comparison function's answers for one original, fictional message — Look under the blue flowerpot. — against 5 decoded strings, computed when this page was built.

Decoded string Answer
The identical text — Look under the blue flowerpot. match
The identical text, compared through the decoder’s raw byte stream — Look under the blue flowerpot. match
The same text with one trailing space — Look under the blue flowerpot. no match
The same text in capitals — LOOK UNDER THE BLUE FLOWERPOT. no match
The same text without its full stop — Look under the blue flowerpot no match

The strictness is deliberate: a comparison that forgave a changed letter would also forgive a changed digit in a phone number. Reveal links guard a related hazard in a different way: some scanners change the case of what they read, and base32 survives that; see the message keepsakes guide.

How 3 results become one verdict

The combining rule is pure and ordered. If at least 2 rasters are verified, the verdict is verified and the message lists the passing sizes. Otherwise a mismatch anywhere is reported first, because a render decoding to different content is never safe regardless of what the other rasters did. Then an undecodable result is reported, with the count of sizes that did decode and the minimum required. Only when no raster was undecodable and none mismatched — every raster that did not match failed on the browser side — is a browser-side error reported, even if some rasters, fewer than 2, had decoded. The resulting message — naming the sizes that passed — is what the badge or warning reports; the examples below show it.

Real runs, executed when this page was built

The keepsakes below are the engine-rendered, fictional examples from their own tool pages, one per style family. When this page was built, each went through the loop above — rasterised at 800, 1200, 1600 px, decoded with jsQR, byte-compared to its payload — with the same sharp-based rasteriser the test suite uses. Nothing here was typed in; if an example stopped verifying, the text under it would say so.

Valentine — Heart modules. Version 8 at 49×49 modules, 57×57 with the 4-module quiet zone. It encodes:

Every love story is beautiful, but ours is my favorite. Happy Valentine’s Day, A.

Build-time verdict: Verified scannable at 800, 1200, 1600 px (3 of 3 rasters) — decoded back to your exact content.

Share your photos with us

Wedding — Floral frame. Version 5 at 37×37 modules, 45×45 with the 4-module quiet zone. It encodes:

https://example.com/album/ella-and-sam

Build-time verdict: Verified scannable at 800, 1200, 1600 px (3 of 3 rasters) — decoded back to your exact content.

Photo keepsake — Photo-woven. Version 3 at 29×29 modules, 37×37 with the 4-module quiet zone. It encodes:

https://example.com/us

Build-time verdict: Verified scannable at 800, 1200, 1600 px (3 of 3 rasters) — decoded back to your exact content.

The bare styles make the arithmetic visible, because their artwork is the code and its quiet zone and nothing else, so it fills the raster square exactly. The heart-module example spans 57 modules a side, which gives each module 14.0, 21.1, 28.1 px at the 3 sizes; each heart covers 0.97 of its cell — large enough, by measurement, that a scanner's sampling grid still reads the cell as decisively dark. The photo-woven example spans 37 modules a side, giving 21.6, 32.4, 43.2 px per module, of which only the central 0.5 of the cell side — 10.8, 16.2, 21.6 px — is pure module colour: the margin a decoder sampling near cell centres actually has. The framed example is not square; the whole composite is scaled to fit the raster and the decoder must find the code inside it — the finished artwork is what is verified, not the bare code.

Badge, warning, locked downloads

Verification runs after each render. A verified verdict shows the "Verified scannable" badge and unlocks the downloads. Any other verdict shows a clear warning and keeps the downloads locked, so an unverified render cannot leave the page as a finished keepsake.

The gates that run before verification

Verification is the last check, not the only one, and several failures never reach it. The styles that redraw modules — hearts and photo-woven — refuse any model not encoded at error correction level H, the level that leaves roughly 30% recovery for decoration to spend. The artistic engine rejects a foreground and background pair measuring below 4.5:1 in WCAG contrast, and rejects an inverted pair, before any artwork exists, so a pale heart colour never reaches the decoder. The halftone style caps the symbol at version 4, because denser symbols shrink the pure cell centres below what a decoder can sample. The 4-module quiet zone is always drawn and never covered by frame art. Each is a measured rule of this engine, explained in why decorated codes still scan, the heart-module guide and the photo halftone guide. Verification exists for whatever those rules did not anticipate.

The same loop, run automatically

The engine's test suite runs the identical render-rasterise-decode loop on every style — at several raster sizes, rotated, and after lossy JPEG re-compression — and requires the decoded bytes to match exactly. The measured limits are pinned by those tests, so a change that breaks scannability fails the build instead of shipping.

What verification cannot promise

On-screen verification proves the artwork decodes cleanly at screen resolution. It cannot see your printer, your paper, or the phone that will do the scanning. Print at least 2 × 2 cm for arm's-length scanning, keep the quiet zone uncropped, and scan a test print with a real phone before the moment that matters; the printing and scanning guide works through the sizes. If a verified code will not scan in print, that is exactly the report we want — see the contact page; confirmed issues are fixed in the engine and locked in with a new test.

Verification also says nothing about what a phone does with the bytes once it has them. A code containing bare text carries no scheme, so a phone has nothing to act on: Apple's Camera and Google's ML Kit recognise links, phone numbers, email addresses, contact cards, calendar events and Wi-Fi joins, and no plain-text type. Faced with bare text, an iPhone offers to copy or search it and Google Lens simply runs a web search; Samsung phones and dedicated scanner apps do display it, but a keepsake cannot depend on which phone opens it. A verified offline note is a correctly encoded message, not a promise that it will be shown — which is why message keepsakes offer the reveal link, and why, on a framed keepsake with no caption of your own, the message is also printed under the code as the caption.

Three common misreadings of a result

  • "It verified, so I can crop the white margin." The 4-module quiet zone was part of the pixels the decoder read. Cropping it afterwards produces artwork that was never verified.
  • "It verified, so the phone will show my words." The badge proves the bytes decode; what happens next is a property of the phone, not of the code.
  • "A 2-of-3 badge is a weaker badge." It is the rule working as designed: one raster missed through resonance, the others decoded to the exact bytes, and the message said which. Fewer than 2 matching sizes is not verified, and the message says so.

Verification FAQ

What does "Verified scannable" actually prove?

That the finished artwork — frame, hearts or photo included — was rasterised in your browser at 3 sizes (800, 1200, 1600 px), that a real QR decoder (jsQR) read a code in at least 2 of those rasters, and that the bytes it read were identical to the content you entered. It proves the artwork at screen resolution — not your printer, paper or phone.

Why does the badge sometimes say "2 of 3 rasters" instead of 3 of 3?

Because a single raster size can fail through sampling resonance while the others decode cleanly — the engine measured a halftone torture render that failed at exactly one raster size and decoded at the others. The badge is earned at 2 exact matches and the message lists which sizes passed, so a 2-of-3 result is a verified render whose one miss is reported rather than hidden.

What is the difference between "no QR code was detected" and "decoded to different content"?

The first means the decoder found no readable code in that raster. The second means it found a code and read it, but the bytes were not the ones you entered. A mismatch is reported ahead of every other failure, because a render that decodes to different content is never safe to print, whatever happened at the other sizes.

Why are the downloads locked until the badge appears?

So that an unverified render cannot leave the page as a finished keepsake. Verification runs after each render; only a verified result shows the badge and unlocks the downloads, and anything else shows a warning and keeps them locked.

Does verification try reading the code inverted, light on dark?

No. The decoder runs with inversion attempts switched off, so the badge can only be earned by a dark-on-light reading. The artistic engine already rejects inverted colour pairs, and pairs below 4.5:1 in WCAG contrast, before anything is rendered — verification is the last gate, not the only one.

Does a verified badge guarantee the printed code will scan?

No. It guarantees the artwork itself decodes cleanly at screen resolution. Print at least 2 × 2 cm for arm’s-length scanning, keep the quiet zone uncropped, and scan a test print with a real phone before the moment that matters.

Every render is decode-verified in your browser before it can be downloaded. The measured rules behind each style — what may be decorated, what never is, and the limits found with a real decoder — are documented on the methodology page; the other guides take each rule in turn.