How big can a logo be on a QR code?
On the codes we measured, the largest logo that still read was 15.5% of a small code and 22.4% of a large one. Aim below that. The 20% figure most sites quote is measured against the whole picture, not against the code itself.
A logo does not break a QR code by sitting on it. It breaks it when the covered area is more than the code can repair. On a small code, a logo drawn at 22% of the printed picture takes a third of the code itself, and the most damaged part of it needs 18 repairs when it can only make 8.
That is not an estimate. We ran it. Below is the table, the method, and everything the test does not prove.
The percentage everyone quotes is measured against the wrong square
The common advice is to keep a logo under 20% or 25%. Nobody says 20% of what.
A printed QR is two squares, one inside the other. The outer square is the whole picture, white border included. The inner square is the code. The border is four modules wide on every side, so the outer square is meaningfully bigger than the inner one.
Measure your logo against the picture and you get a much larger box than if you measure against the code. On a 33-module code, 22% of the picture is a 19-module box. That same box is 33.1% of the code.
The cap was never wrong. The square it was read against was.
What we measured
We ran a sweep on our own bench and costed every logo size on three codes.
These are the three codes people print. A short link of 32 characters, which makes a 33-module code. A plain website address of 49 characters, which makes 41 modules. The same address with campaign tags on the end, 110 characters, which makes 57 modules.
Conditions were fixed so size was the only variable. Error correction sat at level H on every code, with a four-module border, in pure black on pure white. That is the best contrast anyone will ever print, so contrast could not be the thing that moved.
The logo itself was generated in code, not supplied as a file. It was a solid black square, which is the worst a square logo can be.
For each code we walked the logo box down from the largest our tool will draw to a 5-module box. At each step we counted how many of the code's data chunks were damaged, how many the worst Reed-Solomon block could still fix, and then asked our decoder to read the result.
How the bench is built
The sweep is an internal command in our own codebase, not something you can run from your account. It reads no settings and touches no database, so the same commit and the same options give the same table every time.
What makes it repeatable for anyone else is the conditions above, not our command. Level H, a four-module border, whole-module logo boxes, black on white, and a decoder asked to read the composited raster. Any decoder will do.
The table
Read usage first. It is how much of the worst block's repair budget the logo has spent. At 1.00 there is nothing left. Above 1.00 the code is past saving.
| Link | Chars | Modules | Logo box | % of picture | % of code | Codewords damaged | Worst block | Spare | Usage | Reads | Note |
|---|---|---|---|---|---|---|---|---|---|---|---|
| short slug | 32 | 33 | 19x19 | 21.5% | 33.1% | 53/100 | 18/8 | -10 | 2.25 | no | this is what "22% of the picture" means |
| short slug | 32 | 33 | 17x17 | 17.2% | 26.5% | 41/100 | 14/8 | -6 | 1.75 | no | |
| short slug | 32 | 33 | 15x15 | 13.4% | 20.7% | 34/100 | 10/8 | -2 | 1.25 | no | this is what "22% of the code" means |
| short slug | 32 | 33 | 13x13 | 10.1% | 15.5% | 28/100 | 7/8 | 1 | 0.88 | yes | largest that reads at all |
| short slug | 32 | 33 | 11x11 | 7.2% | 11.1% | 22/100 | 6/8 | 2 | 0.75 | yes | what our tool ships |
| short slug | 32 | 33 | 9x9 | 4.8% | 7.4% | 14/100 | 5/8 | 3 | 0.63 | yes | |
| short slug | 32 | 33 | 7x7 | 2.9% | 4.5% | 9/100 | 4/8 | 4 | 0.50 | yes | |
| short slug | 32 | 33 | 5x5 | 1.5% | 2.3% | 6/100 | 3/8 | 5 | 0.38 | yes | |
| plain URL | 49 | 41 | 21x21 | 18.4% | 26.2% | 64/172 | 17/14 | -3 | 1.21 | no | this is what "22% of the picture" means |
| plain URL | 49 | 41 | 19x19 | 15.0% | 21.5% | 53/172 | 14/14 | 0 | 1.00 | yes | "22% of the code", and nothing left over |
| plain URL | 49 | 41 | 17x17 | 12.0% | 17.2% | 45/172 | 13/14 | 1 | 0.93 | yes | |
| plain URL | 49 | 41 | 15x15 | 9.4% | 13.4% | 33/172 | 10/14 | 4 | 0.71 | yes | what our tool ships |
| plain URL | 49 | 41 | 13x13 | 7.0% | 10.1% | 26/172 | 7/14 | 7 | 0.50 | yes | |
| plain URL | 49 | 41 | 11x11 | 5.0% | 7.2% | 21/172 | 6/14 | 8 | 0.43 | yes | |
| plain URL | 49 | 41 | 9x9 | 3.4% | 4.8% | 15/172 | 5/14 | 9 | 0.36 | yes | |
| plain URL | 49 | 41 | 7x7 | 2.0% | 2.9% | 8/172 | 2/14 | 12 | 0.14 | yes | |
| plain URL | 49 | 41 | 5x5 | 1.0% | 1.5% | 6/172 | 2/14 | 12 | 0.14 | yes | |
| long URL | 110 | 57 | 31x31 | 22.7% | 29.6% | 131/346 | 17/14 | -3 | 1.21 | no | |
| long URL | 110 | 57 | 29x29 | 19.9% | 25.9% | 113/346 | 15/14 | -1 | 1.07 | no | this is what "22% of the picture" means |
| long URL | 110 | 57 | 27x27 | 17.3% | 22.4% | 98/346 | 14/14 | 0 | 1.00 | yes | nothing left over |
| long URL | 110 | 57 | 25x25 | 14.8% | 19.2% | 83/346 | 12/14 | 2 | 0.86 | yes | the "22% of the code" rung |
| long URL | 110 | 57 | 23x23 | 12.5% | 16.3% | 72/346 | 10/14 | 4 | 0.71 | yes | what our tool ships |
| long URL | 110 | 57 | 21x21 | 10.4% | 13.6% | 60/346 | 9/14 | 5 | 0.64 | yes | |
| long URL | 110 | 57 | 19x19 | 8.5% | 11.1% | 47/346 | 8/14 | 6 | 0.57 | yes | |
| long URL | 110 | 57 | 17x17 | 6.8% | 8.9% | 39/346 | 6/14 | 8 | 0.43 | yes | |
| long URL | 110 | 57 | 15x15 | 5.3% | 6.9% | 31/346 | 4/14 | 10 | 0.29 | yes | |
| long URL | 110 | 57 | 13x13 | 4.0% | 5.2% | 25/346 | 4/14 | 10 | 0.29 | yes | |
| long URL | 110 | 57 | 11x11 | 2.9% | 3.7% | 16/346 | 4/14 | 10 | 0.29 | yes | |
| long URL | 110 | 57 | 9x9 | 1.9% | 2.5% | 10/346 | 2/14 | 12 | 0.14 | yes | |
| long URL | 110 | 57 | 7x7 | 1.2% | 1.5% | 6/346 | 1/14 | 13 | 0.07 | yes | |
| long URL | 110 | 57 | 5x5 | 0.6% | 0.8% | 0/346 | 0/14 | 14 | 0.00 | yes |
What the columns mean:
- Logo box is the whole-module square the logo reserves.
- % of picture is that box against the whole image, four-module border included.
- % of code is the same box against the code alone.
- Worst block is damaged against correctable in the most damaged Reed-Solomon block.
- Spare is what is left in that block after the logo.
- Usage is damage divided by capacity in that block.
Look at the third row. On the short link, 22% of the code fails too. Only the 13-module box reads, and that is 15.5% of the code. The denominator matters, and on a small code even the right denominator is not generous.
A short link is the dangerous one, not the safe one
A short link makes a small code. A small code has less repair to spend. That is the whole story.
The largest logo that read on our 33-module code was 15.5% of it. On the 57-module code made by the long address, 22.4% read. A bigger code carries a bigger logo, in percentage terms as well as in millimetres.
So if you want a bigger logo, do not shorten the link. Make a bigger code, or print bigger.
The artwork does not matter, the cleared space does
We ran the whole sweep twice. Once with a solid black square as the logo. Once with nothing at all inside the halo, just the space reserved for one.
The decode verdict was identical on all 31 sizes. The damaged-chunk counts moved by at most 2. On a 33-module code at the 13-module box, 28 chunks with the black square against 26 with nothing there.
Your designer's mark is not the variable. The size of the cleared area is. That is what lets us give you one number per logo size instead of one per logo.
Reading on a screen proves nothing about a printed sticker
A code can pass a clean scan with nothing left in reserve. Then one ink blob or one scuff arrives and it stops reading.
We tested that. For every size that read, we flipped whole modules outside the logo to the wrong colour, 40 tries each, and decoded again.
At 1.00 usage, with nothing spare, one extra damaged module dropped the read rate to 59% across 80 tries. Three extra dropped it to 34%. At 0.71 usage and below we flipped three modules 160 times and never lost a read.
What decides it is spare codewords in the worst block. A whole number, not a percentage.
Zero spare, and one blob costs you the read four times in ten. One spare, and one extra damaged module costs nothing. Two spare, and three extra almost never cost anything.
What our tool does with this
Our renderer decode-checks every code before it hands you a file. If a logo leaves the code unreadable, you get a refusal and not a broken PNG.
It also refuses the biggest logo that technically works. The ladder keeps a fifth of the worst block's repair budget unspent, so a size that reads with nothing in reserve is skipped and the next one down is tried. That is why the size you get is smaller than the cap on the settings screen. On a short link it lands at 11.1% of the code.
The codes on our demo page are drawn by the same renderer and checked by the same decoder as a paid one. Scan one off your screen if you want to test that.
What this test does not prove
It is our decoder, not your phone. Every "yes" in the table is a pure-PHP port of ZXing with the TRY_HARDER hint, reading a clean downscaled image. It is one implementation.
An iPhone camera, Google Lens, a payment app's built-in scanner and a warehouse gun all behave differently, and some are more forgiving than ours. We have no field data from real phones. Treat the table as a floor, not as a prediction of any one scanner.
The bench flatters the result. Pure black on pure white is the highest contrast that will ever exist. There is no paper, no ink spread, no lighting, no angle, no curve and no lamination glare in here. Colour was left out on purpose so it could not confuse the size measurement. A coloured code has one more thing eating the same margin.
Print damage is not simulated. Dot gain, registration drift, halftone screening, ink spread on uncoated stock and a die-cut that clips the border are all absent. Our misread test flips whole modules at random and independently. Real print damage is clustered, because a smudge takes its neighbours, and clustered damage concentrates into fewer chunks. Read the one-module and three-module figures as an ordering of risk, not as a probability to quote back at us.
Three payloads, three code sizes, one error-correction level. Versions 4, 6 and 10, all at level H, because our logo add-on forces H. Nothing here says anything about level M or L, about larger codes, or about the denser symbols above version 10.
One logo shape. A square. A wide wordmark reserves a wide flat halo, which lands on a different set of chunks and may cost more or less. Anyone applying these numbers to a banner-shaped logo is extrapolating.
The "22% of the picture" figure is our reconstruction. We computed what the common advice implies, using 22% of the full image area with a four-module border. It is not a quotation from any named company. A site using a different border width would get a different number.
Sample sizes are small at the interesting end. Forty tries per cell is roughly plus or minus 15 points at 50%. The gap between surviving three misreads at 0.75 usage and at 0.71 is two failures out of forty. Do not build a rule on that gap. The codeword version of the same statement, two spare in the worst block, is the sturdier one.
Does a bigger logo always break the code?
No. It breaks it when the damage exceeds what the worst Reed-Solomon block can fix. That threshold moves with the size of the code, which moves with the length of what you encoded.
Why does my code work on my phone but not at the printer?
Because a screen scan does not test the reserve. A code at the limit reads perfectly on glass and then fails on paper. In our test, a code with nothing spare lost the read 41% of the time after a single extra damaged module.
Does the shape of my logo change the answer?
Not much, for a square. A solid black square and an empty space of the same size differed by at most 2 chunks and never changed whether the code read. A wide wordmark is a different shape and we have not measured it.
Will a higher error-correction level let me use a bigger logo?
Every number here is already at level H, the highest there is. There is nothing above it to move to.
What do I do if the tool refuses my logo?
Use a smaller logo, or encode a longer address so the code itself gets bigger. Shortening the link does the opposite of what people expect, because a shorter link makes a smaller code with less repair to spend.
Getting one made
The logo is a paid add-on on any plan, and the guard above runs before you download. The plans are on pricing. The setup steps are in adding a logo to a QR code.