How to Make a QR Code That Always Scans: Size, Contrast and Error Correction
We generated QR codes, covered them with logos, lowered the contrast, shrank them and removed the margin, then tried to decode them. Here is what makes a QR code reliable and what quietly breaks it.
A QR code on a flyer, a menu or a parcel has one job: to open the right thing the moment someone points a phone at it. When it fails, people rarely try twice. Most failures come from a handful of design decisions, and you can test all of them before printing. We generated codes with the same library our QR Code Generator uses and tried to read them with two open-source decoders, ZBar 0.23 and OpenCV 5.0.
How a QR code stores data
The QR code was developed by Denso Wave in Japan in 1994 and is standardised as ISO/IEC 18004 (latest edition 2024). It is made of small squares called modules. The smallest version has 21 × 21 modules; each of the 40 versions adds four modules per side, up to 177 × 177. The three large squares in the corners tell the scanner where the code is and how it is rotated.
Part of every code is redundancy (Reed–Solomon error correction), so a damaged or dirty code can still be read. You choose how much:
| Level | Data that can be restored | Typical use |
|---|---|---|
| L | about 7% | Clean screens, very long content |
| M | about 15% | The usual default for print and screens |
| Q | about 25% | Outdoor use, rough or curved surfaces |
| H | about 30% | Codes with a logo, harsh conditions |
The standard also requires a quiet zone: a blank margin four modules wide around the code. As our tests show, it matters more than it looks.
Longer content means denser codes
The more characters you encode and the more error correction you choose, the more modules the code needs. We encoded four typical contents:
| Content | Characters | L | M | Q | H |
|---|---|---|---|---|---|
| Homepage URL (https://omid57.eu/) | 18 | 25 | 25 | 25 | 29 |
| Page URL (…/en-US/tools/qr-code-generator) | 47 | 29 | 33 | 37 | 41 |
| The same URL with four UTM tracking parameters | 128 | 41 | 49 | 53 | 61 |
| Wi-Fi login (network name and password) | 54 | 33 | 33 | 37 | 41 |
The tracking parameters pushed the code at level M from 33 to 49 modules per side. Printed at the same size, every module becomes about 28% smaller, because the width is shared by 57 instead of 41 module widths (quiet zone included). A short URL is the easiest way to a robust code.
How big does a QR code need to be?
What decides whether a code scans is how many camera pixels each module covers. We shrank codes until each module was a given number of pixels wide, blurred them slightly like a camera lens, and tried to decode them:
| Pixels per module | 25 × 25 code | 33 × 33 code | 49 × 49 code |
|---|---|---|---|
| 2 | not read | not read | not read |
| 2.5 | ZBar only | not read | ZBar only |
| 3 | read by both | read by both | read by both |
| 4 | read by both | read by both | read by both |
Both decoders needed about three pixels per module. For the person scanning, that means: if the modules are twice as big, the code can be read from twice as far away, and a denser code must be scanned from closer. You can calculate the module size of your print:
module size = printed width ÷ (modules per side + 8)
3 cm wide, 33 × 33 code: 30 mm ÷ 41 ≈ 0.73 mm
3 cm wide, 49 × 49 code: 30 mm ÷ 57 ≈ 0.53 mm Whatever size you choose, print a proof and scan it from the distance at which people will actually stand, for example across a table or from the pavement in front of a shop window.
Logos: how much can you cover?
Error correction lets a code survive damage, which is why many designs place a logo in the middle. We covered the centre of the 47-character URL code with a blank square of increasing size and checked when decoding failed:
| Level | Restorable data | Largest centre area that still scanned |
|---|---|---|
| L | about 7% | 3% of the code area |
| M | about 15% | 7% |
| Q | about 25% | 12% (OpenCV: 15%) |
| H | about 30% | 18% |
In practice you can cover only about half to two thirds of the nominal percentage: a logo also cuts codewords partly, and the nominal value is the best case. If you add a logo, choose level H, keep the logo well below 15% of the area and never touch the three corner squares. Our generator does not add logos; if you place one in an image editor, generate the code at level H and test the result.
Contrast and colour
On clean digital images, both decoders read even very pale codes. Photos taken by a camera are different, so we added sensor noise, a slight blur and light falling to 65% across the code, and ran each test ten times:
| Grey value of the dark modules | Contrast to the white background | ZBar | OpenCV |
|---|---|---|---|
| 0 (black) | 100% | 10 of 10 | 8 of 10 |
| 64 | 75% | 10 of 10 | 10 of 10 |
| 96 | 62% | 7 of 10 | 7 of 10 |
| 128 | 50% | 1 of 10 | 9 of 10 |
| 160 | 37% | 0 of 10 | 9 of 10 |
| 192 | 25% | 0 of 10 | 0 of 10 |
Keep the dark modules really dark: around 75% darker than the background was reliable for both decoders. What counts is brightness, not colour. Navy or black on white is ideal; pure red on white is only about 66% darker and already borderline; light blue (about 33%) and yellow (about 21%) on white are not suitable.
The quiet zone is not optional
We placed codes on a busy black-and-white pattern, with a blank margin of 0, 1, 2 or 4 modules, on ten different random backgrounds each:
| Quiet zone | ZBar | OpenCV |
|---|---|---|
| 0 modules | 8 of 10 | 0 of 10 |
| 1 module | 10 of 10 | 10 of 10 |
| 2 modules | 10 of 10 | 9 of 10 |
| 4 modules (standard) | 10 of 10 | 10 of 10 |
Without any margin, OpenCV failed every time. Our generator always adds the standard four-module margin. Don’t crop it away in your layout, and keep text, photos and patterns out of it.
Static codes never expire
Our generator creates static codes: the content itself, such as the URL, the Wi-Fi details or the email address, is stored in the pattern, so the code works forever without any service behind it. So-called dynamic codes from some providers contain only a short link to the provider, which then forwards visitors; if the subscription ends, every printed code stops working. For printed material, a static code that points to an address on your own domain gives you both: it never expires, and you can change where it leads with a redirect on your website.
Security: scan with care
Nobody can read a QR code with their eyes, which makes it ideal for hiding a harmful link. In December 2023 the US Federal Trade Commission warned that scammers stick their own codes over real ones, for example on parking meters, and send codes by email or text message with urgent requests. Before you open a scanned link, check the address your phone shows; don’t scan codes from unexpected messages; and check from time to time that nobody has covered your own printed codes with a sticker.
Checklist before printing
- The content is as short as possible, with no unnecessary tracking parameters.
- Level M for normal use; Q or H outdoors, on curved or rough surfaces or with a logo.
- Dark modules on a light background with strong contrast, never inverted.
- The four-module quiet zone is complete and free of text and graphics.
- SVG for print, because it scales without blurring; PNG for screens and documents.
- A short line of text next to the code says where it leads, for example “Menu: example.com/menu”.
- The proof has been tested with at least two different phones at the real distance and in the real light.
Tools used in this guide
Frequently asked questions
Which error correction level should I choose?
Level M suits most codes on paper and screens. Choose Q or H for codes outdoors, on curved or rough surfaces or with a logo, and L only for very long content shown on a screen.
Do QR codes expire?
Static codes, like the ones our generator creates, never expire because the content is stored in the code itself. Dynamic codes from some services depend on that service and stop working when it is discontinued or the subscription ends.
Can I put a logo in the middle of a QR code?
Yes, with level H. In our test, a blank area of up to 18% of the code still scanned at level H, but only 7% at level M. Keep the logo well below 15%, leave the corner squares untouched and test the printed result.
Why doesn’t my QR code scan?
The most common causes are a code that is too small or too dense for the distance, low contrast, inverted colours, a missing quiet zone, reflections on glossy material and curved surfaces such as bottles.
Is a Wi-Fi password in a QR code safe?
The password is stored as plain text in the code, so anyone who scans or photographs it can read it. Use Wi-Fi codes for guest networks and change the password when necessary.
Is my data sent anywhere when I create a code?
No. Our QR code generator creates the code in your browser; the content you enter is not sent to our server.