How to generate QR codes that actually scan when printed
Most QR codes that fail in the field fail for three avoidable reasons: raster output, too little quiet zone, and poor contrast. What to do instead, with runnable examples.
A QR code either scans or it does not, and when it does not you usually find out after printing several hundred of them. Almost every field failure comes from one of three causes, and all three are decided when you generate the code.
1. Use vector, not raster
The most common failure is a PNG generated at one size and printed at another. Scale a raster code up and the module edges blur; scale it down and modules merge. Either way the scanner loses the grid.
Ask for SVG:
curl "https://twotic.dev/v1/qr/qr?data=https://example.com&scale=8" \
-H "Authorization: Bearer $TWOTIC_KEY"Vector output stays sharp at any dimension, so the same code works on a business card and a poster. It is also small enough to inline directly into a document or an email — no image hosting, and no broken link when someone moves the asset.
If you need a raster at the end, render the SVG at the final print size rather than resizing a bitmap.
2. Leave the quiet zone alone
The blank margin around a QR code is not padding. Scanners use it to find where the code begins, and a code butted up against text or a border frequently will not be detected at all — the scanner never locates it to begin decoding.
The specification calls for four modules of clear space. That is the default here, and the reason to change it is almost always to make it larger:
?data=https://example.com&margin=4 # correct
?data=https://example.com&margin=0 # looks tidier, scans badlyThis one is worth being stubborn about with designers. A code with no margin looks better in the layout and fails in the world.
3. Keep contrast high and the polarity right
Dark modules on a light background. Not the reverse.
Inverted codes — light modules on dark — are decodable in principle and unreliable in practice, because many scanner implementations assume the standard polarity. Low-contrast colour pairs fail the same way, especially under the mixed lighting where codes actually get scanned.
You can brand the code, within limits:
?data=https://example.com&dark=%230e0e14&light=%23ffffffA very dark brand colour on white is safe. A mid-tone on a tinted background is a gamble you will lose some percentage of the time, and you will not find out which percentage until it is printed.
WiFi codes: escape the payload
A code that joins a network encodes a structured string, and the structure has escaping rules that are easy to get wrong by hand:
curl "https://twotic.dev/v1/qr/qr/wifi?ssid=Cafe%20Guest&password=hunter2;x&encryption=WPA" \
-H "Authorization: Bearer $TWOTIC_KEY"A semicolon or a comma in the SSID or password terminates a field early if it is not escaped. The result is not an error — it is a code that scans cleanly and joins the wrong network, or fails to join with no explanation. The endpoint handles the escaping, which is the main reason to use it rather than building the string yourself.
Keep the payload short
Content length drives how dense the grid becomes. A long URL produces a code with many small modules, which needs more physical size and better print quality to stay readable.
The practical limit here is roughly 213 bytes, and longer content is refused rather than silently truncated into something unscannable. But well before that limit, shorter is better:
- Use a short link rather than a full URL with tracking parameters.
- Drop
https://only if you have tested that your audience's scanners still resolve it — many do not. - Encode an identifier and resolve it server-side, rather than encoding the data itself.
Dynamic codes are a redirect, not a feature
If you need to change where a printed code points, encode a URL you control and redirect it on your side. That is all any "dynamic QR" product does underneath. Knowing that is worth something: it means you do not need a vendor for it, and it means the code itself is permanent while the destination is not.
A checklist before you print
- [ ] SVG, rendered at final size — not a resized bitmap.
- [ ] Quiet zone of four modules or more.
- [ ] Dark on light, with real contrast.
- [ ] Payload as short as you can make it.
- [ ] Scanned from an actual print, at the actual size, on at least two phones.
That last one catches everything the first four miss. Print one before you print a thousand.
Error correction is not free insurance
Every QR code carries redundancy, at one of four levels — L, M, Q and H — recovering roughly 7%, 15%, 25% and 30% of the code respectively. The instinct is to pick H and stop worrying.
That instinct is usually wrong, because the redundancy is stored inside the same code. Raising the level does not add a margin around your data; it adds data, which needs more modules, which makes every module smaller at a fixed physical size. Past a point you are trading the scanner's ability to resolve a module for tolerance of damage that will never occur — and a code printed on a clean surface behind glass is not being damaged.
The level should follow the environment, not the anxiety:
- L or M for screens and clean print. A code on a web page, a slide, an invoice or a business card is never obscured. Use the modules for size instead.
- Q for anything handled. Menus, packaging, loyalty cards — surfaces that get fingerprints, creases and wear.
- H when something covers the code, which in practice means a logo in the centre. This is the one case where the extra redundancy is doing exactly the job it was designed for.
That last case has a rule that gets broken constantly: a centred logo may cover no more than about 25% of the code's area, and it must be centred. The three large squares in the corners are the finder patterns — a scanner locates and orients the code by them before it reads anything. Cover one and there is nothing to recover, at any error-correction level, because the scanner never gets far enough to try.
What you can build with this
A guest WiFi card that works the first time. Generate the code with a properly escaped payload, print it, put it on the wall. This is the single highest-gratitude-per-hour thing on this list, and the escaping is the whole reason it works when the ones made in a random online tool do not.
Table or room codes with a redirect in the middle. Point the code at a URL you control, and redirect from there. The printed thing becomes permanent and the destination stays editable, which is the difference between a menu you can update and a reprint.
Event badges generated in bulk. One code per attendee, each pointing at a unique URL, rendered as SVG into a printable sheet. Vector output matters more here than anywhere else, because badges get scaled by whatever prints them.
A pre-print checker. Take a code, render it at the intended physical size, and warn about quiet zone, contrast and payload length before anything is printed. Every one of those failures is cheap to catch now and expensive to catch later.
Related reading
- QR Codes — the generation and WiFi endpoints, including the SVG output this guide recommends.
- How to build link previews that don't break — the other half of sharing a URL: what people see after they scan it.
Frequently asked
Which error-correction level should I use?+
L or M for screens and clean print, Q for anything handled like menus or packaging, and H only when a logo covers part of the code. Higher levels add modules rather than margin, so at a fixed size each module gets smaller — which can cost more scans than the redundancy saves.
Can I put a logo in the middle of a QR code?+
Yes, if it is centred, covers no more than about 25% of the area, and you raise error correction to H. Never let it touch the three corner squares — a scanner uses those to find and orient the code, so covering one makes it unreadable regardless of error correction.
Why does my QR code work on screen but not in print?+
Almost always size or margin. A code that scans on a monitor may be physically too small once printed, or may have been placed tight against surrounding artwork. Print a test at the real size and scan it from the distance people will actually use.
Can I put a logo in the middle?+
Error correction tolerates roughly 15% damage, so a small centred logo usually survives. It eats the margin you would otherwise have for smudging and folding, though — if the code is going somewhere it will be handled, keep the centre clear.
What size should a printed code be?+
A common rule is a tenth of the scanning distance: about 3cm for a code scanned at 30cm, larger for a poster read from across a room. Longer payloads need more size because the modules get smaller.