How to design a custom QR code that actually scans

Branded QR codes — round modules, custom colours, centre logo — work when you respect five constraints. Here's the recipe and the things that quietly break the scan.

Dec 22, 2025 8 min read Linked.Codes
How to design a custom QR code that actually scans

Most "design your own QR code" tutorials end at the point where the code looks pretty in the preview. They skip the part where you print 5,000 of them on labels and discover that 12% don't scan from across the room. The branded QR code is a deceptively forgiving design problem — until it isn't.

This is the recipe we use internally on every code we ship. Five constraints that, if you stay inside them, give you a code that's visually distinctive and reliable. Break any one and you may be looking at a reprint.

Constraint 1: Contrast at minimum 3:1

The decoder needs to tell dark from light. Phone cameras handle high contrast effortlessly and degrade gracefully with mid-contrast. Below a 3:1 ratio between dark modules and the background, you start failing in low light, on glossy paper, or when the user holds the phone slightly off-axis.

Three colour combinations that always work:

  • Black on white (21:1) — the obvious one.
  • Deep navy on cream (14:1) — softer, still high contrast.
  • Forest green on off-white (10:1) — brand-friendly, still safe.

Three that fail more than people think:

  • Mid-grey on white (~3.5:1) — borderline, fails in low light.
  • Dark orange on cream (~4:1) — passes math, fails some scanners due to red-channel weakness on mid-tier cameras.
  • Coloured-on-coloured (e.g., navy on light blue) — almost always under 3:1.

Run any candidate combination through a free contrast checker before committing. The number is the truth; the eye lies.

Constraint 2: Logo at most 25% coverage

A centred brand mark on the QR is the most visible "this is ours" cue. It works because QR codes have built-in error correction — a portion of the code can be missing or unreadable and the decoder still recovers the data.

The numbers:

  • Level L: 7% recoverable
  • Level M: 15% recoverable
  • Level Q: 25% recoverable
  • Level H: 30% recoverable

A logo that covers 25% of the code at level Q leaves zero error-correction headroom for print damage, smudges, or low light. Always leave at least 5% spare. So at level Q, cap the logo at 20%; at level H, cap at 25%.

The other thing the tutorials skip: a logo isn't just the area it physically covers, it's the area where the modules become unreadable. A logo with a "halo" or transparent edges where the modules show through still counts as covered for decoding purposes — those modules are damaged. Use logos with a clean opaque shape and a small white border to make sure the boundary between logo-area and code-area is sharp.

Constraint 3: Quiet zone, always

The "quiet zone" is the white border around the QR code. The decoder uses it to lock onto the code's edges. Specification says four modules of margin on every side. Designers under pressure cram codes into tight layouts and lose the quiet zone — and then can't figure out why the code that worked in the proof doesn't work in the print.

Code crammed against background — fails to scan
No quiet zone — fails
Code with full quiet zone — scans reliably
Proper quiet zone — scans

Modern decoders are slightly more forgiving than they used to be, but only slightly. The quiet zone matters more than designers expect. If the code is sitting on a coloured panel, that panel is not the quiet zone — the white area around the modules is.

Constraint 4: Module density, not overall size

Beginner mistake: making the QR code physically smaller because the layout looks busy. The decoder doesn't care about physical size; it cares about how many camera pixels each module gets. Print a code at 1cm where each module is 2px on a phone screen and it'll scan. Print the same code at 0.5cm where each module is 1px and you've halved the contrast resolution and pushed yourself to the edge of failure.

Rule of thumb: the smallest scan distance times 1/30 gives you the minimum side-length of the printed code. A code on a flyer scanned from 30cm needs to be at least 1cm. A code on a billboard scanned from 30m needs to be at least 1m.

That's why dynamic QR codes win in tight layouts — encoding a short link gives you fewer modules per side, so each module gets more printed area, so the code stays scannable at smaller physical sizes.

1cm
Minimum side length for a QR code scanned from arm's length on a phone. Below 1cm and you're trading reliability for layout. The scan distance × 1/30 rule scales it up for posters and billboards.

Constraint 5: Test on three phones, not on the preview

Every QR designer shows a preview that always scans. The preview is rendered on a screen, your phone is right there, and the contrast is artificially high. The print is a different story.

Before approving a print run, do this:

  1. Print one copy at the actual size on the actual paper stock.
  2. Scan it from the actual distance (not closer).
  3. Repeat with three different phones — at least one mid-tier Android, one iPhone, one device with a known mediocre camera (anything older than ~3 years).
  4. Test in three lighting conditions — bright sunlight, indoor fluorescent, dim warm light.

