Polyatic
All tools

QR Codes Explained

A QR code looks like random noise, but almost none of it is random. It is a two-dimensional matrix barcode — a grid of black and white squares that stores data along both axes instead of in the width of stripes, which is why it holds far more than the one-dimensional barcode on a cereal box. Invented in 1994 by Denso Wave to track car parts, it is now defined by the international standard ISO/IEC 18004. This guide takes one apart from first principles: the fixed patterns a scanner hunts for, the blank margin it needs, the four ways your text is packed into bits, how the grid grows, the four error-correction levels, and the Reed–Solomon maths that lets a torn or logo-covered code still read.

To take one apart as you read: Try the QR Code Generator → — it builds a code from a URL, text, WiFi or contact, shows the version and error-correction level the code ends up at, and reads an existing code back from an image. Everything runs in your browser; nothing is uploaded.

Live: a real QR code, taken apart Type anything — the code redraws as you type, and each layer colours the modules that part of the standard owns. Runs in your browser; nothing is uploaded.
Error correction
Mode
alphanumeric
Version
1
21×21 modules
EC level
M
Mask
–
Capacity used
–

    Drawn by the same encoder as the QR Code Generator. It picks one mode for the whole text — numeric, alphanumeric, else UTF-8 byte — and never mixes segments or uses kanji mode, so for mixed text a specialist encoder can sometimes land one version smaller. The mask and EC level are read back out of the drawn format bits, not assumed; for small single-block codes the mode header is too.

    The single black or white square in a QR code is called a module. A scanner cares only whether each one is dark or light, not how many pixels or millimetres it spans — which is why the same code works on a phone screen, a business card, or a billboard. Some modules are fixed scaffolding, some carry your data, and some carry error correction that repairs the data if part is lost.

    The fixed patterns: scaffolding a scanner can find

    Before a scanner can read a single bit of your content, it has to locate and orient the code in a camera frame that may be rotated, skewed or badly lit. Structural patterns identical in every code make that possible:

    • Three finder patterns — the big square "bullseyes" in the top-left, top-right and bottom-left corners. Each is a 7×7 module ring with a consistent 1:1:3:1:1 dark-light ratio along any line through its centre. That ratio is rare in natural images, so a reader spots the three squares fast and, because there are exactly three (not four), works out which way is up. Highlight them ↑
    • Alignment patterns — smaller 5×5 rings that appear from version 2 onward, more of them in larger codes, letting the scanner correct for perspective distortion when the code is photographed at an angle or printed on a curved surface. See one at version 2 ↑
    • Timing patterns — a single row and column of alternating dark-light modules running between the finders. They act like a ruler, telling the reader the exact module pitch so it can count grid lines even when the image is stretched. Highlight them ↑
    • Format information — a small band of modules near the finders recording which error-correction level and mask were used, so the decoder knows how to read the rest. Highlight it ↑

    Only after that scaffolding is found does the reader walk the remaining modules to recover your data. It costs modules that could have held content, but it is what makes a QR code readable from any angle almost instantly.

    The quiet zone: the margin that isn't optional

    Around every QR code is a mandatory blank margin called the quiet zone, at least four modules wide on all sides. It is not decoration — the scanner uses that uniform light border to tell where the code ends and the busy background begins. Crop a code tight to its edge, or set it on a patterned surface with no margin, and readers that could otherwise decode it perfectly will simply fail to find it. It is the single most common reason a technically valid code won't scan.

    Shade the quiet zone on the live code ↑ — it adds 8 modules to the width of every code.

    Four encoding modes — and why the mode sets capacity

    A QR code stores bits, not characters, and how efficiently your text becomes bits depends on the mode the encoder picks. The standard defines four, each tuned to a different alphabet:

    ModeAlphabet it handlesBits per character
    Numericdigits 0–9 only~3.33 (10 bits per 3 digits)
    Alphanumeric0–9, A–Z (capitals), space and $ % * + - . / :~5.5 (11 bits per 2 chars)
    Byteany byte, i.e. arbitrary UTF-8 text8
    KanjiShift-JIS Japanese characters13

    The narrower the alphabet, the fewer bits each character needs, so the more characters fit the same grid. Byte mode spends a full 8 bits per character because it must represent anything, while numeric squeezes three digits into 10 bits — which is why a phone number encodes into a much smaller, easier-to-scan code than the same count of letters, and why an encoder always uses the most restrictive mode your content allows.

    Worked example: HELLO vs a URL

    The word HELLO is all capital letters, every one in the alphanumeric set, so it encodes in alphanumeric mode at about 5.5 bits per character — roughly 28 bits for the five letters. Compare a real link:

    "HELLO" every char is in the alphanumeric set (A–Z) → alphanumeric mode, ~5.5 bits/char → ~28 bits "https://polyatic.com/" lowercase letters + "//" are NOT in the alphanumeric set → must fall back to byte mode, 8 bits/char → 168 bits

    The URL's lowercase letters aren't in the alphanumeric set, so the encoder falls back to byte mode and spends a full 8 bits on every one of its 21 characters — several times the bits for a similar character count. This is why keeping a QR payload short and, where possible, uppercase-and-numeric produces a smaller, more scannable code.

    Load either into the live code: HELLO — alphanumeric, version 1 ↑ · https://polyatic.com/ — byte, version 2 ↑

    Versions: how the grid grows

    QR codes come in 40 standard sizes called versions. Version 1 is 21×21 modules, and every step up adds four modules to each side: version 2 is 25×25, version 3 is 29×29, on up to version 40 at 177×177. More content, or a higher error-correction level, forces a larger version. The trade is physical: a low version has big, bold modules that scan easily at small print sizes, while a version near 40 is so dense it demands a large, crisp print. A good encoder always uses the smallest version that fits your data at the chosen level.

    Load a 98-character tracking link ↑ — it lands at version 6 (41×41) at level M.

    The four error-correction levels

    Part of every QR code is deliberately redundant: it carries extra error-correction data so the content survives smudges, tears, or a logo dropped on top. The standard defines four levels, their recovery capacities fixed by the QR specification:

    LevelRecovers up toBest for
    L (Low)~7% of the codeclean screens, digital display
    M (Medium)~15%general use — the common default
    Q (Quartile)~25%print handled outdoors
    H (High)~30%logo overlays, harsh conditions

    Those four figures — roughly 7%, 15%, 25% and 30% — are the spec-defined values, not a rule of thumb; they measure the fraction of total codewords that can be lost or wrong while the message stays perfectly recoverable.

    Switch HELLO WORLD to level H ↑ — at M it fits version 1 with 10 of 26 codewords spent on error correction; at H it needs version 2, where 28 of 44 are.

    The honest capacity-vs-resilience tradeoff

    Error correction is not free — every redundant module is one that cannot hold your content. In a fixed-size grid, choosing level H instead of L roughly halves how much data fits, because far more of the grid is spent on recovery. So it is a genuine tradeoff: hold the version fixed and higher correction means less capacity; hold the content fixed and it means a larger, denser code. There is no universally best level — match it to how the code will be handled.

    Why a damaged or logo-covered code still scans

    The error correction is Reed–Solomon coding, the same family of maths used on CDs and deep-space probes. It adds redundant "check" codewords that over-describe the data, so a decoder can rebuild the message even when some codewords are missing or wrong — as long as the damage stays within the level's budget (about 7% at L, up to 30% at H).

    This is why a company logo in the middle of a QR code still reads: the logo destroys some modules, but as long as the lost fraction is under the budget, Reed–Solomon fills them back in — the same reason a code survives a coffee ring, a crease, or a partly torn poster. The catch is the same tradeoff: a logo covering more than the budget breaks the code, which is why logo codes use level H and keep the logo modest.

    Colour the Reed–Solomon codewords on the live code ↑ and switch levels to watch their share change.

    Generate a QR code right now

    Type a link, WiFi login or contact card and watch it encode live, with an error-correction selector and a capacity meter that shows the exact version your content needs — everything runs in your browser, nothing is uploaded.

    Try the QR Code Generator →

    Questions people ask

    The sections above describe how a code is built. These are the questions that come up once you have to put one on something real — a card, a window, a poster, a payment sign.

    How long can a URL be before the code gets too dense to scan?

    There is no character limit in the standard, only a density limit you can read straight off the version table. At level M, the usual default, a 21-character link such as https://polyatic.com/ fits in version 2 (25×25 modules); 50 characters needs version 4 (33×33); 100 characters needs version 6 (41×41); 200 characters needs version 10 (57×57); and 300 characters needs version 13 (69×69). Since the printed width is usually fixed by your layout, every version step makes each module physically smaller, so the real ceiling is how fine a module your printer and the scanning camera can still resolve — not the spec. As a working rule for a code a phone reads at arm's length off a card or a screen, keep the payload under about 100 characters and you stay at or below version 6. Tracking parameters are the usual thing that blows the budget: https://polyatic.com/qr-code-generator/ is 39 characters and encodes at version 3, but adding ?utm_source=newsletter&utm_medium=email&utm_campaign=spring takes it to 98 characters and version 6 — three steps denser for a tail nobody reads.

    Can I change where a printed QR code points?

    Not if the destination is baked into the pattern, and in a static code it is: the modules are the payload, so a code carrying https://example.com/spring holds those exact bytes and nothing short of reprinting changes them. Commercial "dynamic" QR codes work around this by encoding a short redirect URL owned by a QR vendor — the printed pattern never changes while the vendor's server can be repointed at a new destination. The cost is a permanent dependency: the code goes dead the day that redirect is switched off, the vendor folds, or the subscription lapses, and it hands your scan data to a third party. Polyatic's generator makes static codes only, so what it produces keeps working with nobody's servers involved. If you know the target may move, the honest fix is to encode a URL on a domain you control and run the redirect yourself.

    Do QR codes expire?

    The symbol never does. ISO/IEC 18004 defines no timestamp, no expiry field and no scan counter — a static code is a fixed arrangement of light and dark that will decode to exactly the same string in fifty years as it does today, provided the print survives and the quiet zone stays clear. What expires is always whatever the string points at: a domain that lapses, a WiFi password that gets rotated, a menu page that is deleted, or a vendor's dynamic redirect that stops resolving. So "this QR code expired" is shorthand for something on the other end going away, never for the squares wearing out.

    How small can I print one?

    The standard fixes module counts, not millimetres, so the printed size is your decision — but the arithmetic is short. Count the quiet zone first: the mandatory four-module margin on each side means the footprint is the version's module count plus eight. A version 4 code is 33×33 modules, so 41 module-widths across once the margin is included; a version 10 is 57×57, so 65. Print practice commonly treats about 0.4 mm as the smallest comfortable module, which puts that version 4 at roughly 16 mm square and that version 10 at roughly 26 mm. The companion rule of thumb is that a code reads from about ten times its printed width, so a 2 cm code is comfortable at 20 cm and a code meant to be scanned from across a room has to be sized for that distance, not for the page. Both figures are practical print guidance rather than anything in ISO/IEC 18004, so the only real test is to print at final size and scan it with the worst phone you can find.

    Can a QR code carry a virus?

    Not in any direct sense. A QR code is a container for a string of bytes — the standard has no concept of executables, scripts or attachments, and the largest symbol there is, version 40 at level L, tops out at 2,953 bytes of data. The risk lives entirely in what the string says and what you do next. Most payloads are URLs, so the realistic attack is ordinary phishing: a sticker pasted over the genuine code on a parking meter or a restaurant table sends you to a lookalike page. Both iOS and Android show the decoded destination in a banner you have to tap before anything opens, which makes the defence the same one you use on email links — read the host in that banner before tapping. Payloads that are not links deserve equal care, since a WIFI: string can join you to someone else's network and a tel: one can place a call.

    Why does one phone read a code that another refuses?

    The symbol is identical; the camera and the decoder are not, and three things vary between devices. Optics first: a camera that cannot focus close enough, or is being used at an awkward distance, may never bring individual modules into focus on a dense code. Then resolution — a decoder has to sample each module out of the camera image, and the usual practical recommendation is three to four camera pixels per module; below roughly two it cannot reliably separate a module from its neighbour. Last, tolerance: readers differ in how much they forgive, particularly a clipped quiet zone, weak contrast, glare off a laminated card, or a steep viewing angle. The image itself contributes too, from a screen dimmed to save battery to a label wrapped round a bottle. When a code fails on one device only, the productive response is to make the symbol easier rather than argue with the phone: fewer characters, a lower version, a bigger print, more margin.

    Will a light-on-dark or recoloured code still scan?

    Colour is fine; polarity and contrast are where it goes wrong. The decoding procedure in the standard is written around dark modules on a light background, and that is the arrangement every reader is guaranteed to try. Many decoders also attempt an inverted pass, so a light-on-dark code often does work — but "often" is the honest word, and a payment poster is a poor place to discover the exception. The subtler trap is that a scanner works from luminance, not hue: two colours that look strikingly different to you, such as a mid-red on black, can sit close enough in brightness that the reader never resolves the grid at all. If you recolour, keep the modules clearly darker than the background, judge it in greyscale rather than by eye, and test the actual printed or displayed artwork instead of the design file.

    Why do two generators produce different-looking codes from the same text?

    Masking — the step whose result the format-information band records. Left alone, a data region can easily come out with big blank patches or long stripes that make a scanner's job harder, so the encoder XORs it with one of eight standard mask patterns, scores each outcome against four penalty rules (long runs of one colour, 2×2 blocks of one colour, sequences that imitate a finder's 1:1:3:1:1 ratio, and an overall dark-to-light imbalance), and ships the lowest-scoring version. Two encoders that pick a different mode, version or error-correction level will usually land on a different mask as well, so the same URL can produce two images with no visible resemblance that decode to exactly the same string. There is no single "correct" picture for a given payload, which is also why comparing two codes by eye tells you nothing.

    Does a WiFi QR code give away my password?

    Yes, to anyone who can photograph it. A WiFi code is not an authentication handshake — it is the plain string WIFI:T:WPA;S:NetworkName;P:password;; encoded like any other text, so the password sits in the pattern in the clear, and any decoder will print it back out. You can prove that to yourself with the Decode tab of the QR Code Generator: feed it a photo of a WiFi code and the password appears as text. That is perfectly reasonable for a guest-network card you hand to visitors, and a bad idea for a code taped in a street-facing window or included in a photo posted online. A printed code cannot be revoked, only reprinted — so if one has been somewhere public, rotate the password.

    Putting it together

    A QR code stops looking like noise once you can name its parts: three finder squares plus timing and alignment patterns let a scanner find and orient it, the four-module quiet zone marks its edge, your text is packed into bits by the narrowest mode that fits its alphabet, the grid grows in 4-module steps from 21×21, and a slice of every code is Reed–Solomon redundancy that repairs damage up to the L/M/Q/H budget. Keep the payload short, leave the quiet zone alone, and match the error-correction level to the job.

    Open the QR Code Generator → and watch the version and capacity meter respond live, or browse all Polyatic tools.