Elton Lab
Lab online Depth 000% Series two · zero uploads

How QR codes actually work.

A QR code looks like noise, but every square in it has a job. Here is what a camera sees, in the order it sees it, and why a scratched code still scans.

A grid of yes and no

A QR code is a square grid of cells, called modules. A dark module is a one, a light module is a zero, and the whole code is nothing more than a long string of bits laid out in a shape a camera can find. The smallest code, version 1, is 21 modules across. Each version up adds four modules to each side, and version 40, the largest, is 177 across and holds close to three thousand bytes. The generator on this site picks the smallest version that fits your text, because smaller codes have bigger modules and bigger modules scan from further away.

The three big squares

The first thing a scanner looks for is the three large nested squares in the corners. They are called finder patterns, and they are designed so that a line drawn through them in any direction crosses dark and light in the ratio 1:1:3:1:1. That ratio is the same whether the code is upside down, tilted, or photographed at an angle, which is why a phone can lock onto a code before it has worked out anything else about it. The fourth corner is empty on purpose: three corners are enough to know which way is up.

Between the finder patterns run the timing patterns, a single row and a single column of alternating dark and light modules. They tell the scanner how big a module is, so it can count its way across the grid even if the print is slightly stretched. Larger codes also scatter smaller alignment patterns across the middle to correct for curved or warped surfaces.

Where your text goes

Your data is not stored as plain letters. It is first converted into one of four modes. Numeric mode packs three digits into ten bits, alphanumeric mode packs two characters into eleven bits, byte mode stores raw bytes, and kanji mode handles Japanese. The encoder here uses byte mode with UTF-8, because that is the only mode that can hold any text you type, including addresses with accented letters and emoji.

The result is a stream of bytes: a short header saying which mode and how long, then the content, then a terminator, then padding to fill the version out. That stream is then split into blocks, and each block gets something added that makes the whole system work.

Why a damaged code still scans

Every block of data is followed by a set of error correction codewords calculated with Reed–Solomon coding, the same family of maths that lets a scratched CD play. The codewords are redundant in a clever way: from any large enough subset of the total, the original data can be reconstructed exactly. The four error correction levels decide how much redundancy is added.

LevelCan recover aboutBest for
L7% of the codeClean screens, short-lived links
M15%Most print, the default
Q25%Packaging, outdoor use
H30%Codes with a logo placed over the middle

This is also why a logo can sit on top of a code. The logo simply destroys some modules, and as long as fewer are destroyed than the level can recover, the scanner never notices. It is the same mechanism that saves a code from a coffee ring, a fold or a bit of tape.

The mask, or why codes look random

Once the data and error correction bits are laid into the grid in a zigzag from the bottom right corner, the encoder applies a mask. A mask flips modules according to one of eight simple patterns, such as every other row, or a checkerboard. The point is to avoid large blocks of the same colour and, above all, to avoid accidentally producing the 1:1:3:1:1 finder ratio somewhere in the middle, which would confuse the scanner about where the corners are.

The encoder tries all eight masks, scores each result with a set of penalty rules, and keeps the one with the lowest score. A small strip of format information next to the finder patterns records which mask was used and which error correction level, so the scanner can undo the mask before reading anything. That strip is written twice, in two places, because losing it would make the whole code unreadable.

The quiet zone

The empty margin around a code is part of the standard, not decoration. It needs to be at least four modules wide so that the scanner can tell where the pattern ends and the background begins. Cropping it off is the single most common reason a printed code fails, and both downloads from the QR Code Generator include it.

What the scanner does with the result

After decoding, the phone has a string of text and nothing else. It looks at the start of that string to decide what to offer: something beginning with https:// opens as a link, mailto: opens a draft email, tel: offers a call, and anything else is shown as text. There is no registry, no lookup and no round trip to a server. That is the reason a plain QR code cannot expire, and also the reason it cannot count how many people scanned it.

Ready to make one? The QR Code Generator builds the whole thing in your browser, from mode selection to mask scoring, and lets you download it as SVG or PNG.