If any of those fail, the design is wrong. Don't ship it.

The decision tree

Quick design check
1 · Contrast ratio dark-to-light ≥ 3:1?
→ if no: pick a darker dark or a lighter light
2 · Logo coverage ≤ 20% of the code area?
→ if no: shrink the logo or bump error correction to H
3 · Quiet zone ≥ 4 modules wide on all sides?
→ if no: add white margin or move surrounding content
4 · Each module ≥ 0.5mm at smallest scan distance?
→ if no: enlarge the code or shorten the encoded URL
5 · Tested on at least three phones and three lighting conditions?
→ if no: don't ship

Pass all five and the code is reliable. Most failed prints we've inspected fail on either constraint 1 (contrast too aggressive in service of brand) or constraint 5 (tested only in office light on a new phone).

Things that look fine but cause subtle failures

A few traps the decision tree won't catch:

  • Gradient backgrounds. A QR code on a gradient can hit the contrast minimum at one end of the gradient and miss it at the other. The phone's exposure adjusts to the bright end, the dark end falls into noise. If you must have a gradient near the code, keep the area immediately around and behind the code uniform.

  • Patterned paper or fabric. A QR code printed on textured paper or polo-shirt cotton loses module sharpness fast. The decoder samples the centre of each module — if that centre falls on a paper fibre, you've introduced false data. Smooth substrates only for production codes.

  • Reflective coatings. Foil, glossy varnish, plastic film. Each shines a glare spot under most lighting that wipes out a strip of modules. If you must use a glossy surface, ensure the code is matte-finished within the print itself.

  • Over-aggressive vector simplification. If the code is exported as SVG and then run through an image optimiser, sometimes the optimiser merges adjacent shapes or rounds geometry in ways that break decode. Always export as PNG at print resolution for production, or test the SVG after the optimiser pass.

  • Blue-spectrum darks. Some phones have weaker blue-channel sensitivity than red or green. A "dark blue" that reads black to the eye can read as mid-grey to the camera. Black, deep navy with green undertone, and dark forest green all work better than royal blue.

What we ship by default

The Linked.Codes QR designer hard-codes the safe defaults and warns when you cross a line:

  • Error correction defaults to Q (25%).
  • Logo overlay capped at 25%; warning past 20%.
  • Quiet zone always rendered, can't be removed.
  • Contrast is checked when you pick custom colours; under 3:1 you get a yellow flag.
  • Round modules render at 105% of cell size to handle the boundary contrast loss.

You can override most of these. Sometimes you should — e.g., turning off the quiet zone if you're embedding the code in a layout that already has white space around it. But the defaults exist because they're what we'd pick if we were doing it for ourselves.

Can I use my brand's exact colours?

If they pass the 3:1 contrast minimum against the background, yes. Most "deep" brand colours (navy, deep red, forest green, charcoal) work fine. Mid-tone brands (mid-blue, orange, mauve) often fail — substitute a darker shade of the same hue family.

What's the minimum size I can print a QR code?

1cm × 1cm for codes scanned from arm's length on a phone. Smaller is possible if the encoded URL is short and the lighting is controlled, but unreliable in field conditions.

Should I use error correction H always?

Tempting, but H produces noticeably bigger codes for the same encoded data. Q is the sweet spot for most cases. Use H when you're doing a centre logo larger than 20% or printing on surfaces that age (cardboard, fabric).

Why does my code scan in the preview but not the print?

Almost always one of three: contrast is lower in print than on screen, the print is below 1cm side length, or the quiet zone got cropped at the printer. Print one and field-test before the full run.

Can I have a QR code with text on top of it?

No — overlaid text covers modules and the decoder can't tell text from data. Put text below or beside the code, never over it.

Are colour-inverted QR codes (white-on-black) reliable?

Yes — modern decoders handle inversion since around 2019. iOS 13+ and Android 9+ both support it. Older devices may struggle, but they're a vanishing share of scans.

What's the easiest way to brand a QR code without breaking it?

Three changes: round modules at 105%, a 20% centre logo with a white border, and dark modules in your brand colour (passing the 3:1 contrast check). That's the recipe behind 90% of the branded QR codes you see in the wild.

Try it on your own domain

Branded short links and dynamic QR codes, on your subdomain or your own domain. One-time purchase, no per-click fees.