A QR code is a 2D grid of black and white modules that encodes text — most often a URL — together with fixed patterns that let a camera find and orient the code and redundant data that lets it recover from damage. Generating one is straightforward: you supply a string, choose an error-correction level, and the encoder lays out the grid. Understanding what the grid contains, though, is what lets you make codes that scan reliably instead of ones that fail half the time. This article explains the anatomy of a QR code, the encoding modes and versions, the role of error correction and the quiet zone, and how to produce a code that works.
What is inside a QR code?
A QR code is built from function patterns that a scanner relies on and data modules that carry your content. Before any information is read, the camera has to locate and square up the code, and specific fixed patterns make that possible:
| Element | Purpose |
|---|---|
| Finder patterns | Three large square “eyes” in the corners; let a scanner detect the code and its rotation |
| Alignment patterns | Smaller squares that correct for distortion when the code is on a curved or angled surface |
| Timing patterns | Alternating lines between finder patterns that establish the module grid coordinates |
| Quiet zone | Blank margin around the whole code so the scanner can tell where it begins and ends |
| Format and version info | Encodes the error-correction level and the mask pattern used |
| Data and error-correction modules | The encoded content plus the redundancy that repairs damage |
The three corner “eyes” are the most recognisable feature, and they are functional, not decorative: their fixed ratio of dark and light is what a camera scans for to know it is looking at a QR code at all. Everything else is arranged around them.
How does a QR code encode data?
It packs your string into one of several modes, choosing the most compact one that fits your characters. The mode determines how many bits each character costs, so the same visual size can hold very different amounts of text depending on what you encode:
| Mode | Character set | Efficiency |
|---|---|---|
| Numeric | Digits 0-9 only | Most compact — about 3.3 bits per digit |
| Alphanumeric | Digits, uppercase A-Z, and a few symbols | About 5.5 bits per character |
| Byte | Any byte, typically UTF-8 text and URLs | 8 bits per character |
| Kanji | Shift-JIS double-byte characters | 13 bits per character |
Most real-world codes use byte mode, because URLs contain lowercase letters and symbols that fall outside the alphanumeric set. This is also why a URL in all uppercase can sometimes produce a smaller, denser-looking code than the same URL in mixed case: uppercase can use the more efficient alphanumeric mode. The encoder handles this choice for you, but it explains why shortening a URL — or dropping the https:// where safe — reduces the number of modules.
QR codes also carry more than plain links, and the payload is just formatted text that a scanner recognises by convention. A Wi-Fi credential uses the form WIFI:S:MyNetwork;T:WPA;P:mypassword;;, a contact card is a vCard block, and a plain phone number can be tel:+15551234567. The generator does not treat these specially — they are strings encoded like any other — but the scanning app parses the prefix and offers the right action, such as joining a network or saving a contact. Knowing this is useful because it explains why a QR code can contain sensitive data in plain text: the Wi-Fi password above is right there in the pattern for anyone who decodes it.
What do versions and error correction control?
The version sets the grid size and the error-correction level sets how much damage the code can survive — and the two trade off against each other. QR versions run from 1 to 40. Version 1 is a 21×21 grid; each step up adds 4 modules per side, so version 40 is a 177×177 grid. A larger version holds more data but produces a code with smaller, denser modules that a camera finds harder to resolve.
Error correction uses Reed-Solomon coding to add redundant bytes, and comes in four levels:
| Level | Recovery capacity | Best for |
|---|---|---|
| L (Low) | About 7% | Clean digital displays, maximum data |
| M (Medium) | About 15% | General-purpose default |
| Q (Quartile) | About 25% | Printed codes that may get scuffed |
| H (High) | About 30% | Codes with a logo, or harsh environments |
Higher error correction is what lets people place a logo in the centre of a QR code: the missing modules under the logo fall within the recoverable percentage, so the scanner reconstructs them. The cost is that stronger correction consumes capacity, so for the same content you may need a larger version. A practical default is level M; step up to Q or H only when the code will be printed, damaged, or branded.
Why does the quiet zone matter so much?
The quiet zone is the blank margin around the code, and without enough of it, scanners cannot reliably find the code’s edges. The convention is a margin of at least four modules on every side. It is the single most common cause of a code that “sometimes works”: the pattern itself is valid, but it sits flush against text, a border, or the edge of an image, and the scanner cannot isolate it from the surrounding content.
Two related mistakes finish the list of avoidable failures. Low contrast — a light-grey code on white, or dark-on-dark — breaks the black/white distinction the scanner depends on; keep it dark modules on a light background with strong contrast, and avoid inverting the colours. And overloading the payload forces a high version with tiny modules; if you must encode a long string, increase the printed size or shorten the text so each module stays large enough to resolve at scanning distance.
How do you generate a QR code that scans reliably?
Keep the payload short, pick an error-correction level to match the environment, and preserve a generous quiet zone. In practice that means encoding the shortest URL that works, choosing M for screens and Q or H for print or logos, and leaving at least four modules of margin. Test the result by scanning it with an ordinary phone camera at the distance and size it will really be used — a code that scans on your monitor at 10cm may fail on a poster at two metres.
A QR code is pure computation: given your text and settings, the grid is fully determined, so there is no need for the encoding to touch a server. Our QR code generator builds the image entirely in your browser, which means the content you encode — a private link, a Wi-Fi password, a vCard with someone’s phone number — never leaves your machine. That client-side property is worth caring about precisely because QR payloads are often sensitive: a Wi-Fi QR code literally contains your network password in plain text inside the pattern.
Static versus dynamic: a caution
Finally, know the difference between static and dynamic codes, because it decides whether your code can ever break. A static code encodes the final destination directly; the data is in the pattern, it needs no external service, and it works as long as the destination exists. A dynamic code instead encodes a short redirect URL owned by a third-party service, which forwards to your real target — convenient because you can edit the destination later, but it also means the code stops working if that service shuts down or starts charging. For anything you print permanently, a static code pointing at a URL you control is the durable choice.