Printing a QR code so it actually scans
A QR code that scans perfectly on a screen can fail completely on paper, and the discovery normally happens after a thousand copies have been delivered. There are four ways it goes wrong, all of them avoidable in the artwork, none of them obvious.
Size, in millimetres
The rule the print trade actually uses is that a code needs to be about a tenth of the distance it will be read from. A code scanned at arm’s length — say 250mm — wants to be around 25mm across. A poster read from three metres wants 300mm.
Underneath that is the number that matters: each individual square in the pattern, called a module, needs roughly 0.6mm to survive ordinary printing and an ordinary phone camera. So the minimum size is not a fixed figure, it is the module count multiplied by 0.6mm — and the module count depends on how much the code carries. A short link produces a 33-module pattern, which wants about 25mm including its border. A long destination encoded directly can push past 57 modules, which needs about 40mm to do the same job.
Reported independently on both a design forum and a print forum, the practical floor for a small code is that around 12mm reliably fails, 13mm is marginal, and 15mm and above is safe for a short link. Below about 15mm you are relying on a good camera and good light, and a leaflet is read in neither.
The reason to prefer a short destination is now arithmetic rather than aesthetics: a shorter link is a smaller pattern is a smaller printed square. This is also why our resolve host is nine characters. It sits inside every code we generate, and its length sets the grid for all of them.
The border is part of the code
The empty margin around a QR code is called the quiet zone, and it is specified as four modules wide. It is not padding and it is not a design choice — a scanner uses it to find where the pattern begins. Crop it, place the code hard against a coloured panel, or let a photograph run underneath it, and readers that were working will start failing intermittently, which is the worst way for this to fail because it passes your test and fails your customer’s.
Designers ask how to remove that border more often than almost anything else about QR codes. The answer is that you cannot; you can only make it the same colour as what surrounds it.
A logo destroys data, and something has to pay for it
QR codes carry error correction, which is why a code with a coffee ring on it still works. There are four levels, and the highest recovers roughly 30% of the pattern.
A logo in the middle is not sitting on empty space. It is covering real modules and destroying the data underneath, and only the highest level recovers enough for the code to survive that once the losses from printing and camera noise are added on top. Place a logo on a code encoded at a middle level and you get artwork that scans on your monitor, scans off your office printer, and fails on the leaflet stock in a pub.
So the rule is: if there is a logo, the code must be encoded at the highest error correction level, and the logo should cover no more than about a quarter of the pattern. The 30% figure is a theoretical ceiling, not a target — spend it all and there is nothing left for the print process.
This is worth checking on whatever tool you use, because most leave it to you. One offers it as a checkbox at the download screen, one states it is always at maximum, and one recommends a middle level in a help article. Ours re-encodes the code at the highest level the moment a logo is added and says so on screen, which is a single line in the renderer and the difference between a print run working and not.
Contrast, and the colours that quietly fail
Scanners read light against dark, so the pattern needs real contrast against its background — a ratio of at least 4:1, and more if it is going onto anything textured. Two specific traps:
- Inverted codes. Light modules on a dark background are read by some phones and not others. If the brand demands it, test on an old Android as well as a current iPhone.
- Gradients. They look excellent on screen and are the single most common cause of a code that decodes in the design tool and not on paper. We found this the hard way: when we exposed gradients in our own editor, decode-testing the exports produced 285 failures, every one of them a gradient, caused by each module receiving its own full gradient rather than sharing one across the code. It was invisible on screen and fatal on paper.
The file to send
Send vector — PDF or EPS. Both scale from a business card to a pull-up banner without softening, and both are what a printer would rather receive. SVG is vector too and is the right choice for the web. PNG and JPG are raster: fine for a screen, a gamble in print, and JPEG compression actively damages the hard edges a scanner is looking for.
One thing worth knowing about export, because we shipped it broken and did not find out for a long time: our PDF export returned an error on every code from the day the feature was built, because the library reads font metrics from disk at runtime and the build could not see that read. Nothing about testing locally would have caught it. Every download now decodes the finished file before handing it over, and artwork that does not scan is refused with a plain reason rather than delivered.
Test the printed object, not the file
Before committing to a run, print one at final size on the actual stock, and scan it with a phone that is not yours, in the light the thing will really be read in. Matte and uncoated stock scatter more than a screen; laminate can throw a reflection straight back at the camera; a code on a curved surface like a cup loses geometry that no error correction level will recover.
And check where it is going to be. A code above head height on a wall, behind glass with a light source opposite, or on a menu in a dim restaurant is a different problem from the same code on a flyer. The most common outcome of all is not a code that fails — it is a code nobody can comfortably reach.
The one that is not about artwork
Everything above is about whether the pattern can be read. The other way a print run is wasted is when the pattern reads perfectly and the destination behind it has been switched off, which is a subscription question rather than a design one. It is worth settling before you print, not after: what each vendor does when you stop paying, and whether the code you already have can be repointed at all.