Raster QR codes (PNG/JPEG) look fine at the size they were generated for and fall apart the moment someone resizes, screenshots, or prints them larger — the module edges blur, and blurred module edges are exactly what breaks a decoder's ability to read the grid.
SVG sidesteps this completely because a QR code is fundamentally vector data already — it's a grid of black/white squares, not a photograph. Rendering it as <rect> elements instead of a pixel bitmap means it stays crisp at any zoom level, print size, or screen density:
<img src="qr.svg" alt="Scan to open" width="600" />
That's a 600px display of a code that could've been generated at any size — no upscaling artifacts, because there was never a fixed pixel grid to begin with.
A couple of practical notes if you're embedding these in a product:
-
Inline the SVG (rather than referencing it as an
<img src>) if you need to style fill colors with CSS at render time instead of baking colors in server-side. - Strict hex validation on any color params matters more than it looks — if a QR generation endpoint lets you pass custom foreground/background colors and embeds them directly into SVG attributes, that's an injection surface if the values aren't validated as actual hex colors first.
- Raw matrix output is still useful — for canvas rendering, terminal output, or anything that isn't "embed an image," getting the boolean module grid directly beats parsing an SVG back into pixels.
QR API returns image/svg+xml by default from GET /v1/qr, with a /v1/qr/matrix variant returning the raw grid for exactly that second use case. Sibling APIs on the same account: Validate and Currency API.
Top comments (0)