Printing and scanning a keepsake
A keepsake code is finished twice: once on screen, where the engine renders it and your browser decodes it, and once on paper, where a phone must do the same under conditions the engine never sees. This guide covers the second half: the one working size rule behind every print readout on this site, why a longer message prints larger, what the PNG sizes mean, and where the Verified scannable badge stops making promises. Every figure below is computed by the engine when this page is built; the examples are original and fictional.
What the engine has already decided
Three printing decisions are fixed before you see a render. Every style that redraws modules — hearts and the photo halftone — encodes at error correction level H, and the engine refuses to render those styles over a lower level; a frame leaves the code untouched on its panel, so a framed code without heart modules may also carry level Q when the generator's opt-in smaller-code setting is chosen, the engine rejects anything below Q, and a render at either level must still pass decode verification before it can be downloaded. Finder and alignment patterns are always crisp classic squares; restyling alignment patterns broke decoding outright in testing, so the landmarks are never decorated. And the 4-module quiet zone is always rendered and cannot be switched off; in a framed code it sits inside the opaque clean panel, drawn above the frame art so the art can never cover it. The reasoning is in why decorated QR codes still scan.
The size a code must be printed at
The engine carries one working minimum for print, set with margin above the hard floor rather
than at it: a module, the smallest square in the code, must come out at least 0.5
mm wide on paper. Everything else is multiplication. A code's total width is its symbol size plus
the quiet zone on both sides — 4 modules each — and the minimum print width is
that total times 0.5 mm. The function that does this,
minPrintSize, is the one the generator calls for the readout under every render.
The gift-tag example, rendered by the engine when this page was built — a classic frame around an untouched code panel. It encodes a fictional note:
This one took months to find. I hope it makes you laugh as hard as Lisbon did. - M
Version 8, 49×49 modules, error correction H. With the quiet zone that is 57 modules across, so the engine's readout is: print at least 28.5 mm (1.12 in) wide.
That figure is the code panel alone. The frame art around it can be printed at whatever size suits the object, because it is drawn outside the panel and can never touch a module; what matters is that the panel, quiet zone included, measures at least the readout. The methodology page states the rule in rounder terms — print at least 2 × 2 cm for arm's-length scanning — and whichever of the two is larger governs: when the readout exceeds 2 × 2 cm, as it does for this gift-tag example, follow the readout.
Why a longer message prints larger
A QR code grows in fixed steps, called versions, as the content gets longer; between the first two rows below, one version step adds 4 modules to the side. Because every module needs the same 0.5 mm, a denser code needs more paper. Three fictional payloads, encoded at level H, as the generator encodes them by default:
| Content | Characters | Version | Modules (with quiet zone) | Minimum print width |
|---|---|---|---|---|
| A link | 36 | 5 | 37×37 (45 total) | 22.5 mm (0.89 in) |
| A short offline note | 45 | 6 | 41×41 (49 total) | 24.5 mm (0.96 in) |
| A long offline note | 154 | 12 | 65×65 (73 total) | 36.5 mm (1.44 in) — flagged oversized |
The third row trips a second rule. When the total module count passes
65, minPrintSize marks the result oversized; the engine's
source defines that threshold, in its own words, as the “Module count at which a printed keepsake
stops fitting the objects these codes go on (gift tags, cards).” The generator turns that flag into
a warning that the code needs 37 mm to scan reliably, larger than a typical gift
tag, and suggests a shorter message or a link; the warning rounds to whole millimetres, while the
readout line under the render keeps the one-decimal figure, 36.5 mm. The first row
shows why a link helps: a URL to a page holding the long text is short, so the code stays coarse;
a
reveal link keeps the message off every
server too.
Photo-woven codes print at 2× the width
The halftone style spends more print margin than any other. Each data cell is split into a small
grid; only the central 0.5 of the cell's side is painted in pure module colour,
because decoders sample near cell centres, and the ring around it shows the photo. The module a scanner
can rely on is therefore only that central fraction of the nominal one, so
minPrintSize divides the per-module minimum by that ratio, which multiplies the readout
by 2. The engine's photo example is a version
3 code — the style caps content at version 4, since
denser codes shrink those authoritative centres below what a decoder can sample — at
29×29 modules, 37 across with the quiet zone. As a plain
or framed code it would need 18.5 mm; as a photo-woven code the
readout is 37.0 mm. More in
photo halftone codes, explained.
PNG sizes, and what 300 DPI means
The engine's readout function, printSizeAt300Dpi, computes for any pixel size how
large a raster comes out when printed at 300 dots per inch, the resolution it is written for.
The generator's PNG picker offers 1024 px and 2048 px; the table gives the readout for each,
measured along the raster's long side:
| PNG size | Long side printed at 300 DPI |
|---|---|
| 1024 px | 3.41 in (86.7 mm) |
| 2048 px | 6.83 in (173.4 mm) |
Read the two readouts as different kinds of statement. The 300 DPI figure is descriptive: how big this file happens to come out if nothing scales it. The minimum print width is prescriptive: how big the code must be, whatever file carries it. The PNG the generator downloads is a browser rasterisation of the verified SVG, scaled so that its longer side measures the chosen pixel size; on a framed keepsake that side spans the whole composition, frame art included, and the code panel is only part of it, so the readout describes the raster rather than the panel. Printing a 1024 px file wider than 86.7 mm on its long side enlarges pixels; printing a 2048 px file at the minimum width discards resolution it did not need. The SVG download is vector art: the width and height written in the file are a nominal pixel size, not a print size, so the minimum print width still applies to it.
Contrast is measured, not eyeballed
Scanners binarise the image, so low contrast measurably hurts decoding. The engine computes the
WCAG contrast ratio of the two colours from their values rather than guessing; the threshold is
4.5:1. The base renderer warns below it; the heart-module and
photo-woven styles reject the pair outright and will not render. A framed code without heart
modules leaves the code itself unmodified on the clean panel in the renderer's default
dark-on-light colours, so there is no pair to choose; a framed code with heart modules renders
them through the same heart-module gate, in the heart renderer's default colour, which the
generator does not expose for change. Two fictional pairs show the gate: a deep red #9f1239 on white
#ffffff measures 8.02:1 and is accepted;
a pale pink #f9a8d4 on blush
#fff1f2 measures 1.65:1 and is refused.
Hearts add one more reason: each heart spans 0.97 of its cell so the cell still reads
as decisively dark, which only holds when the colour itself is. More in
heart-module codes, explained.
What the badge proves
After every render, your browser rasterises the finished artwork — frame, hearts, photo and all — at 3 sizes, 800, 1200, 1600 px, and runs a real QR decoder, jsQR, on each. The decoded bytes are compared with your exact content. The Verified scannable badge is earned when at least 2 of the 3 rasters match; anything else shows a warning and keeps the downloads locked. More than one raster is needed because of a measured effect called sampling resonance: a render can fail at exactly one raster size and decode cleanly at the others, so a single size could refuse a sound render. Badge, warning and locked downloads are covered in decode verification.
What verification cannot see
Everything the badge knows, it learned from rasters your browser drew: 3 images at 800, 1200, 1600 px, each decoded with jsQR and compared byte for byte with your content. Nothing in that loop touches paper. The engine holds no sample of the printer that will lay the code down, the paper it will land on, or the phone that will be pointed at it; its 0.5 mm module floor is a working minimum set with margin above the hard floor, not a reading taken from your setup. So the general guidance stays short whatever the style — print at least 2 × 2 cm for arm's-length scanning, or the engine's per-style readout when that is larger — keep the quiet zone uncropped, and scan a test print with a real phone before the moment that matters. The canonical statement of what verification cannot promise is on the methodology page. If a verified code will not scan in print, that is exactly the report wanted; the contact page explains how to send it, and confirmed issues are fixed in the engine and locked in with a new test.
What a scan shows: links and messages
Scanning cleanly and showing the right thing are different questions. A code containing bare text carries no scheme, so a phone has nothing to act on: Apple's Camera and Google's ML Kit both 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, so the message is the one thing the reader never sees. Samsung phones and dedicated scanner apps do display it, but a keepsake cannot depend on which phone opens it. This is why a message keepsake here defaults to a reveal link; on a framed keepsake, when the caption is left empty, the words are also printed under the code as its caption so they can be read by eye regardless, and a caption you type takes its place. The two modes are compared in message keepsakes and reveal links.
Common misreadings
- Cropping the quiet zone. The 4-module margin is part of the code, not padding. The engine always draws it and never lets frame art cover it; a trim into the clean panel removes something the decoder relies on.
- Treating the frame as the margin. The quiet zone lives inside the panel. Frame art outside it can be cropped or scaled; the panel cannot.
- Expecting bare text to display. An offline note decodes exactly like any other payload; what the phone then does with bare text is the dispatch behaviour above.
- Pale heart colours. A heart code is rejected below 4.5:1 rather than warned; a refused pair is a measurement, not a bug.
- Printing a photo-woven code at a framed code's size. The halftone readout is 2× the plain one, by construction.
- Reading the badge as a print guarantee. It is a decode of screen artwork at 800, 1200, 1600 px; only a real phone can test the print.
Printing and scanning FAQ
How small can a keepsake code be printed?
The engine's working minimum is 0.5 mm per module, so the floor is 0.5 mm times the code's total module count, quiet zone included. The gift-tag example on this page is 57 modules across and must be printed at least 28.5 mm wide; the generator shows this readout under every render. The methodology page gives the general rule as at least 2 × 2 cm for arm's-length scanning.
Why does the generator say my code needs more than a gift tag?
When the total module count, quiet zone included, exceeds 65, the engine flags the code as oversized and the generator warns that it needs more width than a typical gift tag, suggesting a shorter message or a link. A longer message encodes as a denser code, and every module still needs 0.5 mm on paper.
Does the "Verified scannable" badge mean the print will scan?
No. It proves that this exact artwork, rasterised in your browser at 800, 1200, 1600 px, decoded back to your exact bytes on at least 2 of those 3 sizes. It cannot see your printer, your paper or the phone that will scan it. Scan a test print with a real phone before the moment that matters.
Can the white margin be trimmed to fit a smaller tag?
No. The 4-module quiet zone is always rendered and cannot be disabled, and framed codes keep it inside the clean panel where frame art never covers it. Cropping into it removes something the decoder relies on; shorten the content instead if the code must be smaller.
Which PNG size should I download?
The generator's picker offers 1024 px and 2048 px. The engine's 300 DPI readout gives 86.7 mm to 173.4 mm for those sizes, measured along the raster's long side; on a framed keepsake the code panel is only part of that side. Those figures describe how large a raster happens to come out; the minimum print width is the separate, prescriptive figure, and whichever size is chosen, the code panel must be printed at least that wide. The SVG download is vector art: the width and height written in the file are a nominal pixel size, not a print size, so the minimum print width still applies to it.
Why must a photo-woven code be printed larger than a framed one?
A halftone cell carries its module colour only in the central 0.5 of its side, so the module a scanner sees is only that central fraction of the nominal one. The engine multiplies the minimum print width by 2: the photo example on this page would need 18.5 mm as a plain code and needs 37.0 mm as a photo-woven one.
Every render is decode-verified in your browser before a download is unlocked; the measured rules behind each style, and the limits of that verification, are set out on the methodology page. The other guides cover each style and the verification loop in the same terms.