Every QR code is a grid of squares.
Yours doesn't have to be.
BetterQR generates codes with real shapes, gradients, embedded logos, decorative frames, and animated GIFs — plus Micro QR and one-line WiFi, vCard, and geo codes. Style it however you like; it still has to scan, and it does.
21×21 to 177×177 modules · ECC L / M / Q / H · PNG · JPG · SVG · PDF · EPS · GIF












Every tile above is a real PNG made with BetterQR — scan one and see for yourself.
One library, every finish.
No plugins to install and no post-processing pipeline — styling, logos, frames, and animation all live in the same call chain as the QR generation itself.
Module shapes
square, circle, rounded, diamond, star, gapped, and two bar styles — swap with one keyword argument.
Gradients

Horizontal, vertical, diagonal, or radial — fade between any two colors across the whole code.
Logo embedding

Drop a PNG or JPG in the center. BetterQR raises error correction automatically so it still scans.
Frames & labels

simple, rounded, double, shadow, or fancy — with a text label above or below, any color.
Animated GIFs

shimmer, fade, scan, pulse, build, matrix, wave, blink, typewriter, rotate — the last frame is always fully scannable.
Data helpers
WiFi, vCard, MeCard, geolocation, SMS, email, phone, and crypto — pass the helper object straight in.
Output formats
Raster for the web, vector for print — .save() picks the renderer from the file extension.
Colour control
3- or 6-digit hex, transparent PNG backgrounds, and a separate colour just for the finder squares.
Command line or Python — same feature set.
Reach for the CLI for a one-off code, or the fluent API when you're generating them in bulk.
# styled with a gradient betterqr "Hello" my_qr.png --gradient "#FF6B6B" "#4ECDC4" # logo + frame + label in one line betterqr "https://mysite.com" qr.png --logo logo.png -e H --frame fancy --label "Scan Me!" # WiFi, straight from the CLI betterqr --wifi MySSID MyPassword wifi.png # animated GIF betterqr "Animated QR" animated.gif --effect matrix --fps 12
from betterqr import QR, WiFi # chain style, logo, frame, and label (QR("https://mysite.com", ecc="H") .style(shape="circle", fill="#6C3082") .logo("logo.png", ratio=0.25, shape="rounded") .frame("fancy") .label("Scan Me!") .save("framed.png")) # data helpers pass in directly QR(WiFi("MyNet", "MyPass", "WPA")).save("wifi.png") # animation QR("Hello", ecc="H", version=4).animate("matrix", fps=15).save("anim.gif")