Docs · Guide

Do styled QR codes still scan

Usually, and the limit is measurable rather than a matter of taste. A QR symbol carries spare capacity for damage, and styling spends it: a centre logo, a coloured fill, rounded modules and a frame all draw on the same margin that was there to survive scuffing, ink spread and a bad angle. Three styling choices are not a tradeoff but a failure, measured on real renders: separated-circle modules, module colour closer than 3:1 to the background, and a pale finder square in the corners. Everything else is budget, and the only way to know how much of it you have left is to render the code and read it back with a decoder.

Every builder will let you make the pretty version. Far fewer will tell you what it cost, because telling you means rendering the artwork and decoding it again. This page is what we measured, including the two designs we built and then refused to ship.

What error correction actually buys

A QR symbol encodes its content twice over: the data, and enough Reed-Solomon parity to reconstruct the data when part of the symbol is unreadable. The level is chosen when the code is generated, and it fixes how much of the symbol can be missing before the payload is lost.

  • Level L recovers about 7% of codewords · the smallest symbol for a given payload, and the least room for anything to go wrong.
  • Level M recovers about 15% · what a taproute code is encoded at unless it carries a logo or you pick a level yourself.
  • Level Q recovers about 25% · the industrial middle.
  • Level H recovers about 30% · forced automatically the moment a logo is added, because a logo is damage you are planning in advance.

The important part is that this budget is spent once. It was never free capacity waiting for a brand mark; it is what lets the code survive a scuffed carton, a thermal printhead running dry, glare off a laminate, a curved bottle and a phone held at an angle. A logo sized to consume the whole of level H decodes perfectly on your monitor and arrives in the world with nothing in reserve. That is why the studio caps the logo slider at 50% of what the level can recover and keeps the rest back, rather than letting the design use every codeword the standard would allow.

Raising the level is not a free upgrade either, and this is the piece most advice gets backwards. More parity means more codewords, which pushes the symbol to a larger version with more modules across. Printed at a fixed width, every module gets smaller, and a module has a practical floor of about 0.4mm for a phone camera at arm's length. The studio derives the minimum print width from the module count on that basis, and quotes the readable distance at 10 times the symbol width. Level H behind a logo is the right trade. Level H on a small print because it sounds safer is usually the wrong one.

The three styling choices that measurably do not read

These are not warnings. Each was measured against the real renderer by rasterizing the design and decoding it back, and each fails, so the API refuses to save a design that introduces one and returns the reason and the remedy rather than a bare rejection.

  • Fully separated circular modules · the style every builder calls "dots". The gaps between the circles break the sampling grid a reader lays over the symbol. The failure is not that it always fails, which would be easy to live with. It is erratic: swept across a ladder of pixel sizes it decoded at some and failed at others, with no pattern a designer could predict or design around. taproute still renders it, because codes styled before the rule existed have it saved and rewriting somebody's design without asking is worse, but the picker does not offer it. The rounded style people actually want is available and reads at every size.
  • Module colour closer than 3:1 to the background · a light grey fill on white, or a gradient whose lightest stop fades toward the paper. Both are checked at the worst stop rather than the average, and against every stop of a background gradient, because a fill is only as readable as its most hostile corner.
  • A pale finder square · the three corner patterns, coloured independently of the modules. This is the one that surprises people, and it is the most important line on this page: error correction cannot save the finders. A reader that cannot locate the symbol never gets as far as the codewords, so no amount of parity helps. Pale finder rings and pale finder centres failed at every size on the ladder, and a mid-grey finder at a 2.4:1 ratio decoded at exactly one of six sizes, which is the erratic failure again.

Three other things the studio flags but does not block, because they decode: a transparent background (fine on white, undefined on whatever the artwork actually lands on), a light-on-dark symbol (permitted by the standard, coped with by most readers, and still the cheapest scanner in a print run is not most readers), and a logo past the reserve but inside the budget. Those are judgement calls that belong to whoever is buying the print, not to us.

Two designs we built and then refused to ship

