A QR Code Decodes at 1.2:1. Do Not Design Anywhere Near It
by KoloQR TeamResearch

Neither Apple nor Google publishes a contrast threshold for the camera apps that read most QR codes, so every number quoted as the iPhone or Android limit is quoted from a measurement nobody has published. What can be read is the source of ZXing, the open-source decoder behind a large share of everything else: it works in 8 x 8 pixel blocks and treats a block whose lightest and darkest pixels are within 24 levels of 255 as containing no edge at all. That is a contrast ratio of about 1.24:1 - a barely visible grey on white. The decoder is not the constraint. Paper that reflects 85% instead of 100%, ink that spreads, glare that lifts the blacks, and a half-millimetre of motion blur are the constraint, and they are why the working numbers are 4:1 on a screen and 7:1 in print.
Key Points
- Neither Apple nor Google publishes a contrast threshold for the QR scanning built into iOS and Android, so a single number quoted as "the" iPhone or Android limit is not a measurement anybody can check. What is checkable is the published source of ZXing, the open-source decoder, and the print-quality standard ISO/IEC 15415.
- ZXing's hybrid binarizer works on 8 x 8 pixel blocks and treats a block whose lightest and darkest pixels are within 24 levels of 255 of each other as containing no edge. Against white, 24 levels is the grey #E7E7E7 - a contrast ratio of about 1.24:1.
- Design at 4:1 for a screen and 7:1 for print, and treat 3:1 as the line below which a code should not ship. The gap between 1.24:1 and 7:1 is not superstition: it is the paper, the ambient light, the glare and the blur that subtract from the design figure before the decoder sees anything.
- A contrast ratio is not what a camera measures. The ratio weights green at 71% of perceived brightness and adds a flare term; a camera's luminance channel weights green at 59% and adds nothing. The two disagree most on saturated red, green and blue, and the ratio is the harsher of the two.
- Blur and low contrast multiply rather than add, because blur averages neighbouring pixels and therefore reduces the lightest-to-darkest spread inside each block - the exact quantity the binarizer thresholds. A code that survives 3:1 in a still photograph fails at 3:1 in a moving hand.
Nobody Publishes the Number, and That Is the Starting Point
There is no published contrast threshold for the QR code scanning built into iPhone and Android cameras. Apple's barcode detection sits inside the Vision framework and Android's inside Google Play Services, both closed, both undocumented on this point, and neither has ever stated a minimum. Any article that names one - 3:1, 4:1, 40% - is either quoting a design guideline written for something else or quoting nothing.
That is worth saying plainly rather than working around, because the shape of the honest answer follows from it. Three things can be established without owning a lab: what an open-source decoder does, because its source is published; what the print-quality standard measures, because it is a published standard; and what any given code does on any given phone, because that takes twenty minutes and a printer. Everything else on this subject is someone's impression.
The reason the question keeps getting asked is that contrast is the one QR code variable a designer controls without meaning to. Module size is a deliberate decision. Error correction is a deliberate decision. Colour is chosen for a brand palette three years before anyone thinks about a QR code, and the code inherits it. So the practical question is not "what is the minimum" but "how much margin does this palette leave me", and that has an answer.
What a Decoder Actually Measures Is a Local Difference
A decoder never compares your foreground colour with your background colour. It converts the camera frame to a single grey channel, decides for each small neighbourhood of pixels where the boundary between dark and light falls in that neighbourhood, and reads modules off the result. Binarization is the step where a decoder turns a grey photograph into pure black and white pixels before it tries to read any modules. Everything about contrast tolerance is decided there.
ZXing is the decoder worth reading, because it is the only widely deployed one whose source is public. Its default hybrid binarizer divides the image into 8 x 8 pixel blocks, computes the lightest and darkest pixel in each block, and sets that block's threshold halfway between them. Below an image dimension of 40 pixels it abandons the local approach and thresholds the whole image at once.
The interesting constant is the guard on that block loop. If the difference between the lightest and darkest pixel in a block is 24 or less, out of 255, ZXing does not compute a threshold from it - it assumes the block contains only light pixels or only dark ones and borrows an estimate from its neighbours. Twenty-four levels below white is the grey #E7E7E7, which is a contrast ratio of about 1.24:1. In a clean digital image with generous module size, that is the floor.
Two consequences follow, and both are more useful than the number itself. The first is that contrast is measured locally, over roughly the area of a few modules, not across the page - which is why a slow gradient behind a code is far less dangerous than it looks, and why a photograph behind a code is fatal. A gradient keeps the local difference intact everywhere; a photograph flips which side of the boundary a module lands on halfway across the symbol.
The second is that contrast and size are the same problem wearing different clothes. The blocks are eight by eight camera pixels rather than eight by eight modules, so how many modules fall inside one block depends entirely on how large the symbol lands on the sensor. A code that fills the frame gets several blocks per module and a threshold computed from that module's own edges. A code shot from too far away gets one block spanning several modules and a threshold averaged across all of them, which is a smaller effective difference from exactly the same artwork. Sizing a code for its scanning distance is therefore part of its contrast budget, not a separate topic.
The Design Number and the Number the Camera Gets Are Different
Everything between the design file and the image sensor subtracts contrast, and the losses compound rather than cancel. This is the whole reason the recommended figures sit six times above the decoder's floor, and it is worth itemising rather than summarising, because most of the items are fixable and the fixes are cheap.
- The paper is not white. Uncoated office and offset stock reflects roughly 80 to 90% of the light hitting it. A 21:1 design ratio does not arrive as 21:1; it arrives as whatever the stock allows before a drop of ink is laid.
- Ink spreads. Dark modules grow into the light cells beside them on absorbent stock, which raises the darkest value and lowers the lightest one inside every block the decoder measures. Kraft, newsprint and thermal receipt paper are the worst offenders.
- Gloss and lamination add light to both. Specular reflection puts the same amount of white light into the dark modules and the light ones, which lifts the black level and compresses the ratio - the same arithmetic as the flare term in the contrast formula. A matte laminate costs a little sharpness and buys back more contrast than it costs.
- Ambient light does the same thing. A code under a shop window in daylight has veiling glare over it. A code in a dim restaurant has a camera pushing its sensor gain up, which adds noise to the very quantity the binarizer measures.
- Automatic exposure is set for the frame, not the code. A dark code on a small light label inside a mostly-dark photograph gets exposed for the dark part, and the label clips towards white with the modules dragged up with it.
- Blur is the multiplier. Focus error and hand motion average each pixel with its neighbours, and averaging is precisely what reduces the lightest-to-darkest spread inside an 8 x 8 block. Low contrast and slight blur do not add up, they multiply, which is why a marginal code passes when someone braces the phone and fails when they do not.
Screens have their own version of the same list, which surprises people who assume a display is a controlled environment. A phone at 20% brightness in sunlight, behind a matte screen protector, showing a code inside a browser that has applied a dark-mode filter to it, is not delivering the ratio the design file says. The design ratio is the ceiling of what is achievable, never the value that arrives.
So the answer to "what contrast do phones need" is that phones need very little and workflows need a lot. The margin you are budgeting is not margin against the decoder. It is margin against the eight things above, none of which are visible on the monitor where the decision gets made.
The Contrast Ladder: A Test That Produces Your Own Number
The way to find the contrast floor for a specific job is to print the same code at eight descending contrast levels on the real material and note where it stops working. This takes about twenty minutes, it costs one sheet of paper, and it produces a number for your printer, your stock and your customers' phones rather than for somebody else's.
The eight rungs below are greys on white, chosen so that each one lands on a round contrast ratio. Generate the same payload eight times, once per foreground colour, keep the background pure white, keep the module shape and size identical across all eight, and lay them out on one sheet in the order given.
| Foreground on white | Contrast ratio | Luminance difference (of 255) | Reflectance difference |
|---|---|---|---|
| #000000 | 21:1 | 255 | 100% |
| #595959 | 7.0:1 | 166 | 90% |
| #7F7F7F | 4.0:1 | 128 | 79% |
| #949494 | 3.0:1 | 107 | 70% |
| #A3A3A3 | 2.5:1 | 92 | 63% |
| #B7B7B7 | 2.0:1 | 72 | 53% |
| #D2D2D2 | 1.5:1 | 45 | 36% |
| #E7E7E7 | 1.24:1 | 24 | 20% |
- Print the Eight Rungs at Final Size on Final Stock. One sheet, all eight codes at the size the real code will be, on the material the real job uses. An office laser print on copier paper is not the test if the job goes on kraft, a bottle label or a menu card - ink spread differs by material and is subtracted from the same budget as the colour.
- Scan Every Rung With Two Phones, Native Camera Only. One iOS and one Android, using the built-in camera app rather than a scanning app. Dedicated scanning apps are more tolerant than the native ones and will pass rungs your customers cannot. Note the first rung that fails on either phone.
- Repeat Under the Light the Code Will Live In. Carry the same sheet to the actual place - the restaurant table, the shop shelf, the outdoor sign at dusk. Lighting moves the failure point by more rungs than any other single variable, and this is the step that gets skipped.
- Repeat at the Real Distance and a Real Angle. Scan from where a person actually stands, and once at roughly 30 degrees off square. Distance reduces the pixels per module, which shrinks the difference each block sees; the angle costs a little more of the same thing.
- Repeat Without Bracing the Phone. Hold it the careless way, one-handed, moving. Blur reduces the lightest-to-darkest spread inside each block, so this run will usually fail a rung earlier than the careful one. The careless number is the real number.
- Design Two Rungs Above the First Failure. Take the worst result across every condition and move two rungs up the ladder from it. Two rungs is the working margin for the variables the test could not include - a different phone, a colder day, a worn print head, a laminate the sample did not have.
One rung deserves a note. The #000000 row is a control rather than a test: if black on white fails on that sheet, the problem is size, focus, glare or the quiet zone, and nothing further down the ladder will tell you anything until that is fixed.
Colour Is Not Contrast, and the Two Metrics Disagree
A colour's contrast ratio is a poor predictor of how a colour behaves on camera, because the two numbers are built differently. A contrast ratio is a single number comparing the relative luminance of two colours, running from 1:1 for two identical colours to 21:1 for black against white. It weights green at 71% of perceived brightness, applies a gamma curve, and adds a small flare term that deliberately penalises dark pairs. A camera's grey channel weights green at 59%, red at 30% and blue at 11%, and adds nothing.
| Colour on white | Contrast ratio | Luminance difference (of 255) |
|---|---|---|
| Black #000000 | 21:1 | 255 |
| Deep navy #0F172A | 17.9:1 | 232 |
| Dark red #7F1D1D | 10:1 | 197 |
| Pure blue #0000FF | 8.6:1 | 226 |
| Brand blue #1D4ED8 | 6.7:1 | 176 |
| Web green #008000 | 5.1:1 | 180 |
| Red #DC2626 | 4.8:1 | 163 |
| Pure red #FF0000 | 4.0:1 | 179 |
| Green #16A34A | 3.3:1 | 144 |
| Magenta #FF00FF | 3.1:1 | 150 |
| Orange #FF7F00 | 2.5:1 | 104 |
| Amber #F59E0B | 2.2:1 | 88 |
| Pure green #00FF00 | 1.4:1 | 105 |
| Cyan #00FFFF | 1.25:1 | 76 |
| Yellow #FFFF00 | 1.07:1 | 29 |
Pure blue is the standout and it is the useful finding in the table. At 8.6:1 and a luminance difference of 226 it sits second only to near-black on both measures, which makes deep blue the safest saturated colour for a QR code by a wide margin. Deep reds and deep plums follow it. Any colour whose ratio comes from being dark rather than from being saturated behaves well. Which palettes that leaves usable, and where they belong, is the subject of colored QR codes.
Pure green is where the two metrics diverge most and where the ratio is worth trusting anyway. Its 1.4:1 ratio looks catastrophic while its luminance difference of 105 matches orange's 104, so the camera sees more in a green code than the ratio implies. It is still not enough: 105 out of 255 is under half scale before the paper, the light and the lens take their share, and green codes are the ones that reliably work in the mockup and fail on the shelf.
Yellow, cyan and amber fail on both measures and there is no technique that rescues them. Yellow on white gives the camera a difference of 29 levels out of 255 - barely above the 24 at which ZXing stops looking for an edge at all. A yellow code is not a risky code, it is a decorative object that occasionally scans in perfect conditions.
The fix when a brand colour does not reach the target is always the same and it is always in one direction: darken the code, do not lighten the background. Backgrounds have to stay near white for the reflectance difference to survive print, and a brand colour taken two or three steps darker usually keeps its identity while doubling its ratio. Where that is unacceptable, put the brand colour in the frame, the label and the call to action around the code and leave the code itself dark - branded QR codes are mostly this, and it costs no contrast at all.
Light Modules on a Dark Background Are a Separate Problem
An inverted QR code - light modules on a dark background - can have a perfect contrast ratio and still fail, because the ratio is symmetric and the decoder is not. White on black computes to the same 21:1 as black on white, and no contrast check anywhere will flag it. What varies is whether the software on the other end is willing to try the image both ways round.
Current iPhone and Android camera apps generally handle inverted codes, and this has improved steadily. Older hardware is where it breaks: fixed imagers, point-of-sale scanners and warehouse equipment frequently expect dark data on a light background and have no inversion pass, and ZXing itself only inverts when the calling application wraps the image in the inverted luminance source it provides - a decision made by whoever built the app, not by the code.
The practical rule is that inversion is a bet on the reader, not a property of the code. For a poster, a screen or a social post read by phones, an inverted code is a reasonable design choice. For anything a customer might scan with unknown equipment, or anything read at a till, it is a coin flip taken for aesthetic reasons, and the safe version - a dark code inside a light panel, on the dark background - costs one rectangle.
There is one more asymmetry worth naming, because it is invisible on screen. Printing a light code on a dark background means laying a large solid dark area, and solid coverage spreads more than sparse coverage does. The light modules are the ones that shrink, and they are the ones the decoder is reading as the light half of the pair. An inverted code therefore loses more contrast in print than the same code the right way round.
What the Print Standard Measures Instead of a Ratio
The QR code world has its own contrast measure and it is not a ratio. Symbol contrast is the print-quality measure defined by ISO/IEC 15415 as the difference in reflectance between the lightest and the darkest point in a symbol. It is expressed in percentage points and graded from A down to F. A verifier reports it alongside modulation, fixed pattern damage, grid non-uniformity and unused error correction, and the symbol's overall grade is the worst of them.
The distinction matters because a reflectance difference and a contrast ratio are not convertible impressions of the same thing. Reflectance is linear light; a contrast ratio applies a gamma curve and a flare term on top of it. Run the arithmetic and the divergence is large: a 40% reflectance difference, the level commonly required in retail specifications, corresponds against ideal white to a contrast ratio of about 1.6:1, and a 70% difference to about 3:1. A colour pair that a web accessibility checker rejects outright can be a perfectly compliant barcode.
That is not licence to design at 3:1. It is an explanation of why the two industries disagree: a verifier measures a printed sample under controlled light at a fixed distance with the symbol filling the aperture, and a designer's ratio has to survive a phone in a pocket. The standard is measuring the artefact, and the ratio is being used as a proxy for the whole chain.
The trap inside the standard is the light it uses. Barcode verification is performed under red illumination at 660 nanometres, the wavelength the original laser scanners used and the one modern verifiers still emulate; a symbol's grade is quoted with it, as in 4.0/20/660. Red ink reflects red light, so a red code on white paper has almost no contrast at 660 nm and grades as unreadable while scanning perfectly on any phone. This is the specific reason a red QR code can pass every check a designer runs and fail at a till or on a warehouse imager.
The rule that falls out of it: anything read by fixed equipment rather than by customers should be black on white, at the size that equipment's documentation asks for, and verified rather than eyeballed. Anything read by phones has the whole colour space available, minus the parts the table above rules out.
The Numbers to Design To
Aim for a contrast ratio of at least 7:1 for anything printed, at least 4:1 for anything shown on a screen, and treat 3:1 as the point below which a code should not ship regardless of how good it looks in the mockup. Those figures are design targets with the losses of the previous sections already priced in, not thresholds anyone measured on a phone. Fifty QR code colour pairs applies those two numbers to a table of named colours, so a palette can be checked against them without doing the arithmetic first.
- Print, uncontrolled conditions - menus, packaging, signage, stickers. 7:1 or better. Black or near-black on white is 21:1 and costs nothing; the gap between 21:1 and 7:1 is where a brand colour fits.
- Print on absorbent or awkward stock - kraft, newsprint, receipts, fabric, engraved surfaces. Do not spend contrast at all. Black on the lightest available background, and put the budget into module size instead.
- Screens - websites, presentations, app screens, video. 4:1 or better, on the understanding that the viewer's brightness and ambient light are outside your control.
- Anything read by fixed scanners, or governed by a specification. Black on white, verified. Colour is a risk with no upside here, and red is a risk with a specific failure mode.
- Below 3:1. Do not ship it. It is not a marginal code that some phones will manage - it is a code whose entire margin is spent before the paper is chosen.
One check that is easy to forget: the three corner markers count. A scanner locates a QR code by its finder patterns before it decodes anything, so a code whose modules are dark and whose corners are set in a pale accent colour has its weakest contrast exactly where the failure is unrecoverable. Whatever tool you use, evaluate the corner colour against the background separately and take the worse of the two figures as the code's real contrast.
KoloQR, a free QR code generator with circular and custom-shaped QR codes, computes that pair automatically: the badge beside the preview reports the contrast ratio for the pattern colour and for the corner colour against the background, shows whichever is worse, and passes at 4:1. It judges a transparent background as white, since that is where a transparent code usually lands. You can set up the ladder in the generator by exporting the same payload at each of the eight greys above and printing the sheet.
The honest limit on everything here: none of these numbers guarantee a scan on hardware we have not tested, and we have deliberately not published a figure for any named phone because we did not measure one. The ladder exists so that you can. Twenty minutes and one sheet of paper produces a number that is true for your job, which is worth more than any figure in this post.
When Contrast Is Not Actually the Problem
Most QR codes blamed on contrast fail for one of four other reasons, and raising the contrast on any of them changes nothing. Working through this list first is faster than running the ladder, because three of the four are visible without a phone.
- The code is too small for the distance. Below roughly 0.4 mm per module in print, phone cameras struggle whatever the colours are. Measure one module before adjusting anything else.
- The quiet zone has been cropped. ISO/IEC 18004 specifies a clear margin of four modules around the symbol, and a designer reclaiming that space for a layout is one of the most common causes of a code that photographs beautifully and never decodes.
- The image was saved as a JPEG somewhere in the workflow. JPEG compression puts faint rings around every module, which lowers the local difference inside exactly the blocks the binarizer measures. It looks like a contrast problem and it is a file format problem.
- Glare. A gloss laminate or a screen reflecting a ceiling light does not reduce the design contrast at all - it adds a bright patch over part of the symbol, and the blocks under that patch lose their difference while the rest of the code is fine. Tilting the phone fixes it, which is the tell.
Error correction belongs on this list too, in the negative. Raising the level from M to H does not help a low-contrast code, because error correction repairs modules the decoder read wrongly and low contrast prevents the decoder from reading the symbol at all. The trade-off between recovery capacity and module size is a real decision, and it is not the lever for this problem. The lever for this problem is a darker foreground, a lighter background, or a larger code.
The related failure worth knowing about, since decoration and contrast are spent from the same budget: decorative module shapes ink less of each cell than square modules do, which reduces the local difference the binarizer measures in the same way low contrast does. What a custom QR code shape actually costs works through that arithmetic, and the two effects stack - a styled code in a pale brand colour is spending twice from one budget.
Make Your QR Code
Free, with no account and no watermark. Choose a shape, add a logo, check the contrast, and export SVG, PDF, EPS or PNG - a static code with no subscription behind it.
Generate QR CodeQuestions? Answered
As a design target, 7:1 for print and 4:1 for screens, with 3:1 as the line below which a code should not ship. The decoder's own floor is far lower - ZXing stops detecting an edge when the lightest and darkest pixels in a block differ by 24 of 255, about 1.24:1 - but that floor applies to a clean digital image, not to ink on paper under a shop light.
Neither Apple nor Google publishes a threshold, so any specific figure you see quoted is not a measurement anybody can check. Both decoders are closed source. The only readable reference point is ZXing, which gives up at about 1.24:1 on a clean image, and the practical answer for a real job is to print a ladder of descending contrast levels and find where your own combination of stock, light and phones fails.
Because a screen delivers the design contrast and paper does not. White stock reflects 80 to 90% rather than 100%, ink spreads into the light cells beside each dark module, and gloss or ambient light adds a bright veil over both. A pair that computes to 3:1 in the design file can arrive at the camera closer to 2:1. Test on the real material at final size, never on a monitor.
Usually, if the colour is dark rather than merely saturated. Deep blues, navies and dark reds all clear 7:1 against white and behave well on camera. Oranges, ambers, cyans and yellows do not, and no error correction level rescues them. When a brand colour falls short, darken the code rather than lightening the background - or keep the code dark and put the brand colour in the frame around it.
On current phones, usually. On older or fixed scanners, often not. A contrast ratio is symmetric, so white on black computes to the same 21:1 as black on white and no contrast check will warn you - what varies is whether the reader tries the image inverted. Inverted codes also lose more contrast in print, because solid dark coverage spreads into the light modules. Use them where phones are the only reader.
A gradient usually survives and a photograph usually does not, and the reason is that decoders threshold locally. ZXing computes a separate light-dark boundary for each 8 x 8 pixel block, so a background that changes slowly keeps the local difference intact everywhere. A photograph changes faster than the code does, so somewhere across the symbol the modules end up on the wrong side of their own block's threshold.
Because barcode verifiers and many fixed scanners read under red light at 660 nanometres, and red ink reflects red light. A red code on white paper has almost no contrast at that wavelength even though a colour camera sees it clearly. This is a known trap from the 1D barcode world and it applies unchanged to QR codes. Anything scanned by fixed equipment should be black on white.
Not on white. Yellow on white gives a camera a luminance difference of 29 levels out of 255, barely above the 24 at which ZXing stops looking for an edge at all, and a contrast ratio of 1.07:1. Pastels sit only slightly better. If a pale palette is the requirement, invert the problem: a dark code inside a pale panel keeps the palette and keeps the contrast.
No, and this is the most common wrong fix. Error correction repairs modules that were read incorrectly; low contrast stops the symbol being read at all, because binarization happens before any data exists to repair. Raising the level from M to H also makes the symbol denser at the same printed width, which shrinks every module and makes a marginal code worse rather than better.
More, in the sense that failure there is unrecoverable. A scanner locates a QR code by its three corner markers before it decodes anything, so pale corners on a dark code put the weakest contrast exactly where error correction cannot reach. Evaluate the corner colour against the background separately and treat the worse of the two figures as the code's real contrast.
Keep Exploring
Pages that pick up where this one leaves off - the same setting, the same kind of code, or the next thing worth deciding.
Retail Stores
Product details, stock and review links on shelf labels, shop windows and checkout signs.
Event Agencies
Codes produced for someone else's event: client redirects, exhibitor spec sheets, badge runs and signage sized for the room.
Colored QR Codes
Put your palette on a QR code without breaking it: which color goes on the pattern, and which belongs on the frame.
Banners
Roll-ups, exhibition and outdoor banners - the size the distance demands, the height that works, and why mesh and wind break scans.
Vehicles
Vans, cars and fleet livery - the size a code needs at the kerb, and the part of the bodywork where it survives rivets, seams and road film.
A QR Code in a Video Ad Needs a Third of the Screen. It Gets a Corner
A QR code in a video ad has to be a quarter to a third of the screen height before a phone on the sofa can read it. Almost every one you have seen is a corner logo, and we measured what happens to those.
Why KoloQR?
- Create QR codes for websites, menus, Wi-Fi, PDFs, and business cards
- Customize colors, logos, and unique shapes
- Download high-quality PNG and SVG files
- Built for both print and digital

