How do QR codes work?
A short, honest tour of what's actually going on inside those little black-and-white squares — finder patterns, error correction, and why a damaged QR still scans.
- explainer
- anatomy
A QR code looks like noise. It isn’t. Every dot has a job, and the design is the result of a surprisingly clever engineering problem from 1994: how do you make a barcode that a cheap camera can read at any angle, in bad light, even if part of it is missing?
Here’s the short version of how it actually works.
A QR code is a grid of black and white squares
The dots are called modules. A QR code is just a grid of them, where black means 1 and white means 0. The smallest QR is 21×21 modules; the largest the spec allows is 177×177. Every QR you’ve ever scanned is somewhere in that range.
What turns this grid into something a camera can read reliably is the structure layered on top of the raw data.
Inside a QR code
Every dot has a job.
- Finder patterns — the three big squares the camera uses to locate and orient the code.
- Timing patterns — alternating dots that tell the scanner the size of one module.
- Format info — records the error-correction level and mask pattern.
- Data + error correction — your encoded string, plus Reed-Solomon redundancy.
The three big squares are how the camera finds it
Those three big concentric squares in the corners — top-left, top-right, bottom-left — are called finder patterns. They’re the loudest visual feature of a QR code on purpose. A camera can spot the 1:1:3:1:1 ratio of dark and light bands inside those squares from any angle, in any rotation, and use them to figure out:
- Where the QR code is in the image.
- How it’s rotated (the missing fourth corner is what tells the scanner which way is “up”).
- How big each module is, so it knows how to slice up the rest of the grid.
If you ever damage one of these three squares, the code stops being scannable — period. They’re the anchors. The little square near the bottom-right (in larger codes) is an alignment pattern, which helps when the QR is on a curved or angled surface.
The thin rows of alternating dots are timing patterns
Connecting the finder patterns are two skinny lines of alternating black and white modules — one horizontal, one vertical. These are timing patterns, and they tell the scanner exactly how big a single module is in the captured image. Without them, on a photo taken at an awkward angle, the scanner couldn’t reliably grid up the rest of the code.
The data lives in the rest
Once the scanner has found the finder patterns, oriented the code, and measured the module size, it reads the remaining modules in a specific zig-zag pattern from the bottom-right toward the top-left. That stream of bits is the data + error correction.
The first few bits tell the scanner what kind of data it is:
- Numeric (digits only): packs 3 digits into 10 bits — the densest mode.
- Alphanumeric (uppercase letters, digits, a few symbols): 2 chars per 11 bits.
- Byte (UTF-8): 8 bits per byte. This is what’s used for URLs.
- Kanji: 13 bits per character, for Shift-JIS-encoded Japanese.
So https://example.com is encoded in byte mode, character by character, exactly like a normal string.
Error correction is the magic
Here’s the bit that feels like wizardry. Every QR code is encoded with Reed-Solomon error correction — the same math used in CDs, DVDs, and deep-space communication. When the QR is generated, the encoder adds a bunch of redundant “checksum” modules. When the scanner reads the code, it can use those checksum modules to reconstruct missing or corrupted data.
There are four error-correction levels, and they’re a tradeoff between data capacity and damage tolerance:
- L (Low): ~7% of modules can be lost or covered.
- M (Medium): ~15%.
- Q (Quartile): ~25%.
- H (High): ~30%.
This is why you can put a logo in the middle of a QR code: the scanner reconstructs the missing data from the redundancy. It’s also why a coffee-stained, slightly torn QR poster still scans. The Reed-Solomon math doesn’t care which 30% of the modules are missing — only that fewer than 30% are.
Masking: the quiet little detail
If you generated a QR with a long string of zeros (white modules), you’d end up with big white blocks that look like negative space — confusing for cameras. To avoid that, after the data is encoded, the QR generator XORs the entire grid against one of eight predefined mask patterns to break up runs of same-color modules. The chosen mask is recorded in the format-info bits next to the finder patterns, so the scanner knows which mask to undo.
It’s a small detail, but it’s the reason QR codes look “noisy” instead of striped.
Putting it together
When your phone’s camera sees a QR code, in roughly 100ms:
- It locates the three finder patterns and the alignment pattern.
- It calculates the rotation, perspective, and module size.
- It reads each module as a 0 or 1, in the spec’s zig-zag order.
- It removes the mask pattern.
- It applies Reed-Solomon to repair any damage.
- It decodes the resulting bits as a numeric/alphanumeric/byte/kanji string.
- It hands you the result — usually a URL, which your phone then opens.
That’s it. It’s not magic, it’s just a particularly clever 30-year-old standard, executed in a few microseconds by a chip that costs eight cents.
Why this matters in practice
A few useful consequences fall out of how QR codes work, once you know:
- You can’t make a QR code “expire” by changing the dots. The encoded string is fixed forever. Anything that “expires” is a server somewhere, not the code itself. (We’ve written about this trick at length.)
- A QR code can’t carry a virus. It’s just a string. The risk is whatever the string points to — usually a URL.
- High-error-correction QRs are slightly less data-dense but much more robust. That’s why we default to level Q for codes you’re going to print.
- A logo in the middle of your code doesn’t break it as long as you stay under the error-correction budget and don’t cover the finder patterns.
If you want to see one of these working, make a QR right now — the dots you’ll see are doing exactly the work above.
Need a QR code that won't expire?
Make one in your browser, free, no signup. Or sign in with Google to manage dynamic codes with scan stats.