How to Make a QR Code (and Choose the Right Error-Correction Level)
QR codes are on menus, packaging, posters, payment terminals, and business cards. Generating one takes seconds — paste a link, get an image. But a surprising number of QR codes in the wild don’t scan reliably, and it’s almost always down to two decisions people make without thinking: the error-correction level and how much data they cram in. Get those right and your code works on the first try, every time.
What a QR code actually stores
A QR code is a grid of black and white squares (called modules) that encodes text — most often a URL, but it can hold plain text, contact details, Wi-Fi credentials, or a payment string. The more characters you encode, the more modules are needed, and the denser and smaller each module becomes at a fixed physical size. That density is the root of most scanning problems.
Part of the grid isn’t your data at all — it’s error-correction information, redundant data that lets a scanner reconstruct the code even if some of it is unreadable. How much of the code is reserved for that is a choice you make.
The four error-correction levels
QR codes define four levels, each able to recover a different fraction of a damaged code:
| Level | Recoverable | Best for |
|---|---|---|
| L (Low) | ~7% | Clean codes shown on a screen, where nothing will obscure them |
| M (Medium) | ~15% | The sensible default for most print |
| Q (Quartile) | ~25% | Small codes, or rough/curved surfaces |
| H (High) | ~30% | Codes with a logo in the middle, or printed very small |
The trade-off is real: a higher level dedicates more of the grid to recovery data, which means less room for your actual content and a denser code at the same size. So you don’t just always pick H — you pick the lowest level that comfortably survives how the code will be used.
Adding a logo? Use level H
Dropping a logo into the center of a QR code physically covers some modules. Level H can lose up to ~30% of the code and still scan, which is what makes the logo trick work. At level L, the same logo would likely break it.
Keep the data short
The single biggest lever for reliability is how much you encode. A short link produces a sparse, easy-to-scan code with large modules; a 120-character tracking URL produces a dense thicket of tiny squares that phone cameras struggle with — especially in poor light or at small sizes.
If your destination URL is long, shorten it before generating the code (a short link, or your own redirect). You’ll get a cleaner code that scans faster and tolerates more damage. The QR Code Generator builds the code in your browser; if you want to inspect or tidy a URL first, the URL Parser breaks it into its parts.
Static vs dynamic — what’s inside the code
There are two ways to point a QR code at a web page:
- Static: the URL is encoded directly into the pattern. It can never change, depends on no third-party service, and works forever — but if the destination moves, the printed code is dead.
- Dynamic: the code encodes a short redirect that you can re-point later (and usually track). Flexible for campaigns, but it relies on the redirect provider staying alive.
For a permanent link — a address on packaging, a menu, a portfolio — static is the more robust choice. Reach for dynamic only when you genuinely need to change the destination after printing.
Test before you print
This is the step that prevents expensive mistakes. A QR code that scans perfectly on your monitor can be unreadable once it’s shrunk onto a business card or printed on a textured bag. Before you commit to a print run:
- Generate the code and place it at the actual final size.
- Leave a clear quiet zone — an empty margin of at least four modules — around it; codes butted right against other content often fail.
- Scan it with a couple of real phones, in normal lighting, from a normal distance.
If it hesitates, shorten the data, increase the size, or bump the contrast before raising the error-correction level — density and size are usually the real culprits.
The takeaway
A reliable QR code is mostly about restraint: encode as little as you can (short link), pick the lowest error-correction level that suits the setting — M for everyday print, H when you’re adding a logo or going small — leave a quiet zone, and test at real size on a real phone. Do that and you’ll never hand out a code that just shows a shrug on someone’s camera. For the broader toolkit of generators that save these kinds of headaches, see the developer generators guide.