What Breaks a QR Scan: Lab Results on Logos, Size and Blur
QR advice repeats the same rules: keep the logo small, print it big enough, use high contrast. We wanted numbers behind those rules, so we generated 480 codes and ran more than 20,000 decode attempts.
Every QR guide says to keep the logo small, print the code big and use strong contrast. None of them say how small, how big or how strong. When you add a logo feature to a generator, as this site has, you need real limits, so we measured them.
A word on what this is. We tested one decoder, ZBar, on synthetic images made on a computer. We did not test phone cameras, glare, creased paper or bad printing. The results are good for comparing choices against each other, such as one error correction level against another. They are not a promise that your printed code will scan on every phone.
With that said, some of the results surprised us, and a few of them change what we would recommend.
How We Tested
We built the codes with the same qrcode package (version 1.5.4) that this site's generator uses. We made three kinds of payload: a 35-character short link, an 81-character URL and a 186-character URL with tracking parameters. For each kind we generated 40 random payloads at each of the four error correction levels, L, M, Q and H. That is 480 base images, drawn at 10 pixels per module with a four-module quiet zone around them.
We then damaged those images in controlled ways, ran each one through ZBar 0.23, and counted a success only when the decoded text matched the payload exactly. The experiments were a centered logo (three shapes, 14 sizes), downscaling to a given number of pixels per module, Gaussian blur, lower contrast, and rotation. Altogether that came to more than 20,000 decode attempts.
The tables below show the share of codes that decoded. Logo and size results combine all three payload lengths unless we say otherwise.
Logos: How Much of the Code Can You Cover?
We placed a round, two-tone logo with a thin white ring in the center, the way most brand marks sit on a code. The sizes in the table are the logo's width as a share of the code's width. Each cell is 120 codes.
| Error correction | 8% | 14% | 18% | 22% | 26% | 30% | 35% |
|---|---|---|---|---|---|---|---|
| L (about 7% recovery) | 84% | 100% | 100% | 85% | 33% | 2% | 0% |
| M (about 15%) | 98% | 100% | 100% | 100% | 100% | 100% | 38% |
| Q (about 25%) | 100% | 100% | 100% | 100% | 100% | 100% | 100% |
| H (about 30%) | 91% | 100% | 100% | 100% | 100% | 100% | 100% |
Level L tolerated a logo of 14 to 18 percent of the width and then fell off fast: 81 percent at 20, 33 percent at 26, and almost nothing at 28. Level M held 100 percent up to 26 percent and mostly to 30, then dropped at 32. Level Q read every code at every size we tried, up to 35 percent, and level H did the same from a 12 percent logo upward.
The generator on this site uses level M and a logo about 22 percent of the code width. That combination decoded in all 360 trials we ran with it (three logo shapes, 120 codes each), so the default sits inside the safe zone.
The part we did not expect is at the other end of the table. A very small logo is not automatically safer. At an 8 percent width, two of our twelve configurations failed noticeably: level L with the 186-character URL decoded only 52 percent of the time, and level H with the 81-character URL 72 percent. Both of those are version 8 codes, which have an alignment pattern, a small square, at the exact center. A logo that covers only part of that square seems to confuse the decoder more than a logo that covers all of it. At 14 percent both configurations read normally again.
Shape mattered too. Round logos behaved cleanly. A flat dark square with a white border produced odd dips, for example level Q at 22 percent decoded 70 percent of the time but 100 percent at 20 and at 24. Treat any logo size as something to test with your own artwork, not a number to trust blindly.
Why a Short Link Makes a Code Easier to Scan
The length of what you encode decides how many modules the code has, and the number of modules decides how wide each one is at a given print size. The table shows the QR version and the modules per side for our three payloads at each error correction level.
| Payload | L | M | Q | H |
|---|---|---|---|---|
| 35 characters (a short link) | 29 | 29 | 33 | 37 |
| 81 characters | 37 | 37 | 45 | 49 |
| 186 characters (a long tracked URL) | 49 | 57 | 65 | 73 |
Numbers are modules per side. At level M, the short link makes a code 29 modules wide and the 186-character URL makes one 57 modules wide. Print both at the same width and the modules of the long one are about half as wide. Raising the error correction level adds modules too: the short link goes from 29 at level M to 37 at level H.
This is a practical argument for dynamic codes. The code holds a short redirect link instead of your long destination, so it stays small and sparse however long the real address is. It is the same reason we put that short link in the image once you click Make Dynamic. If you want to know more, see dynamic vs static QR codes.
How Small Can It Be? Pixels Per Module
For size, the number that matters is how many pixels of the camera image fall on each module. We downscaled the codes with bicubic resampling, the way a camera effectively does, and checked where reading stopped.
| Payload (level M) | 1.5 px | 2 px | 3 px |
|---|---|---|---|
| 35 characters | 45% | 100% | 100% |
| 81 characters | 70% | 100% | 100% |
| 186 characters | 0% | 100% | 100% |
Two pixels per module was enough for every code, and 1.5 was not: the longest payload failed completely. That fits what you would expect from sampling, since a decoder needs more than one pixel to tell neighbouring modules apart.
It gives you an arithmetic rule. A code with 29 modules plus the four-module quiet zone on each side is 37 modules across, so the camera image needs about 75 pixels across the whole code. A 57-module code needs about 130. We did not measure how that translates to centimeters, because it depends on the phone and the distance, but the rule makes the point about short links again: fewer modules means more forgiveness.
For printed sizes and distances, see the QR code size guide.
Blur, Contrast and Rotation
Blur was the harshest test. We blurred the codes with a Gaussian filter measured in module widths. At a quarter of a module every code still read. At half a module, none of the 120 did. If your phone has not focused, a QR code does not degrade gracefully, it stops reading.
Contrast was the opposite. ZBar read every code all the way down to a 1.5 to 1 luminance ratio, light gray on white. We would not take that as permission for pale codes. It says the decoder was not the limit; glare, print quality and phone cameras are the real constraints, and we could not simulate those. Dark on light, as strong as you can make it, is still the right advice.
Rotation did not matter at all. Codes at 5, 15, 30, 45, 90 and 180 degrees all read. You do not need to worry about which way up the code is printed.
A Checklist From the Results
- Encode as little as possible. A short link beats a long URL on every measure above.
- Use level M by default. Move to Q or H only if you need a big logo, and accept the denser code.
- Keep a logo to about a quarter of the code width at level M, and less at level L. On some codes a tiny logo is riskier than a medium one, so either skip the logo or make it a clear 14 percent or more.
- Leave the quiet zone alone. All of our tests used four modules of blank margin.
- Test the final printed code with two or three different phones, at the distance people will really scan from. Everything above is a guide for choosing; only a real scan confirms it.
Frequently Asked Questions
Make a code and test it
Free, no account. Download the PNG at 1100 pixels or the SVG for any print size.
Create a Free QR Code