As empty as a QR code
can get and still scan
A normal QR code is about half black. This one gets that down to a tenth, without breaking the spec.
Same URL, same scanners
Not adding blank space. Emptying space that was already wasted.
- Leave room to spare
- Pick a version larger than your URL needs and you get leftover codewords. The spec tells you to fill them with fixed junk bytes, and that junk is a big part of why QR codes look so dense.
- Undo the mask on purpose
- The last encoding step XORs a lattice over the data area. XOR of two equal values is zero, so if you pre-load each padding bit with the mask value for that position, the two cancel and the module comes out white.
- The reader never looks
- Decoders stop at the terminator and ignore everything after it. Whatever sits in the leftover space, the result is identical. That makes it our canvas.
How empty it gets is decided by the error correction level
Error correction bytes are computed by the algorithm, so we cannot touch them and they stay black. Raising the level grows that untouchable area and shrinks the blank space.
| Level | V2 | V5 | V10 | Good for |
|---|---|---|---|---|
| L | 27% | 15% | 12% | Sharing on screens |
| M | 34% | 21% | 21% | Sensible default |
| Q | 38% | 32% | 29% | Cards and stickers |
| H | n/a | 40% | 34% | Print and outdoors |
Measured by encoding the same URL with each setting and counting black modules in the data area. An ordinary QR code sits around 47% at every setting.
Questions people ask
- Does this break the spec?
- Only the contents of the padding differ. The mask number is recorded exactly as the spec requires and Reed-Solomon is computed normally, so decoders treat it as an ordinary QR code. Strict spec mode fills the padding by the book as well.
- Will every scanner read it?
- Every code is decoded by a real decoder in your browser before you download it, and the result is shown to you. That said, phone cameras and messaging apps each ship their own decoder. Test on real devices before using one somewhere that matters.
- Why do some settings scan unreliably?
- A large white area gives the binarizer nothing to calibrate against. In dim light or a shaky photo, specks appear where there were none, and if the error correction bytes cannot absorb them the read fails. Raise the error level or drop one version.
- Is what I type stored anywhere?
- No. Encoding, rendering and verification all happen in your browser, and the text is never sent to a server. There is no link shortener either, so nothing redirects in the middle.
- It says my URL is too long
- Versions up to 10 are supported. At error level L that is 271 characters for a normal URL, or 395 if you use only uppercase letters and digits, because that mode packs two characters into 11 bits. If you can uppercase the path, your code gets a size or two smaller.