QRQR Code Agency
Concepts

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.

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.png

Python

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.png

warning: SSRF protection on logo_url The 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

LimitValue
Max file size2 MB
Max dimensions1024 x 1024 px (auto-downscaled if larger)
Accepted formatsPNG (preferred), JPG, GIF, BMP, TIFF
RecommendedSquare 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.

ValueLogo size on a 4 in QRRisk
0.10~10 mmNone: always scannable
0.18~18 mmLow
0.24 (default)~24 mmNone: within ERROR_CORRECT_H tolerance
0.30~30 mmMarginal: test on multiple scanners
> 0.30n/aRejected 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 logo

tip: 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.6

Bright 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

On this page