Both looked good. Both were killed by the same measurement, and they are here because a page that only lists what we shipped tells you nothing about where the edge is.

  • A diamond finder centre · a rotated square in the middle of each corner pattern, which at half the area of the three-by-three centre is a genuinely pretty mark. It decoded erratically depending on which finder ring it was paired with: fine with some rings, failing with others, at the same sizes. Dropped outright in July 2026. It is not in the picker and the note explaining why sits next to the code that would have drawn it.
  • A caption set free above the symbol · plain text on paper above the top two finders, which is the obvious way to build a header frame. A long caption in a heavy typeface decoded erratically by size, failing at one large size or another depending on the string. The cause is specific and worth knowing: a dense line of bold text forms false locator candidates, false runs that look enough like a finder pattern for a reader to chase them. The same caption knocked out of a solid ink bar reads at every size, because the bar's mass leaves no such runs to hallucinate on. So the header frame ships as an ink bar. A caption below the symbol never had the problem.

A third case is invisible rather than aesthetic, and it is the defect that shaped how the whole renderer emits geometry. Adjacent module shapes drawn as separate elements composite their antialiased edges independently, leaving a hairline light seam down every join between two dark modules. It is invisible to a human and lethal to a decoder: the seam clears the minimum dynamic range a binarizer needs to treat contrast as real, so the block threshold drops and the seam is binarized white. A phantom white line through a dark run breaks the symbol. The fix was structural rather than cosmetic. Every touching module goes into one path, so the shared edges cancel and no boundary is rasterized at all, and a test asserts that no light pixel survives inside a dark run for any module style we offer.

How a style earns its place: the decode gate

A shape bug in a QR renderer does not throw and does not look wrong in a preview thumbnail. It produces a beautiful code that no reader can decode, and the first person to find out is holding a print run. So no style at taproute is offered on taste. Continuous integration renders the symbols, rasterizes them through a real headless Chromium on the same path the studio's PNG export uses, and decodes the pixels back with jsQR, asserting the exact URL comes out.

  • Every module style, every finder ring, every finder centre · the ring and centre families are swept as a full cross product, not a hand-picked sample.
  • A size ladder from 192 to 768 pixels · the admission bar for a new style is that it reads at every rung. Reading at most of them is what the separated-circle style does, and it is the thing we refuse to ship.
  • Every preset and every palette, twice · once at 512 pixels and once at 256, which is roughly a code printed at 22mm and read by a phone. Presets and palettes are one tap from a print run, so a preset that stopped scanning would be an outage rather than a styling bug.
  • Every frame in the enum, with a caption, decoded as a whole card · none hand picked, so a frame that crowds the symbol fails the moment it is added rather than when a customer prints it.
  • Every logo in the built-in library · each mark decoded at the largest size the studio offers, with the densest marks swept further: knockout off, at the error correction cap, and down at 256 pixels.
  • Background gradients, multi-stop fills and independent finder colours · the light-to-mid direction specifically, because that is the one that erodes module contrast.

Two parameters in the shape geometry are calibrated by that sweep rather than chosen by eye: a chamfer depth and a corner notch depth. The first candidate for one of the chamfer styles was cut deeper, failed at the top of the ladder in the erratic way, and was reworked shallower until it passed. The depth is not cosmetic, and the code says so where somebody might be tempted to deepen it.

The check that runs on your own design, and what it cannot tell you

The gate above proves the vocabulary. It says nothing about the specific combination you built out of it, so the studio measures that too, on the design in front of you. It rasterizes your actual code at ascending widths and decodes each one, and reports the smallest width that still reads. If none of them read, it says the code did not decode, in those words, rather than showing a green badge with a caveat underneath.

Two decoders run, and the difference between them is reported rather than averaged away. jsQR models the everyday phone and is the gate. ZXing at its stock settings models the stricter fixed scanner at a till or a warehouse door, and it is consulted second. When the phone decoder reads a design and the strict one does not, the panel says exactly that, because a design headed for a point of sale can be simplified and a design headed for a poster probably does not need to be. Alongside the measurement the panel predicts what it can predict: the ISO 15415 symbol contrast grade, whether the symbol is inverted, how much of the recovery budget the logo has taken, and the minimum print width. The free static QR generator runs a lighter version of the same check, badge and minimum print width only.

