QRonimo
QRonimo Learn How QR Codes Work

How QR Codes Work

A QR code looks like a random scatter of black and white squares, but every single module is deliberate. Once you understand the anatomy, the fact that your phone decodes one in under a second stops feeling like magic and starts feeling like elegant engineering.

The Anatomy of a QR Code

Every QR code is built on a square grid of small cells called modules. A module is either dark or light — that binary contrast is all a scanner needs to reconstruct the encoded data. But the grid is not just raw data from edge to edge. Several fixed structural regions must appear in every valid QR code, regardless of content.

Finder Patterns

Look at any QR code and you will immediately notice the three bold squares in the top-left, top-right, and bottom-left corners. These are finder patterns, and they are the first thing a scanner looks for. Each one is a 7×7 square of dark modules surrounding a 5×5 light ring surrounding a 3×3 dark core — a precise 1:1:3:1:1 dark-to-light ratio that is extremely unlikely to appear by accident anywhere else in an image.

The scanner searches the entire camera frame for this ratio in any direction — horizontal, vertical, diagonal — and once it finds three of them, it knows exactly where the QR code is, how large it is, and which way it is oriented. The bottom-right corner has no finder pattern deliberately; its absence is what tells the scanner which corner is which.

A thin one-module-wide strip of light modules, called the separator, isolates each finder pattern from the surrounding data area so the scanner never confuses structural pixels with data pixels.

Timing Patterns

Running between the finder patterns along row 6 and column 6 are two lines of alternating dark and light modules: the timing patterns. They look like a dotted line. Their purpose is practical: they tell the scanner the exact size of each module in pixels, even if the image is slightly blurry or distorted. By counting the alternating cells, the decoder can calibrate itself to the grid spacing before it attempts to read any data.

Alignment Patterns

Larger QR codes add one or more alignment patterns — small 5×5 bullseye-like squares scattered through the interior of the code. These appear starting at version 2 (25×25 modules), and larger versions can have dozens of them. Their job is to help the scanner correct for perspective distortion and lens warp. If you photograph a QR code at an angle, the alignment patterns act like survey markers that allow the decoder to mathematically unwarp the grid back to a flat square before reading the data.

Format Information Strips

Adjacent to each finder pattern you will find two strips of 15 modules each that encode the format information: which error correction level is in use (L, M, Q, or H) and which data mask pattern was applied. This information is so critical that it is stored twice — once near each of two finder patterns — and it is protected by its own small error correction code. Without knowing the format information, the decoder cannot correctly interpret a single bit of the data area.

Data Modules

Everything that is not a finder pattern, separator, timing pattern, alignment pattern, or format strip is a data module. These encode your actual content — the URL, text, phone number, or whatever else the QR code carries — along with the redundancy data used for error correction. Data is written in two-column-wide zigzag columns that snake from bottom-right to top-left, stepping left two columns at a time and skipping over any reserved regions.

┌─────────────────────────────────────────┐
│ [FINDER]  separator  timing  [FINDER]   │
│           ─────────────────             │
│  timing                                 │
│  │         data modules                 │
│  │         data modules   [align]       │
│  │         data modules                 │
│ [FINDER]   data modules                 │
│            format info strips           │
└─────────────────────────────────────────┘
        
Schematic layout of a QR code's structural regions. Real codes follow this same arrangement at every version.

Version Numbers: From 21×21 to 177×177

The word version in the QR context does not mean a revision — it means a size tier. Version 1 is the smallest possible QR code: 21×21 modules. Each step up adds 4 modules to each side, so version 2 is 25×25, version 3 is 29×29, and so on up to version 40 at 177×177 modules.

Larger grids hold more data, but they also require more alignment patterns and more error correction overhead. In practice, the vast majority of QR codes you encounter in the real world — restaurant menus, product packaging, business cards — are version 3 or lower, because a short URL fits comfortably in a tiny grid and small codes are faster to scan.

Version information itself (the number 7 through 40) is encoded in two 6×3 blocks of modules near the finder patterns. Versions 1 through 6 are small enough that the scanner can infer the size just from the finder pattern positions, so they do not need this extra block.

How Data Is Encoded: Four Modes

Before a QR encoder writes a single module, it must decide how to represent your data. The standard defines four encoding modes, each suited to a different character set, and each achieving a different density:

  • Numeric mode — digits 0–9 only. Three digits are packed into 10 bits, so this is the most efficient mode. A version 1 QR code can hold up to 41 numeric characters.
  • Alphanumeric mode — digits, uppercase A–Z, and nine special characters (space, $, %, *, +, -, ., /, :). Two characters are packed into 11 bits. Version 1 holds up to 25 alphanumeric characters. URLs encoded in this mode must be uppercased, which is why many generators produce codes that decode to uppercase links — browsers handle the redirect.
  • Byte mode — arbitrary 8-bit bytes, typically interpreted as UTF-8. One character per 8 bits, making it less dense but universally capable. Version 1 holds up to 17 bytes. Most URL QR codes use byte mode to preserve lowercase and special characters exactly.
  • Kanji mode — double-byte characters from the Shift JIS encoding used for Japanese text. Two bytes are compressed into 13 bits, giving better density than byte mode for Japanese content.

The encoder begins the bitstream with a 4-bit mode indicator telling the decoder which mode to use, followed by a character count field, then the encoded data itself. Multiple segments with different modes can be chained together in a single QR code.

Capacity at a Glance

The table below shows selected versions under byte mode with the medium (M) error correction level, which is the most common configuration. Actual capacity changes depending on the error correction level you choose.

