Logos
How to drop a brand logo into the center of a QR without breaking the scan. Sizing, clear zones, neon-alpha stripping.
Logos
A centered brand mark turns a generic QR into a recognizable asset. QR Code Agency supports any PNG, JPG, GIF, BMP, or TIFF up to 1024 x 1024 px and 2 MB.
Custom logos require Starter plan or higher.
Two ways to send a logo
A. Multipart upload (logo_file)
Send the image bytes directly. Best when the logo lives on your filesystem.
cURL
curl -X POST https://api.qrstudio.agency/api/v1/generate/ \
-H "X-Api-Key: smk_..." \
-F "data=https://yourbrand.com" \
-F "size_inches=4" \
-F "logo_file=@/path/to/logo.png" \
--output qr.pngPython
with open("logo.png", "rb") as f:
r = requests.post(
"https://api.qrstudio.agency/api/v1/generate/",
headers={"X-Api-Key": "smk_..."},
data={"data": "https://yourbrand.com", "size_inches": 4},
files={"logo_file": f},
)B. URL reference (logo_url)
Tell us where to fetch the logo. Useful when the logo lives on a CDN.
curl -X POST https://api.qrstudio.agency/api/v1/generate/ \
-H "X-Api-Key: smk_..." \
-H "Content-Type: application/json" \
-d '{
"data": "https://yourbrand.com",
"size_inches": 4,
"logo_url": "https://cdn.yourbrand.com/logo-mark.png"
}' \
--output qr.pngwarning: SSRF protection on
logo_urlThe API resolves the hostname and refuses any URL pointing to:
- Loopback (
127.0.0.1,localhost) - Private networks (
10.x,172.16-31.x,192.168.x) - Link-local (
169.254.x, AWS metadata, etc.) - Multicast and reserved ranges
Returns 400 Bad Request with a clear reason. There is no way to
bypass this. Even DNS rebinding is mitigated.
Logo limits
| Limit | Value |
|---|---|
| Max file size | 2 MB |
| Max dimensions | 1024 x 1024 px (auto-downscaled if larger) |
| Accepted formats | PNG (preferred), JPG, GIF, BMP, TIFF |
| Recommended | Square PNG with transparent background |
logo_size_ratio
Fraction of the QR's diameter that the logo occupies. Default 0.24
(24%) is the safest scannable maximum.
| Value | Logo size on a 4 in QR | Risk |
|---|---|---|
0.10 | ~10 mm | None: always scannable |
0.18 | ~18 mm | Low |
0.24 (default) | ~24 mm | None: within ERROR_CORRECT_H tolerance |
0.30 | ~30 mm | Marginal: test on multiple scanners |
> 0.30 | n/a | Rejected by validator |
note: Why 0.30 is the hard cap The QR spec's H error correction recovers up to ~30% obstruction. Above that, you are gambling that the obstructed modules happen to be the redundant ones. We refuse the request rather than ship a QR that scans on iPhone but fails on industrial readers.
logo_clear_zone
Default true. A small rounded transparent (or background-colored)
zone is carved out of the QR matrix behind your logo so module shapes
do not peek between the logo's negative space.
{ "logo_clear_zone": true } // default, clean carve-out
{ "logo_clear_zone": false } // modules continue under the logotip: When to disable the clear zone Disable only if your logo is fully opaque (no transparent gaps) and fills its bounding box. Otherwise QR modules will be visible through the logo's transparent areas, which looks messy.
logo_neon_alpha
Default false. When true, we apply a luminance-based alpha to your
logo:
new_alpha = original_alpha * luminance ^ 0.6Bright pixels stay opaque; dark pixels fade to transparent. This strips dark backings and shadow halos that otherwise create black blobs around bright neon strokes on a dark substrate.
{ "logo_neon_alpha": true }Use this when your source logo has:
- A solid dark backing rectangle behind glowing strokes
- Drop shadows around bright shapes
- "Neon glow" SVG exports baked-in
Do not use when:
- Your logo is already flat and clean
- You actually want the dark backing to show
Choosing colors that play with logos
flowchart LR
A{Logo color?} --> B[Bright / saturated]
A --> C[Dark / monochrome]
B --> D{Substrate?}
D --> E[Dark t-shirt or photo]
D --> F[Light card stock]
E --> E1["color: white<br/>logo_neon_alpha: true"]
F --> F1["color: black<br/>logo_neon_alpha: false"]
C --> G[color: same as logo<br/>or black/white]A worked example
A neon-bracket logo on a dark gradient substrate, output as transparent PNG:
{
"data": "https://yourbrand.com",
"size_inches": 8,
"color": "white",
"background": "transparent",
"pattern": "rounded",
"logo_url": "https://cdn.yourbrand.com/scanner-bracket-neon.png",
"logo_clear_zone": true,
"logo_neon_alpha": true,
"logo_size_ratio": 0.24
}Result: white modules on transparent (drops cleanly on the dark substrate), neon scanner-bracket logo with no dark blob, scannable from across the room.
Same logo, different QRs (caching)
Logo bytes are part of the render cache key. Two requests with the same parameters and the same logo bytes share the cache slot, regardless of which API key sent them. This means:
- Re-using the same brand logo across thousands of dynamic-QR renders is essentially free after the first miss.
- Switching the logo by one byte invalidates the cache.
See Caching for the full key formula.
What is next
- Caching: same logo + same params = cached PNG
- Print quality: for stickers and posters
- Security model: SSRF and webhook signing