QR code error correction levels: L vs M vs Q vs H, and when the tradeoff is actually worth it
Every QR code has a Reed-Solomon error-correction level baked in — L (~7% recovery), M (~15%), Q (~25%), H (~30%) — and picking the wrong one either wastes visual density or leaves you with a code that stops scanning the
Every QR code has a Reed-Solomon error-correction level baked in — L (~7% recovery), M (~15%), Q (~25%), H (~30%) — and picking the wrong one either wastes visual density or leaves you with a code that stops scanning the moment it gets a little damaged.
Here's the actual decision, not just the percentages:
- L — clean digital display only (a code shown on a screen, never printed, never overlaid with anything). Smallest, least dense module grid for a given payload.
- M — the safe default for most printed material. Handles minor print smudging or a slightly low-quality printer.
- Q — printed material that gets handled a lot (product packaging, shipping labels) or is at moderate risk of scuffing.
- H — anything with a logo or graphic overlaid on top of the code, since that overlay is itself "damage" the decoder has to recover from. Also the right call for outdoor/weather-exposed prints.
The mistake I see most often: defaulting to H everywhere "to be safe." Higher error correction means more modules for the same data, which means a denser, harder-to-scan-from-a-distance code with zero benefit if nothing's ever going to obscure it. Match the level to the actual damage risk, not to the theoretical maximum.
curl "https://qr-api.p.rapidapi.com/v1/qr?data=https://example.com&ecc=Q" \
-H "X-RapidAPI-Key: <your-key>" \
-H "X-RapidAPI-Host: qr-api.p.rapidapi.com" \
--output qr.svg
QR API exposes ecc as a plain query param (defaults to M) so you can set it per use case instead of hardcoding one level everywhere.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.