A QR code that looks sharp on a phone can fail in print: the modules are too small for the scanner, the quiet zone got cropped, or contrast disappeared on dark or glossy stock. This note is for developers generating codes for cards, labels or flyers.

The figures below come from DENSO WAVE, the inventor of QR Code, whose public documentation matches the model in ISO/IEC 18004 (first published as an ISO standard in 2000; current edition 2024). I am not quoting unpublished tables from the standard itself.

Size is module size times module count

A QR Code is a grid of square modules. Once you know the version, printed size is:

printed size = (modules + 2 × quiet-zone modules) × module size 

DENSO WAVE's outline of the specification gives the grid sizes: Version 1 is 21 × 21 modules, growing by four modules per side up to Version 40 at 177 × 177. Version V is 21 + 4 × (V − 1) modules on a side. The payload, not a style option, usually picks the version. A short HTTPS URL often fits in Version 2 or 3; a long tracking URL, vCard or Wi-Fi string can jump several versions. Prefer a short, stable URL if the print area is tight.

The quiet zone is four modules, on every side

DENSO WAVE is direct: "QR Code requires a four-module wide margin at all sides of a symbol." That is a clear area with nothing printed in it — no logo, crop mark or background pattern. Those four modules on each side add eight modules to the width, so a Version 3 symbol (29 modules of data) occupies a 37-module square. If a layout tool or a margin: 0 export trims that margin, readers may fail.

A worked example from the official docs

DENSO WAVE encodes 50 alphanumeric characters at error-correction level M. That requires Version 3 (29 modules); Version 2 at level M only holds 38 alphanumeric characters. They then print on a 400 dpi printer with a 4-dot module:

module size = 25.4 mm/inch ÷ 400 dpi × 4 dots/module = 0.254 mm/module data area = 29 × 0.254 mm = 7.366 mm full area = 7.366 + (0.254 × 8) = 9.398 mm 

The reserved square, including the quiet zone, is 9.398 mm on a side. That is a printer-stable size for a machine that can resolve 0.254 mm modules — not, on its own, a comfortable size for a phone camera.

Module size is limited by the printer and the scanner

DENSO WAVE recommends that each module be made of four or more printer dots, so the cell stays square when the head or paper feed varies. At 600 dpi, a 4-dot module is 0.17 mm; at 360 dpi it is 0.28 mm; at 300 dpi thermal, 0.33 mm; at 200 dpi thermal, 0.50 mm. A Version 1 symbol at that 600 dpi size is 21 × 0.17 mm = 3.57 mm before the quiet zone — a printer floor, not a target for a handheld camera.

Each scanner also has its own readable module-size limit. DENSO WAVE lists industrial "standard type" readers around 0.25 mm, and camera-type readers and phone decode software as "variable according to lens." Size the symbol for the scanner you actually have, and print it as large as the layout reasonably allows.

For phone scanning, start from the space you can give the code, then test. If you reserve a 22 mm square, quiet zone included, for a Version 3 symbol (37 modules), each module is 22 / 37 ≈ 0.59 mm — well above the 4-dot printer floor. A common print-industry rule of thumb is to make the symbol about one tenth of the intended scan distance — a starting point to test, not a figure from ISO/IEC 18004.

Error correction changes the version, not just robustness

QR Code uses Reed-Solomon error correction. DENSO WAVE states the approximate proportion of codewords that can be restored, and notes that level M is the one most frequently selected: L ≈ 7% (clean environment, large amount of data), M ≈ 15% (the usual default), Q ≈ 25% and H ≈ 30% (dirtier environments).

Raising the level does not protect a code that is printed too small. It consumes capacity, which can bump the symbol to a higher version and shrink every module if you keep the same printed square. For a card or label that will be handled or scuffed, Q or H is reasonable if the modules stay large enough. For a short URL on a clean flyer, M is the documented default. If you punch a logo out of the centre, keep the finder and alignment patterns clear, keep the quiet zone intact, and test the result.

Contrast, finish and file format

Readers distinguish modules by the difference in reflected light between dark and light cells. The reliable default is dark modules on a light, opaque background. DENSO WAVE notes that a symbol on a transparent bag needs a white background behind it, and that a glistening surface can interfere with reading. Low-contrast palettes, inverted (light-on-dark) codes, busy backgrounds and laminate glare are the usual failures; on dark or metallic stock, put the code in a solid light patch that includes the quiet zone.

Export SVG or PDF when you can. Vector modules stay sharp at any print size, and a 4-module border in the file is a 4-module border on paper. If you must ship a PNG, treat scale or width as pixels per module, not as "the size of the code." Give the raster several pixels per module, then size that bitmap to the physical millimetre size at 300 or 600 DPI. Do not stretch a 128-pixel PNG across a 30 mm square, and do not drop the quiet zone to zero.

Generate it with the right margin and ECC

Python, with segno:

import segno qr = segno.make("https://example.com/event", error="M") # border is the quiet zone in modules; 4 is the required margin qr.save("qr.svg", scale=10, border=4) # scale is pixels per module in a raster export, not millimetres qr.save("qr.png", scale=10, border=4) 

Node.js, with the qrcode package:

import QRCode from "qrcode"; const url = "https://example.com/event"; await QRCode.toFile("qr.svg", url, { type: "svg", errorCorrectionLevel: "M", margin: 4, // quiet zone in modules }); await QRCode.toFile("qr.png", url, { errorCorrectionLevel: "M", margin: 4, width: 512, // output pixels; prefer a multiple of (modules + 2×margin) }); 

A browser QR code generator is useful when you want to inspect the version, the quiet zone and a vector download before the symbol goes into a print file.

Test on the real object

Preview at 100% zoom is not a test. Print at the final size on the final stock, including any laminate, and scan with two phones in ordinary light at the real reading distance. If the code is on a card, keep it inside the safe area so trim cannot eat the quiet zone; a CR80 artwork checker will show that overlay on an ID-1 / CR80 card.

If a test scan is flaky, enlarge the modules, restore the four-module quiet zone, increase contrast, shorten the URL, then raise the error-correction level if the surface will take damage.

TL;DR

  • Printed size = (modules + 8) × module size. Version 1 is 21 × 21; each version adds four modules per side. Keep a four-module quiet zone on every side.
  • Four or more printer dots per module is the official floor; 0.17 mm at 600 dpi is a printer minimum, not a phone-scanning size.
  • Default to error-correction M. Dark on a light, matte, opaque patch. Prefer SVG or PDF, and test a real print with more than one phone.