ProAll Pro features are unlocked for everyone — free for a limited time.
← Blog/Deep Dive

How QR Codes Work — the technical bit, made simple

March 2026·7 min read

You paste a URL into a box, click a button, and a grid of black-and-white squares appears. A phone hovers over it and — instantly — the original URL is back. What actually happened in between?

QR codes were invented by a Toyota subsidiary in 1994 to track car parts. Today they encode everything from restaurant menus to payment links. The underlying mechanism is surprisingly elegant, and you don't need a computer science degree to follow it.

Step 1: Turn the text into binary

The first thing the QR encoder does is convert your URL into a stream of 1s and 0s. The most common method for URLs is called byte mode: each character is looked up in a table called ASCII and converted to an 8-bit number.

The letter h is number 104 in ASCII. 104 in binary is 01101000. Every character in your URL gets the same treatment, one after another, producing a long chain of bits.

URL → Binary (byte mode)

h

01101000

t

01110100

t

01110100

p

01110000

s

01110011

········

Each character becomes 8 bits. “h” = 104 in ASCII = 01101000 in binary.

The encoder also prepends a short header to the bit stream: a 4-bit code that says “this data is in byte mode”, followed by the character count. This gives the decoder everything it needs to reverse the process.

Why binary? A QR code is ultimately a grid of dark and light squares. Dark = 1, light = 0. Binary is the most natural language for something that only has two possible states per cell.

Step 2: Add redundancy (so it survives damage)

Here's the clever part. Before the bits are placed on the grid, the encoder runs them through a mathematical process called Reed-Solomon error correction.

Reed-Solomon adds extra “parity” data — a calculated checksum of the original bits. If some squares in the printed code get scratched, dirty, or blocked by a logo, the decoder can use this parity data to reconstruct the missing information. Think of it like how a vinyl record can skip past a scratch because the groove contains enough context to fill in the gap.

Intact code

All data present, decodes normally.

Damaged — still works

~25% obscured — error correction fills the gaps.

QR codes come in four error-correction levels:

LevelCan recover up to…Common use
L (Low)7%Clean environments
M (Medium)15%Most general use
Q (Quartile)25%Industrial / outdoor
H (High)30%Logos embedded in QR

Adding a logo on top of a QR code works because of level H — the logo intentionally covers part of the grid, and the error-correction data fills in what's missing. This is why you can put a company logo in the middle of a QR code and it still scans perfectly.

Step 3: Build the grid

Now the encoder has a long binary string — original data plus error-correction data. It's time to place it onto the square grid. But first, some scaffolding goes in.

QR Code Anatomy

Finder patterns

The three square targets in the corners. Every QR code has exactly these. They're how your camera instantly knows where the code is, even at an angle.

Format info

Tiny strips next to the finder patterns. They tell the scanner which error-correction level and mask pattern to use before decoding anything else.

Data + error correction

The rest of the grid. Your URL is encoded here as binary (0s and 1s), mixed with redundant data that lets the code survive damage.

The finder patterns — the three bold squares in the corners — are placed first, and they never change. Every QR code in existence has the same three finder patterns in the same corners. This is what lets your camera lock onto a code so quickly: it's scanning for that specific nested-square shape, not the data.

The timing patterns are alternating dark/light strips that run between the finder patterns. They establish the grid spacing, which matters because codes can be printed at any size.

With the scaffolding in place, the encoder fills the remaining cells with the binary data — reading through the grid in a specific zigzag path, placing one bit per cell.

Step 4: Apply a mask

There's one more step before the code is finalised: masking.

If the data happened to produce a large solid block of dark squares, a scanner might struggle — it could confuse that block for a finder pattern or simply fail to track the grid. To prevent this, the encoder XORs (flips) certain cells based on a mathematical pattern called a mask.

There are eight standard mask patterns. The encoder tries all eight and picks whichever produces the most balanced, evenly distributed result. The chosen mask ID is stored in the format info strip so the decoder knows which one to reverse.

This is why QR codes always look like a noisy mess rather than having obvious rows of data — the masking deliberately scrambles the visual pattern to make it easier to scan.

How does a phone read it back?

Decoding is the same steps in reverse. When you point your camera at a QR code:

  1. Find the code. The camera scans the frame looking for three finder patterns in an L-shaped arrangement. Once found, it knows the rotation and perspective of the code — it can even correct for a severe angle.
  2. Read the format strip. Before touching the data, the scanner reads the format info strip to learn which error-correction level and mask pattern were used.
  3. Sample the grid. Using the timing strips to calibrate cell size and position, the scanner reads each cell as dark (1) or light (0), reversing the mask as it goes.
  4. Error-correct. Reed-Solomon is run on the recovered bits. Any corrupted or missing cells are reconstructed from the parity data.
  5. Decode the bytes. The mode header tells the decoder how to interpret the bits. In byte mode, every 8 bits maps back to an ASCII character. The URL emerges.

The whole process takes a few milliseconds. Most of the time you spend “scanning” is just waiting for the camera to autofocus.

Why do longer URLs make bigger QR codes?

A QR code's size is called its version. Version 1 is a 21×21 grid and can store up to 17 characters. Version 40 is a 177×177 grid and can store up to 3,000 characters. Each version step adds 4 cells to each side.

More characters → more bits → more grid cells needed. Longer URLs and higher error-correction levels both push the code into a higher version and make it visually denser. This is why a short URL like qr.io/a produces a simple, sparse code, while a long Google Maps URL produces a dense, busy one.

Practical tip: If your QR code looks very dense and complex, consider using a URL shortener first. A shorter URL produces a simpler, more scan-friendly code.

The short version

1

Your URL is converted to binary using ASCII encoding.

2

Reed-Solomon error correction adds redundant data so the code survives damage.

3

Fixed finder patterns and timing strips are placed on the grid so cameras can locate and orient the code.

4

The binary data fills the remaining cells in a specific path.

5

A masking pass flips certain cells to ensure an even visual distribution, preventing false pattern detection.

6

A phone reverses all of this in milliseconds: find, orient, unmask, error-correct, decode.

See it in action

Paste any URL and watch a QR code appear in real time — free, no account needed.

Generate a free QR code →