QR Code Error Correction: L, M, Q and H Explained
Error correction is the one QR setting everyone has an opinion about and few people understand. The marketing version — "level H survives 30% damage!" — is close enough to be useful and vague enough to cause real mistakes. Choosing H does not make your code more reliable in any general sense. It makes it more tolerant of damage, and it charges you for that tolerance by making the code denser.
What the four levels actually mean
A QR symbol stores your data as a sequence of 8-bit codewords, then appends redundant codewords computed from that data. The four levels set how many redundant codewords get added:
- L (Low) — roughly 7% of codewords can be restored
- M (Medium) — roughly 15%
- Q (Quartile) — roughly 25%
- H (High) — roughly 30%
Two clarifications that matter. The percentage is of codewords, not printed area, and it is approximate: symbols are divided into blocks, each with its own correction budget, so the effective figure wobbles a few points either way. Area coverage is a different thing entirely — a logo covering 10% of the symbol is not the same as losing 10% of codewords, because a centred logo hits data modules unevenly.
How Reed-Solomon recovery works, without the algebra
The mechanism is Reed-Solomon coding, the same family used on CDs. You do not need the polynomial arithmetic to reason about it.
Imagine fitting a curve through a set of points. Two points define a straight line completely; plot ten anyway and you can lose three and still reconstruct the line exactly, because you have more information than the minimum. Reed-Solomon does this with codewords instead of coordinates: the data defines a polynomial, the encoder evaluates it at extra points to produce parity codewords, and the decoder solves backwards for missing values.
The practical consequences follow directly:
- Recovery has a hard budget. Once errors exceed roughly half the parity codewords, the decode fails outright rather than degrading — there is no "mostly readable" outcome.
- Damage at a known location is about twice as cheap to repair as damage at an unknown one. In practice your scanner does not know your logo is there, so it does not get that discount.
- QR interleaves codewords across blocks, so a scratch in one corner spreads thinly across several blocks instead of destroying one. Localised physical damage is exactly what this scheme is built for.
The capacity cost, in real numbers
Every byte of redundancy is a byte you cannot spend on content. At version 40 that is the difference between holding 2,953 bytes and holding 1,273.
| Level | Approx. recovery | Version 10 bytes (57×57) | Version 40 bytes (177×177) | Version 40 digits |
|---|---|---|---|---|
| L | ~7% | 271 | 2,953 | 7,089 |
| M | ~15% | 213 | 2,331 | 5,596 |
| Q | ~25% | 151 | 1,663 | 3,993 |
| H | ~30% | 121 | 1,273 | 3,057 |
Going from L to H costs you about 55–57% of usable capacity. For most URLs that is irrelevant — you are nowhere near the limit. It matters when you are encoding a long vCard or a full payment payload, where hitting the ceiling forces a jump to a much higher version.
Version, module count, and why H makes codes bigger
Versions run 1 to 40, and each side of the symbol is 17 + 4 × version modules: 21×21 at version 1, 177×177 at version 40. Higher level means more codewords per payload means a higher version means more modules means smaller modules at any fixed print size.
Here is what that does to a plain 100-character URL printed at 3 cm:
- Level L — fits version 5, 37×37 modules, module size about 0.81 mm.
- Level M — fits version 6, 41×41 modules, module size about 0.73 mm.
- Level Q — fits version 8, 49×49 modules, module size about 0.61 mm.
- Level H — fits version 10, 57×57 modules, module size about 0.53 mm.
Same URL, same 3 cm of paper, and H leaves you with modules two-thirds the size of L. On a coated offset print at 0.53 mm you are still fine. On an uncoated stock or a 203 dpi thermal printer you have just dropped below the reliable floor. This is the mechanism behind a lot of "it scanned in the proof but not in the print run" stories: someone set H for a logo, the version jumped, and nobody re-checked the module size. Our print sizing guide has the per-process minimums.
Why a logo means you should pick H
A logo printed over the centre of the symbol destroys real data modules. There is no clever way around that — the scanner sees whatever is not covered. Level H is the right response because it gives the decoder the largest budget to reconstruct what is missing.
But H is not a licence. Rough working limits that hold up in practice:
- Keep the covered area to roughly 20% of the symbol or less, even at H. Some designs survive 25%; very few survive more.
- Print bigger than you otherwise would. Extra width buys back the module size that the higher version costs you.
- Add a solid light border around the logo, a few modules wide, so the covered region has clean edges rather than antialiased ones.
- Test with the oldest phone you can find, at the real distance, at final size. If a logo is worth having, it is worth twenty minutes of testing.
If your brand guidelines insist on a logo larger than that, the honest options are to put the logo beside the code instead of on top of it, or to accept a lower scan rate. Both are better than shipping something that silently fails.
What error correction does not do
This is where H gets oversold. None of these improve with a higher level:
- Low contrast. A grey code on a grey background fails at thresholding, long before any correction is attempted.
- Insufficient size or resolution. If the camera cannot resolve modules, there are no codewords to correct.
- Dot gain and ink spread. These corrupt every module in the same direction, which is a pattern Reed-Solomon handles badly.
- Glare and reflections. Same story: large uniform areas of corruption.
- A wrong or expired URL. The code will decode perfectly and take the user to a 404.
If your problem is on that list, changing the level will waste your afternoon. Work through the troubleshooting checklist instead.
Picking a level
- L — on-screen display, projected slides, digital signage, and anything where the payload is near the capacity ceiling. No physical damage to survive, so do not pay for tolerance.
- M — the sensible default for printed URLs on paper, cards and packaging handled normally.
- Q — outdoor signage, labels on goods that get scuffed in transit, codes laminated into high-traffic surfaces.
- H — any code with a logo over it, small codes on textured surfaces, and permanent outdoor signage that will weather for years.
Frequently asked questions
Does level H make my QR code scan faster or from further away?
No. Detection speed depends on contrast, module size and focus, none of which change with the correction level. H actually makes the code slightly denser at a fixed size, so if anything it is marginally harder to acquire at distance.
Is 30% the same as "a third of the code can be covered up"?
No. It is approximately 30% of the symbol's codewords, and it assumes damage scattered across blocks. A single opaque blob in one spot is harder to recover than the same number of lost codewords spread around, which is why the safe logo coverage figure is lower than 30%.
Can I change the error correction level after printing?
No. The level is baked into the format information encoded in the symbol. Changing it means re-encoding and reprinting. If you think you might need to, generate both versions before the print run.
Do all scanners support level H?
Yes. All four levels are part of ISO/IEC 18004 and any conforming reader handles them. You will find occasional cheap hardware scanners with partial support, but they are rare enough that it is not worth designing around.
Which level should I use for a WiFi QR code?
M is plenty. Indoor codes on a wall or a card do not face meaningful physical damage, and the payload is short. If you want the code to survive being printed small, L keeps the version lower and the modules bigger — a better trade than added redundancy.
What about payment codes like EPC?
Use M unless the code will be exposed to weather or heavy handling. Neither payload is anywhere near capacity. For anything involving money, verify the decoded content on screen before confirming — error correction guarantees the data is what you encoded, not that it is what you meant.
Is there a level above H?
No. H is the maximum defined in the standard. If your code is still failing at H, the cause is somewhere other than correction capacity.
Why does my generator not let me pick the level?
Some encoders lock it, usually to M or Q, or pick automatically based on payload length. If you need control — for a logo, or for a tight space — use a tool that exposes it. Our generator lets you set the level and shows the resulting version.
Related guides
Error correction interacts directly with physical size: read What Size Should a QR Code Be? for module-size floors by print process, and Why Your QR Code Won't Scan for the failures no correction level can fix. Choosing between static and dynamic codes changes your payload length, which changes the version you land in. Payloads with their own capacity considerations: vCard, WiFi, EPC on invoices.