The short answer
Masking is the last step before a QR code is finalized. After the encoder turns your text into a grid of dark and light data modules, it XORs those modules with a checkerboard “mask pattern” that swaps some modules light-to-dark and dark-to-light. The standard defines exactly eight mask patterns, the encoder tries all eight and keeps the one that produces the most scanner-friendly grid, and the chosen pattern is recorded in the format information so the scanner can undo it before decoding. Masking is the reason two QR codes encoding the exact same text can look completely different — and the reason a QR never has one giant block of solid color that would confuse a camera. It is the structural concept that complements the finder patterns, alignment pattern, timing pattern, and format information covered in our how does a QR code work guide.
What a mask pattern actually is
A mask is a repeating rule that, for every module position in the grid, says whether to flip the color of that module or leave it alone. Each of the eight standard masks is a simple mathematical formula over the module’s row and column coordinates — for example, “flip when row + column is even”, or “flip when the column is a multiple of 3”, or “flip when row × column mod 2 + row × column mod 3 is 0”. The result is a checkerboard-like overlay that, when XORed with the raw data grid, breaks up large same-color blocks into a balanced mix of dark and light.
Crucially, masking is reversible. The scanner reads the chosen mask number from the format information, regenerates the exact same mask, and XORs the grid a second time — because XOR applied twice returns the original, the scanner recovers the unmasked data exactly. So masking changes how the code looks without changing what it stores. The masking step sits after error correction is added and before the format information is written, which is why it is the last structural operation a QR encoder performs.
Why QR codes need masking at all
Without masking, a QR code could easily contain a large patch of solid dark or solid light modules — a long run of identical bits. To a scanner those patches look like noise or like a finder pattern in the wrong place, and the sampler can lose its place reading the zig-zag data path. The finder patterns themselves are already large solid blocks; the last thing the data area needs is more of them. Masking exists to break up those runs so the data area has roughly balanced dark and light modules everywhere, the way a naturally noisy image does, which is far easier for a camera to read reliably.
Masking also protects against the edge cases the raw data grid creates: a long string of zeros or a long string of ones in the encoded bitstream would otherwise print as a solid block, and the scanner’s contrast threshold across that block would be unstable. By flipping roughly half the modules, the mask guarantees no large region is uniformly one color. This is the same reliability goal as error correction (our qr error correction guide covers the resilience side); masking is the readability side, applied to the layout rather than the payload.
The eight standard masks
The ISO/IEC 18004 standard defines exactly eight mask patterns, numbered 0 to 7. Each is one formula over the module coordinates. The encoder applies each mask in turn, scores the result against four penalty rules (large same-color blocks, long same-color runs, patterns that mimic the finder 1:1:3:1:1 ratio, and overall dark/light balance), and the mask with the lowest total penalty wins. The table below lists all eight with their flip rules and the situation each one handles well.
| Mask | Flip rule (where dark/light swap) | What it breaks up |
|---|---|---|
| 0 | (row + column) mod 2 == 0 | Even checkerboard — handles regular alternating data grids. |
| 1 | row mod 2 == 0 | Horizontal stripes — breaks up wide same-color rows. |
| 2 | column mod 3 == 0 | Vertical stripes — breaks up column-aligned runs. |
| 3 | (row + column) mod 3 == 0 | Diagonal balance — counters diagonal banding. |
| 4 | (floor(row / 2) + floor(column / 3)) mod 2 == 0 | Blocky 2×3 regions — breaks up chunky tiled patterns. |
| 5 | (row × column) mod 2 + (row × column) mod 3 == 0 | Combined density — counters woven intersecting runs. |
| 6 | ((row × column) mod 2 + (row × column) mod 3) mod 2 == 0 | Weave pattern — handles mixed interlocking blocks. |
| 7 | ((row + column) mod 2 + (row × column) mod 3) mod 2 == 0 | Irregular — best all-rounder against uneven payloads. |
How the encoder picks the mask
The encoder does not guess — it tries all eight masks on the same data grid, scores each masked result against the four penalty rules, and keeps the lowest-scoring one. The penalty rules reward a roughly 50/50 dark/light balance, punish large solid blocks, punish long same-color runs, and specifically punish any pattern that looks like a finder 1:1:3:1:1 ratio in the wrong place (because that would trick the locate step our qr finder pattern guide covers). The scoring is deterministic, so two encoders following the spec produce the same mask choice for the same payload — which is why the same text always generates the same-looking code on a spec-compliant generator.
This selection step is also why a tiny change in the payload can change which mask wins and shift the whole grid: a one-character difference changes the raw bits, changes which mask scores lowest, and can flip many modules at once. That is not a bug; it is the mask penalty function responding to a different raw grid. Our qr code version guide covers how the payload also changes the grid size; masking changes the grid coloring on top of that.
The format information records the chosen mask
Because the scanner must undo the mask before it can read the data, the chosen mask number has to travel inside the code itself. It lives in the format information block, the same small block next to each finder pattern that records the error-correction level. The format block encodes two things together: the error-correction level (L, M, Q, or H) and the mask number (0–7), protected by their own error correction so they survive damage. This is why the version and the format are distinct pieces of metadata, as our qr code version guide notes — the version fixes the grid size, the format fixes the error-correction level and the mask, and together they let the scanner set up its sampling grid correctly before reading a single data module.
On scan, the order reverses: locate the finders, read the format block to learn the error-correction level and the mask, regenerate the mask from its number, XOR it out of the data grid, then run Reed-Solomon decoding on the unmasked data. Masking and error correction therefore work as a pair — masking keeps the grid readable so the scanner can recover the bits, and error correction repairs any bits that were still lost. Our qr error correction guide covers the repair half; masking is the readability half.
Why two codes for the same text look different
This is the single most common masking-related question: “I encoded the same URL twice and the codes look different — is one wrong?” The answer is no, and masking is usually the explanation. If the two codes came from two different encoders that chose different masks (or applied the penalty rules slightly differently), the same payload can produce visibly different grids that both decode to the same text, because the mask only changes the appearance, not the stored data. A spec-compliant encoder picks deterministically, but not every tool follows the penalty rules exactly, and some let you override the mask manually.
There are two other reasons two same-text codes can differ besides masking: different error-correction levels change the grid (more redundancy means different data modules), and a different version (grid size) means a different layout entirely. So when you see two codes for the same text that do not match pixel-for-pixel, the checks are: confirm the error-correction level matches, confirm the version matches, and then any remaining difference is the mask — and a mask difference is cosmetic, not a data difference. Run either code through the free /decode helper to confirm both round-trip to the same payload.
How QRForge handles masking
QRForge’s encoder follows the standard end to end: it builds the raw data grid with error correction, tries all eight mask patterns, scores each against the four penalty rules, and keeps the lowest-scoring mask, then writes the chosen mask number into the format information alongside the error-correction level. You never choose the mask by hand — the encoder picks the most scanner-friendly one for your specific payload, which is why the same content always renders the same way on QRForge and why a one-character change can shift the pattern. The same masked grid then drives all three export formats (SVG, PNG, and EPS), so a vector print and a raster screen image always carry the identical mask.
Masking is one of the structural choices that keeps a styled code scannable alongside the design levers in our qr code styling and qr code colors guides — it operates below the styling layer, on the raw data grid, so your colors, module shapes, and gradients sit on top of an already-balanced pattern. The habit that pairs with masking is the one throughout our qr best practices guide: keep the payload short so the version stays low, choose the error-correction level deliberately (H for logos and wear), and run the final exported image through the free /decode helper plus a real-phone scan-test before any print run. Pair masking with the finder, alignment, and timing pattern guides and you have the full structural picture of how a QR stays readable.
Frequently asked questions
What is QR code masking?
Masking is the final step of QR encoding: the data grid is XORed with one of eight standard checkerboard patterns to break up large same-color blocks, making the code easier for a camera to read. The chosen mask is recorded in the format information so the scanner can undo it.
Why do two QR codes for the same text look different?
Usually because the encoders chose different mask patterns, or used different error-correction levels or versions. Masking only changes the appearance, not the stored data — two differently-masked codes both decode to the same text. Confirm both round-trip with a decode helper.
How many mask patterns does a QR code have?
Eight, numbered 0 to 7, defined by the ISO/IEC 18004 standard. The encoder tries all eight, scores each against four penalty rules, and keeps the one with the best dark/light balance and fewest confusing patterns.
Do I choose the QR mask pattern myself?
No. A spec-compliant encoder picks the mask automatically based on penalty scoring, so the same content always renders the same way. You control the inputs that affect readability indirectly — keep the payload short and choose the error-correction level deliberately.