Skip to content

Design

QR code error correction: what L, M, Q and H really cost you

Higher error correction is not automatically safer. Here is what each level recovers, what it costs in capacity and module size, and when to use which one.

by Kyllian 6 min read

Someone raises error correction to H because it sounds like the careful choice, prints the code at 20 mm on a business card, and produces a symbol that is harder to scan than the M version they started with. The redundancy is real; so is the price, and almost nobody prices it.

What the four levels promise

QR codes carry Reed-Solomon error correction codewords alongside the data codewords. The four levels defined by ISO/IEC 18004 differ only in how many:

LevelRecoveryData capacity vs LTypical name
L~7%100%Low
M~15%~79%Medium
Q~25%~56%Quartile
H~30%~43%High

The capacity column is the part people miss. At the largest version, byte mode holds 2,953 bytes at L and 1,273 at H — level H throws away more than half the symbol’s capacity to buy 30% damage tolerance. In practice you rarely notice this as “the code refused my text”; you notice it as the code silently getting denser.

One more clarification on that 30%: it is 30% of the codewords, not a guarantee that any 30% of the picture can be destroyed. The finder patterns in the corners and the timing pattern between them are structure, not data. Damage those and the decoder never locates the grid, whatever the level says.

The cost is measured in modules

A QR symbol comes in versions. Version 1 is 21 modules across, and every version up adds four: version 4 is 33, version 5 is 37, version 10 is 57, version 40 is 177. When you raise the error correction level, the same payload no longer fits in the same version, so the encoder promotes it — and the printed code is suddenly made of more, smaller squares.

At a fixed print size, module size is simply the code width divided by the module count. This is the whole trade-off in one line.

The same URL at four levels

Take a sixty-character link — a domain, a path, no tracking parameters — encoded in byte mode:

LevelVersionModules per sideModule size at 25 mm
L4330.76 mm
M4330.76 mm
Q5370.68 mm
H7450.56 mm

L and M land in the same version here, so M is free — you gain 15% recovery for no increase in module count at all. That is why M is the right default and why the image API defaults to M — pass ?ec=l, q or h when you want one of the others.

H is a different story. 0.56 mm is close to the 0.4 mm practical floor for offset print and already under the ~0.6 mm you want for thermal labels or rough stock. You have bought damage tolerance and spent it on making every module harder to resolve. The print size guide has the per-module minimums by process.

Choosing by medium

MediumLevelWhy
Screen, slide, email, socialMNothing degrades a backlit image; keep modules large
Flyer, menu, poster, business cardMClean flat print; size is the constraint, not damage
Code with a centred logoHThe logo is deliberate damage and must be covered
Thermal label, warehouse, industrialQSurvives scuffing and print head dropout
Curved surface — can, bottle, tubeQOptical distortion behaves like partial loss
Very large format, long URLLModules are huge anyway; buy back the capacity

The pattern: raise the level only when you can name the thing that will obscure the code. A logo, a fold, a scuff, a curve, a rubber stamp. “Just in case” is not a reason, because the redundancy is not free.

Why H is the wrong instinct on a small code

The failure mode is quiet. Nobody sees the version increase — the generator just draws a denser square, it still previews fine on a retina display, and the problem only appears in a restaurant with a three-year-old Android phone. The rule of thumb that keeps you out of it:

  • Under 25 mm printed, use M and shorten the URL instead.
  • Between 25 and 50 mm, M unless there is a logo, then H and make the code bigger to compensate.
  • Above 50 mm, use whatever the surface demands; the modules have room.

If you find yourself at H on a small code because a logo has to fit, the real fix is usually the URL. Dropping four UTM parameters from a link can save a whole version, which is more module size than any level change will give you. Static versus dynamic QR codes covers the short-URL argument in more detail.

Level and logo are one decision

A centred logo needs H, because the area it covers is genuinely unrecoverable data — even at the 20–25% of the code’s width that is the sane working range, which is 4–6% of the symbol’s area. But H already pushed the code to a higher version, so the printed size has to grow too — otherwise you are stacking smaller modules underneath an obstruction. Setting H, adding a logo and keeping the original 20 mm artwork is the single most common way to produce a code that looks professional and does not work. Putting a logo in a QR code without breaking it works through the geometry.

What error correction never fixes

Redundancy recovers damaged modules. It does not help with:

  • Low contrast. If the decoder cannot binarise the image, there are no codewords to correct.
  • A missing quiet zone. The four-module margin is how the symbol is found.
  • Blur and undersizing. These corrupt the whole symbol at once, not a recoverable fraction of it.
  • A dead destination. A perfectly decoded 404 is still a 404.

Each of those has its own fix, and they are collected in why your QR code is not scanning.

Worth noting that this trade-off is not unique to QR. PDF417 exposes nine error correction levels, 0 to 8, and the same logic applies: more correction means more codewords means a physically wider symbol on the same label.

The generator exposes all four levels next to the live preview, so the honest way to make this decision is to set your real URL, flip between M and H, and watch the module count change. Then print the one you chose at final size and scan it before it goes anywhere near a print run.

Frequently asked

Does higher error correction make a QR code more reliable?
Only when something will physically obscure the symbol. Raising the level adds redundant codewords, which pushes the code to a higher version with more modules, so at a fixed printed size every module gets smaller. On a small code that shrinkage costs more readability than the redundancy buys back.
Which error correction level should I use for a QR code on a screen?
M is the sensible default. A screen is backlit, sharp and undamaged, so there is nothing for the redundancy to recover from, and M keeps the module count low enough that the code stays readable even in a small slide or email image. Reserve Q and H for physical surfaces.
How much bigger does a QR code get when I switch from L to H?
It depends on where your payload sits relative to a version boundary. A sixty-character URL is a 33-module version 4 symbol at L and M, a 37-module version 5 at Q, and a 45-module version 7 at H. That is a 36 percent increase in modules per side for the same content.
Can I change the error correction level of a QR code after printing it?
No. The level is baked into the symbol's format information and changes the entire module pattern, so a new level means a new code and a new print run. Decide before the artwork goes out, and test the exact level you intend to ship on the exact stock you intend to use.

Make the code this guide describes

The generator runs in your browser — add a logo, pick colours, tag the link with UTM parameters and download a PNG or SVG. No account, no watermark.

Keep reading

← All guides