Now the honest half. A decode on a screen is not a print verification, and this page will not pretend otherwise. A real ISO 15415 grade needs a calibrated hardware verifier reading reflectance off the printed piece, which is a machine we do not have and cannot simulate. Ink spread on uncoated stock, a laminate that throws glare at the angle people actually hold a phone, a label wrapped around a small-diameter bottle, a substrate whose white is not white: none of that is modelled by anything above. That is why the pre-press proof sheet the studio prints says what was measured and names the decoders that measured it, and never uses the word certificate. For a code already in the world, our free decoder reads a photograph of it back with every recovery option turned on, which tells you what the print still carries.

Where taproute comes into this

Styling is not a paid tier here and there is nothing on the rate card for it. A dynamic code costs 1 credit to create, once, and 1 credit per scan, prepaid, with no subscription. Restyling it, re-exporting it and printing the proof sheet cost nothing, because the design is a column on a row we already sold you and not a feature to meter. Credits are valid 18 months and any top-up rolls the whole balance forward.

Our own failure mode, in the same breath. At a zero balance scans keep resolving for 14 days or 5% of your last top-up, whichever ends first. After that a scanner sees a paused page saying whose code it is, never a 404 and never an ad, and topping up resumes the same printed code instantly. That has nothing to do with how the code is styled, which is the point: a design decision should never be able to turn a printed code off, and here it cannot. The renderer takes the address and the design as separate inputs, so a restyle changes what the next export looks like and never what the pattern already in the world says.

Questions

Do styled QR codes still scan?

Usually, and the limit is measurable rather than a matter of taste. A QR symbol carries spare capacity for damage, and styling spends it: a centre logo, a coloured fill and a heavy frame all draw on the same margin that was there to survive scuffing, ink spread and a bad scanning angle. At the highest error correction level a reader can recover a symbol with about 30% of its codewords unreadable, and a logo is simply a planned piece of that damage. Three styling choices are not a tradeoff but a failure, and they are listed on this page.

Does putting a logo in the middle break a QR code?

Not on its own. Adding a logo forces the symbol up to error correction level H, which raises recovery capacity to about 30% of codewords, and the studio caps the logo slider so it can never spend more than half of that. What the reserve is for is everything that happens after the file leaves you: ink spread, a scuffed carton, glare off a laminate, a phone held at an angle. A logo that eats the whole budget still decodes on your screen and has nothing left for the world.

Which QR code styles actually fail to scan?

Three, on our measurements. Fully separated circular modules, because the gaps break the sampling grid: that style read at some pixel sizes and failed at others, with no pattern a designer could work around. Module colour closer than a 3:1 contrast ratio to the background. And a pale finder square in the corners, which is the one part of the symbol error correction cannot rescue, because a reader that cannot locate the symbol never reaches the codewords at all. All three are refused at save time rather than warned about.

Is a higher error correction level always the safer choice?

No, and this is the advice most guides get backwards. Raising the level adds codewords, which pushes the symbol to a larger version with more modules across. At a fixed printed width that makes every module smaller, and a module has a practical floor of about 0.4mm for a phone camera. So level H buys damage tolerance and spends physical module size. On a business card it can be the wrong trade; behind a logo it is the right one, which is why a logo forces it and nothing else does.

How can I check a styled code scans before I print it?

Render it and decode it, at the size it will be read at, on the artwork it will sit on. A preview is not a check. In the taproute studio that runs automatically: your actual design is rasterized and read back by two decoders at ascending sizes, and the panel reports the smallest width that still works, or says plainly that it did not decode. For a code that is already printed, photograph it and paste it into our free decoder.

Does restyling a code change what it encodes?

No. The renderer takes the address and the design as separate inputs, so changing colours, module shapes, the logo or the frame changes the artwork and never the text inside the pattern. A code already printed and out in the world is unaffected by anything you do on the design tab. What a restyle changes is what the next export looks like.