Version Grid size Numeric Alphanumeric Bytes (URL / text)
1 21 × 21 41 25 17
2 25 × 25 77 47 32
3 29 × 29 127 77 53
5 37 × 37 187 114 78
10 57 × 57 652 395 271
20 97 × 97 2,061 1,249 858
30 137 × 137 4,296 2,603 1,789
40 177 × 177 7,089 4,296 2,953
Capacities shown for error correction level M. Level L allows slightly more data; levels Q and H allow less but recover from more damage. See the error correction guide for detail.

A typical short URL like https://qronimo.app/r/abc123 is around 28 characters, which fits in a version 2 or 3 code. Long URLs with tracking parameters can easily push into version 7 or 8 territory, producing a visibly denser code that is slower to scan in poor light. This is why link shorteners exist: a shorter URL means a smaller, faster, more reliable QR code.

Reed-Solomon Error Correction

QR codes can survive physical damage — a scratch, a smudge, a partially obscured logo — because every code contains more data than strictly necessary. The extra data is computed using an algorithm called Reed-Solomon error correction, the same technique used in CDs, DVDs, and deep-space communications.

The idea is straightforward even if the mathematics is not: the encoder treats the data as a polynomial, evaluates it at extra points, and appends those extra values (called error correction codewords) to the bitstream. If some codewords are lost or corrupted, the decoder can reconstruct the originals from the surviving ones, much like solving for missing values in an equation.

The QR standard offers four error correction levels:

  • L (Low) — recovers from up to ~7% damage. Maximizes data capacity.
  • M (Medium) — recovers from up to ~15% damage. The most common default.
  • Q (Quartile) — recovers from up to ~25% damage. Good for industrial printing.
  • H (High) — recovers from up to ~30% damage. Required when you embed a logo, since the logo intentionally obscures part of the code.

Higher error correction means more redundancy codewords, which leaves fewer modules available for actual data, which either reduces capacity or forces a larger version number. Choosing the right level is a genuine trade-off. If you are adding a logo to your QR code, level H is not optional — it is the safety net that lets the scanner recover the modules hidden under the image.

Data Masking: Why QR Codes Look the Way They Do

After encoding the data and computing error correction, the encoder applies a data mask. The QR standard defines eight mask patterns — mathematical rules applied to every data module that flip dark to light or light to dark based on the module's row and column position.

The reason is practical: a large unbroken block of dark modules or a perfectly regular repeating pattern can confuse a scanner into misidentifying a data region as a finder pattern, or cause the timing calibration to fail. Masking breaks up those patterns deliberately. The encoder tries all eight masks, scores each one against a set of penalty rules that penalize things like long runs of same-color modules or patterns that resemble finder patterns, and picks the mask with the lowest penalty score. The chosen mask number is stored in the format information strips so the decoder can reverse it.

This process is invisible to the user but it explains why two QR codes encoding slightly different strings can look very different — a small change in content can result in a different mask being selected, producing a visually distinct pattern of modules.

How a Scanner Reads a QR Code in Milliseconds

Modern smartphone cameras perform this entire pipeline dozens of times per second as you point the camera:

  1. Image capture. The camera sensor captures a frame. Dedicated barcode scanning chips or optimized camera APIs (like AVFoundation on iOS or ML Kit on Android) analyze the frame in a background thread without blocking the viewfinder.
  2. Locate finder patterns. The decoder scans horizontal lines of pixels looking for the 1:1:3:1:1 dark-light-dark-light-dark ratio. When it finds three matching clusters that form an L-shaped triangle, it has located the code.
  3. Perspective correction. Using the four corner positions (three finder patterns plus the inferred fourth corner) and any alignment patterns found inside the code, the decoder applies a perspective transform to produce a clean, flat, square grid image.
  4. Sample the grid. The decoder samples the center of each module cell. A module above a threshold luminance is light; below it is dark. The timing patterns calibrate the exact center positions for each row and column.
  5. Read format information. The 15-bit format strip is read first to determine the error correction level and mask pattern. The mask is reversed to restore the original encoded bits.
  6. Decode the data stream. The data codewords are read in the zigzag order defined by the standard. The mode indicator and character count are parsed, then the characters are decoded according to the mode.
  7. Apply error correction. The Reed-Solomon decoder checks the error correction codewords against the data codewords. Any discrepancies that fall within the recovery capacity are repaired automatically.
  8. Return the result. The decoded string — a URL, plain text, a phone number — is handed to the operating system, which typically offers to open it.

The whole process takes between 10 and 100 milliseconds on a current smartphone, limited mostly by how quickly the camera can capture and deliver a focused frame rather than by decoding speed.

Why Square? Why Those Corner Patterns?

The square shape is not arbitrary. A square grid is the simplest two-dimensional structure that maps cleanly to rows and columns of bits. It also means the finder patterns in three corners create an unambiguous orientation marker: any other polygon would require more complex logic to determine rotation.

The concentric square design of the finder pattern — dark border, light ring, dark core — was chosen specifically because it produces the 1:1:3:1:1 ratio in every direction through the center, regardless of the viewing angle. It is one of the few shapes where this property holds. The inventors at Denso Wave tested many candidate patterns and selected this one precisely because it was least likely to appear accidentally on packaging, signage, or other printed material that a scanner might encounter.

The absence of a fourth finder pattern in the bottom-right corner is what makes orientation unambiguous. With only three, the scanner can determine not just where the code is but exactly which way it is rotated — critical for correctly interpreting which end of the bitstream is the beginning.

Try It Yourself

Now that you know how QR codes are structured, watching one get generated is much more interesting. QRonimo generates codes entirely in your browser — no data is sent to any server — so you can experiment freely with different content lengths, error correction levels, and visual styles.

Try encoding a short URL versus a long one and compare the version numbers. Switch between error correction levels L and H and watch the code grow. Everything described on this page is happening live in your browser.

Open the QR Code Generator →