QR code error correction, explained
Why a QR code with a logo in the middle still scans, why some codes survive coffee stains and others don't, and how to pick the right error correction level for your use case.
Hold a damaged QR code up to your phone. A coffee stain, a fold across one corner, a logo printed dead-center — and the code still scans. The mechanism that makes this possible is one of the more elegant pieces of mathematics deployed at industrial scale, and the choice of how much of it to use is one of the few design decisions a QR code asks you to make.
This post explains what's actually happening when a damaged code resolves correctly, why the four levels (L, M, Q, H) exist, and how to choose between them for your use case.
What error correction is, mechanically
A QR code is a grid of black and white modules. Some of those modules encode the data you want (the URL, text, or other content). Others encode redundancy — extra information derived from the data that lets the scanner detect and correct errors.
The mathematical machinery is Reed-Solomon coding, a family of error-correcting codes invented in 1960 and used in everything from compact discs to deep-space transmissions. The relevant property: given enough redundant symbols, you can reconstruct the original message even when some of it is missing or corrupted, up to a fixed budget set by how much redundancy you encoded.
The QR specification (ISO/IEC 18004) bundles this into four named levels:
| Level | Recovery | Data overhead |
|---|---|---|
| L | ~7% | Lowest |
| M | ~15% | Low |
| Q | ~25% | High |
| H | ~30% | Highest |
"Recovery" here means: what percentage of the code's modules can be unreadable — covered, damaged, distorted — before the scanner gives up. The cost is data overhead: at level H, almost a third of the code is just redundancy, which means you need a physically larger or denser code to encode the same message.
Why the levels exist
The original engineers at Denso Wave knew QR codes would live in the physical world. A barcode on a clean retail box is one thing; a code printed on the side of a factory part, or inscribed into a metal panel, or embossed on a curved surface, is another. They chose four levels rather than one because the right tradeoff genuinely varies by environment.
Level L exists for pure data efficiency — the most content in the smallest code. You see this in dense industrial applications where the code is laser-etched in a controlled environment.
Level M is the historical default for general use: enough robustness for a code shown on a screen, printed in an email, or displayed on signage that won't get touched.
Level Q is where most printed marketing materials should sit. It assumes some abuse — a fingerprint, a fold, a partial smudge — without taking too much capacity.
Level H exists for the worst-case scenarios and one specific creative use case: putting a logo in the middle of the code.
The logo trick
Here is the move that made QR codes interesting again around 2015: brands started printing their logos inside the QR code itself, replacing the center 15-20% of the modules with brand artwork. The code still scanned. This was not a hack — it was a direct consequence of the error correction being there.
A QR code with H-level correction has a 30% recovery budget. A logo replacing 18% of the code's area uses 18 of those 30 percentage points, leaving 12 points of margin for additional damage like scuffs and folds. The scanner sees the logo as "damage" and reconstructs the missing data using the redundancy in the rest of the code.
A few rules of thumb if you are trying this:
- Use level H. Q sometimes works; H reliably works.
- Keep the logo to ~20% of the total code area or less.
- Center it. Decoders are more tolerant of damage in the center than at the edges, where the alignment patterns and finder patterns live.
- Test by scanning at a distance, in poor lighting, and with a low-end phone. If it scans on a five-year-old Android in a dim room, you are fine.
How to pick a level
The choice is mostly about where the code lives:
Aside
Quick rule: screens get M, paper gets Q, packaging gets H, and anything with a logo in the middle gets H regardless of medium.
A few specific cases:
- Restaurant menus. Q. They get coffee on them.
- Product packaging in retail. H. They get scuffed in transit, stacked on top of each other, and photographed under bad fluorescent lights.
- Email signatures and PDFs. M. They are displayed on clean screens and rarely printed.
- Outdoor signage. H. Sun fades printing. Rain drips. Birds happen.
- Conference badges. Q. They get bent, sweat-stained, and scanned by tired people in crowded rooms.
- Codes with embedded logos. H, every time.
A word on density
Higher error correction means a denser code. A short URL at level L might fit in a 25×25 grid; the same URL at level H needs 33×33. If you are printing small (think shipping label, not poster), this matters because the module size — the physical dimension of one black or white square — has a minimum below which scanners struggle. Cameras need roughly 4-5 pixels per module to read reliably; below that, the focus has to be perfect.
The practical rule: at small print sizes, prefer a shorter URL over higher error correction. A 30-character URL at H might need to be printed at 25mm × 25mm; the same URL shortened to 15 characters at M might fit in 15mm × 15mm. (You can use the Tryst Link QR generator to test how content length and error correction interact.)
What scanners actually do
The decoding pipeline a phone runs through, in rough order:
- Find the three large square markers in the corners. These are finder patterns — they tell the scanner there is a QR code and orient it.
- Locate the alignment patterns (smaller squares scattered through larger codes) to correct for perspective distortion.
- Read the format information to determine the error correction level and mask pattern.
- Read the data modules.
- Apply error correction to recover any damaged or unreadable modules.
- De-mask and decode the recovered bits into the original message.
The error correction step is where the magic — really, the math — happens. By the time the scanner is interpreting your URL, it has already silently fixed the coffee stain and ignored the logo.
Further reading
If you want the full specification, it's ISO/IEC 18004:2015. For the practical side, our URL shortener primer covers the other half of the link-creation pipeline. And the Tryst Link QR generator lets you experiment with all four error correction levels and see how the visual density changes.
Frequently asked
- What does error correction level mean for a QR code?
- Error correction level is the percentage of a QR code's modules that can be obscured or damaged while the code still scans. Level L tolerates about 7%, M about 15%, Q about 25%, and H about 30%. Higher levels add more redundant data, which makes the code denser — more black-and-white squares to fit the same content.
- Which error correction level should I use?
- Use M for digital displays, marketing emails, and any QR code shown on a clean screen. Use Q or H for printed materials, packaging, anything that might get scuffed, and any code that has a logo in the middle. L is rarely the right answer outside of dense data encoding tasks where every byte matters.
- How can a QR code still scan with a logo in the middle?
- Reed-Solomon error correction lets the scanner reconstruct the missing data as long as enough of the code is intact. A code with H-level correction can lose up to 30% of its area and still decode. A logo replacing the center 15-20% of the code is well within that budget.