DEV Community

Jonas Hämmerle
Jonas Hämmerle

Posted on

The QR code capacity cliff: why a shortened URL scans more reliably than a long one

QR codes don't degrade gracefully as you stuff more data into them — they hit a capacity ceiling per version/error-correction combination, and the module grid gets denser and denser as you approach it. Past a certain point you're not looking at a QR code you can scan from arm's length anymore, you're looking at one that needs to nearly touch the camera lens to resolve.

The numbers, roughly: at the lowest error correction level (L), a QR code tops out around 2,900 alphanumeric characters or ~4,300 numeric-only characters. That sounds like a lot until you remember two things:

  1. Every character costs more space than you'd think, because the encoding also has to carry the error-correction payload alongside your data — that's not overhead you can opt out of, it's the whole point of the format being scannable at all.
  2. Real-world scanning distance matters more than theoretical capacity. A QR code sized for a business card that's encoding near the character ceiling will produce a module grid so fine-grained that a phone camera needs to be uncomfortably close to resolve individual modules.

The fix is almost always: don't encode raw data, encode a short pointer to it. A URL-shortened link, a UUID that looks up a record server-side, a short numeric ID — anything that keeps the encoded payload well under a hundred characters keeps the module grid coarse enough to scan reliably from a normal distance, at a normal print size.

# fine — short, scans easily even printed small
curl "https://qr-api.p.rapidapi.com/v1/qr?data=https://short.link/x7f2" ...

# avoid — encoding a full JSON payload directly makes the grid dense
# and print-size-sensitive for no real benefit over a lookup pointer
Enter fullscreen mode Exit fullscreen mode

If you're building this into a product, cap the accepted input length and fail with a clear error before hitting the encoder's own hard limit — silently truncating someone's data is worse than telling them up front. QR API caps data at 2000 characters for exactly this reason: comfortably under the spec's own ~2900-character ceiling at the lowest ECC level, with a clear 4xx instead of an encoder crash past it. Same account also runs Validate and Currency API.

Top comments (0)