Skip to main content

How Big Can a Logo Be in a QR Code?

A customer asked us to make the logo in the middle of his QR code bigger. It looked like a one-line change. Every guide says roughly the same thing: error correction Level H recovers up to 30% of a QR code’s data, so a logo may cover up to about 30% of the code. We were covering 7.8%. Enormous headroom.

We tested it instead. The obvious answer was wrong, and it was wrong in the direction that breaks the customers who pay the most.


First: A Width Is Not an Area

Our logo size is stored as a fraction of the code’s width:

  • Logo: 22% of the symbol width
  • White ring around it: 3% on each side
  • Total plate: 28% of the width

Every published guideline is a fraction of area. Because area scales with the square of width, 28% of the width is 7.8% of the area — so “we’re at 0.22, the limit is 0.30, therefore we have room” compares a width to an area and overstates the headroom by about three times.

Correcting the units made the change look safer, which is exactly the sort of reasoning that should invite suspicion.


The Test

We generated QR codes reproducing our renderer exactly — same error correction level, same white plate, same aspect-preserving logo placement — across logo ratios from 0.22 to 0.50, and machine-decoded every one.

Two payloads, because the length of the encoded URL changes the symbol size:

PayloadExampleSymbol
Shorthttps://card.example.bizversion 4
Longhttps://nexalink.co/c/long-slug-hereversion 8

Four conditions each: clean, blurred, rotated 30°, and downsampled to simulate a 2 cm print scanned by a phone.

The Control That Changed the Answer

The first run produced a satisfying table of failures. Blur failed. Print-at-2cm failed. It looked like the logo was overwhelming the error correction. Then we ran the identical degradations with no logo at all:

PayloadCleanPrint @ 2 cmBlurRotate 30°
Short (v4)passpassfailpass
Long (v8)passfailpasspass

Those two failures happen at zero occlusion. They are artifacts of the simulation and the decoder’s strictness, not the logo. Without that control, half the result table blamed the logo for failures it did not cause, and we would have concluded the current size was already at its limit.

A test with no control does not measure what you think it measures. It is the cheapest step in the exercise and the one most often skipped.


Results

Reading only the cells the control validates:

Logo ratio (width)AreaShort URL (v4)Long URL (v8)
0.22 (previous)7.8%passpass
0.259.6%passpass
0.26 (chosen)10.2%passpass
0.2710.9%passpass
0.2811.6%failpass
0.29 – 0.3112.2 – 13.7%failpass
0.3214.4%pass*pass

Finding 1: Symbol Size Decides It, Not Area Percentage

The long-URL code survived everything to 0.32. The short-URL code broke at 0.28. Same error correction, same fraction, same area percentage — different outcome, because a shorter URL produces a smaller, denser symbol, and a fixed fraction of a smaller symbol consumes proportionally more of the modules that carry structure rather than payload.

“Keep the logo under 30% of the area” is a ceiling for the ideal case. It is not a licence to ship 13% on a version-4 symbol.

Finding 2: The Fragile Case Belongs to the Paying Customer

A short URL means a custom domain. card.allendale.biz is far shorter than nexalink.co/c/howard-evo-managing-director. Custom domains are a paid feature, so the most fragile code in the system belongs to the customer who paid extra — and who is likeliest of anyone to print it at scale.

Had we tuned against the default URL, which is the obvious thing to test since most codes use it, every internal check would have passed and the failures would have landed exclusively on paying customers, discovered after a print run.

Finding 3: Failures Are Not Monotonic

The short-URL column fails at 0.28, 0.29, 0.30 and 0.31 — then passes at 0.32. That is not robustness returning. It is where the plate’s edge happens to fall relative to the symbol’s alignment pattern at that size. It is luck, and it evaporates the moment the URL changes length by one character.

Hence the rule: never pick a value above the first failure. A threshold search reporting the “highest passing value” will hand you 0.32 here. The honest ceiling is 0.27.


What Everyone Else Publishes

The published guidance does not agree with itself. Depending on the source you will read 10–20% of area, 15–20%, 25% of width, or up to a third of the edge length. All five major digital business card platforms support a logo in the QR code, and all five gate it behind a paid tier:

PlatformLogo in QRUser can resizePublished logo spec
PoplPro, Pro+, TeamsYes540 × 540, 1:1 (full spec table)
HiHelloProfessional and aboveNot documented332 × 332 minimum, 1:1
BlinqPremium and aboveNot documentedAspect ratios only, no pixels
MobiloPremium and aboveColour and logoNot published
LinqPro, TeamsLogo uploadNot published

Three honest observations. Popl is ahead on the thing that matters — they let the customer size the logo themselves. Ours asked for a bigger logo because a fixed ratio was the only lever he had.

HiHello independently found what we found. They tell users to avoid text-based logos because of the size of the logo field — the same effect we measured, since aspect ratio is preserved and a wide wordmark is scaled to fit by its width.

And none of them publish the thing that actually breaks codes. All five say some version of “logo, centred, keep it reasonable”. None mention that the length of your URL changes how much logo your code can survive — so none can warn a custom-domain customer that theirs is the fragile one.


The Part That Generalises

  1. Check the units before trusting the headroom. A width compared against an area budget produced a number wrong by a factor of three, in the reassuring direction.
  2. Run the null condition. Testing the degradations with no logo at all invalidated half the results and changed the conclusion.
  3. Ask who owns the worst case. The failure mode concentrated on custom domains — which is to say, on the customers who pay for them. An average-case test would have shipped it.

* 0.32 passes by coincidence of module alignment, not by robustness — see finding 3. Decode testing used jsQR, which establishes relative safety between ratios rather than absolute scannability; on-phone confirmation at print size gates any change before release.

Related Guides