PXLA

How QR Codes Work: Encoding, Finder Patterns, and Masking Explained

The technical pipeline behind every QR code — encoding modes, finder and timing patterns, error correction, and masking — explained step by step.

Updated July 11, 2026

Generating a QR code isn't one step — it's a small pipeline, and every stage exists to solve a specific real-world problem: fitting your data into the smallest reliable grid, surviving damage or glare, and being findable by a camera at any angle. This article walks through that pipeline in the order it actually happens, using the exact terms you'll see if you ever look at the ISO/IEC 18004 specification.

1Choose encoding mode
2Pick version & EC level
3Add error correction
4Place modules
5Apply masking

Step 1: choosing an encoding mode

A QR encoder first decides how to represent your text as bits, because different character sets pack more or less efficiently. The four standard modes are numeric (digits only, the most compact), alphanumeric (digits, uppercase letters, and a handful of symbols), byte (any UTF-8 text, including lowercase letters and full URLs), and kanji (for Japanese text). A URL like https://example.com/path?query=1 needs lowercase letters and characters like : and /, so it's encoded in byte mode — which is what PXLA QR always uses, since it generates URL codes exclusively.

Step 2: picking a version and error-correction level

The grid size is called the "version," from Version 1 (21×21 modules) to Version 40 (177×177 modules). The encoder looks at how many bytes your data needs, combines that with your chosen error-correction level (see Error Correction Explained), and picks the smallest version that fits everything with room to spare. This is also why very long URLs produce visibly denser, more detailed-looking codes — more data and more redundancy simply need more modules to hold them, which is one reason we recommend keeping the URLs you encode reasonably short.

Step 3: adding error correction

Before your data ever gets placed into the grid, the encoder runs it through Reed–Solomon error correction — a well-established coding scheme that adds extra, mathematically derived codewords alongside your actual data. Those extra codewords let a scanner reconstruct the original message even if part of the printed code is scratched, faded, has a logo stamped over it, or simply photographed under glare. PXLA QR uses error-correction level Q by default (about 25% of the code can be damaged and still recover), which trades a small amount of extra code density for real-world print durability.

Step 4: placing fixed patterns and data

Not every module in the grid carries your data. A meaningful chunk of the grid is reserved for structures that exist purely to help a camera find and read the code correctly:

  • Finder patterns — three identical concentric squares in three of the four corners. Their black-white-black ratio (1:1:3:1:1) is deliberately unlikely to occur naturally in a photograph, which is how a scanner locates the code at all, at any rotation.
  • Timing patterns — alternating dashed lines connecting the finder patterns, used to count rows and columns precisely so a slightly warped or perspective-skewed photo still maps correctly onto the grid.
  • Alignment patterns — smaller square markers (in larger versions only) that help correct for the mild geometric distortion of paper that isn't perfectly flat.
  • Format and version information — a small strip of modules near the finder patterns that tells the scanner which mask pattern and error-correction level were used, so it knows how to decode everything else.

Everything that isn't one of those fixed structures is available for your actual data plus its error-correction codewords, which get interleaved together and threaded through the remaining grid in a specific zig-zag path defined by the standard.

Step 5: masking

The last step is subtle but important. Raw encoded data can accidentally produce patterns that are hard to scan — large solid blocks, or shapes that resemble a finder pattern in the wrong place, confusing the scanner about where the code actually starts. To avoid this, the encoder XORs the data region against eight standardized candidate patterns, scores each result using a penalty formula defined in the spec, and keeps whichever produces the most scanner-friendly result. This is invisible to you as a user, but it's a big part of why a well-formed QR code reads reliably even at a glance.

How a phone reads it back

Scanning largely reverses this process: the camera finds the three finder patterns, uses their positions to compute a perspective transform (correcting for tilt or rotation), reads the format information to learn which mask and error-correction level were used, undoes the mask, walks the same zig-zag path to extract the raw bits, and finally runs Reed–Solomon decoding to correct any damaged modules before reconstructing your original URL. All of this typically happens in well under a second on modern phone hardware.

None of this happens on a server

PXLA QR runs this entire encoding pipeline inside your browser using the open-source qrcode JavaScript library — see Is Generation Client-Side? for exactly how, and why that matters for your privacy.

Why do some QR codes look denser than others?

Density reflects how much data is encoded relative to the grid size. A short URL fits comfortably in a low version with lots of whitespace-looking modules; a long URL with tracking parameters needs a higher version, packing in more, smaller-looking modules.

Can two different URLs ever produce the same QR code?

No. The encoding process is deterministic — the same input, encoding mode, version, and error-correction level always produce the same grid, and different input always produces a different grid.

What is the maximum version, and does PXLA QR let me choose it?

Version 40 is the largest defined by the standard. PXLA QR selects the version automatically based on your URL's length, since manually picking a version that's too small for your data isn't something the format allows anyway.