What is a QR code and how does it work?
A QR code (Quick Response code) is a 2D barcode that encodes data — text, URLs, contact info, payment info — in a black-and-white grid pattern that smartphone cameras can read instantly. Invented in 1994 by Masahiro Hara at Denso Wave (originally for tracking automotive parts), QR codes went mainstream during the 2020 pandemic when restaurants needed contactless menus. Today they're everywhere: payment apps, transit tickets, restaurant menus, business cards, marketing posters, WiFi sharing, two-factor authentication.
The "Quick Response" name comes from how fast scanners can read them — 10× faster than 1D barcodes. A QR code can store up to 4,296 alphanumeric characters or 7,089 numeric digits, and reads correctly from any angle (4-way rotation). Three large square "finder patterns" in three corners let scanners find and orient the code in milliseconds.
Modern QR codes use Reed-Solomon error correction: even if part of the code is damaged, dirty, or covered by a logo, the data can still be reconstructed. The ISO/IEC 18004:2024 standard formalizes the encoding, and major mobile OS camera apps (iOS Camera, Android Google Lens) can scan them natively without a separate app.
QR code structure — what's inside
| Element | Purpose |
|---|---|
| Finder patterns (3 large squares) | Top-left, top-right, bottom-left corners. Tell the scanner this is a QR code and which way is "up." |
| Alignment patterns (small squares) | Help correct for camera distortion when the code isn't perfectly flat. |
| Timing patterns | Alternating black/white lines connecting finder patterns — used to determine module size. |
| Format info | Encodes which error-correction level the code uses (L, M, Q, or H). |
| Version info | Versions 1–40, indicating size: V1 = 21×21 modules, V40 = 177×177. |
| Data & error correction | The actual payload + redundant bytes for Reed-Solomon recovery. |
| Quiet zone | 4-module-wide white border. Without it, scanners often fail. |
Error correction levels — picking the right one
QR codes use Reed-Solomon error correction, which adds redundant data so the code stays scannable even when partially damaged or obscured. Higher correction = bigger QR (more modules) but more robust:
| Level | Recoverable damage | Best for | Trade-off |
|---|---|---|---|
| L (Low) | ~7% | Clean digital displays, screens, online ads | Smallest code, holds most data |
| M (Medium) | ~15% | Default — most printed materials, posters, packaging | Balanced size + robustness |
| Q (Quartile) | ~25% | Industrial labels, dirty environments | Larger, holds less data |
| H (High) | ~30% | QR codes with embedded logos, outdoor billboards, products that may scratch | Largest code; required if you add a center logo |
Common QR code use cases — what people actually do
URLs (most common — ~80% of all QR codes)
Just encode the full URL with https://. Keep URLs short — long URLs make the QR code larger and harder to scan. For URLs over 100 chars, shorten with bit.ly, your own domain redirect, or a UTM-stripped version.
WiFi network sharing
The format is a special string starting with WIFI::
WIFI:T:WPA;S:NetworkName;P:Password;H:false;;
// T = encryption (WPA, WEP, or "nopass" for open networks)
// S = SSID (network name)
// P = password
// H = true if the network is hidden, false otherwise
// Final ;; (yes, double semicolon) terminates the format
Both iOS and Android cameras recognize this format and offer one-tap "Connect to WiFi". Print it on a small card for guest WiFi.
vCard (digital business card)
BEGIN:VCARD
VERSION:3.0
FN:Anees Ur Rehman
TITLE:Full-stack Developer
ORG:FreeDevTool
EMAIL:anees@example.com
TEL:+1-555-1234567
URL:https://freedevtool.org
END:VCARD
Scanning saves the contact directly to the user's address book. Far better than a printed business card that gets lost.
Email links
Format: mailto:address@example.com?subject=Hello&body=Message. The user's mail app opens with everything pre-filled.
Phone numbers
Format: tel:+15551234567. Use international format (E.164) for cross-country compatibility.
SMS
Format: SMSTO:+15551234567:Pre-written message text. Tapping opens the SMS app with recipient + body filled in.
Geolocation
Format: geo:37.7749,-122.4194. Opens the user's default maps app at those coordinates.
Calendar events
iCalendar format encoded in a QR code. Useful for event invitations on flyers.
Cryptocurrency payments
Bitcoin: bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa?amount=0.001. Ethereum: ethereum:0xAbC.... Wallet apps recognize these formats automatically.
QR code generation in 8 programming languages
JavaScript (qrcode library)
// npm i qrcode
import QRCode from 'qrcode';
// Generate as PNG data URL
const dataUrl = await QRCode.toDataURL('https://example.com', {
errorCorrectionLevel: 'H',
margin: 4,
width: 512,
});
// Generate as SVG string
const svg = await QRCode.toString('https://example.com', { type: 'svg' });
// Save to canvas (in browser)
QRCode.toCanvas(document.getElementById('canvas'), 'https://example.com');
Python (qrcode library)
import qrcode
qr = qrcode.QRCode(
version=None, # auto-detect size
error_correction=qrcode.constants.ERROR_CORRECT_H,
box_size=10,
border=4,
)
qr.add_data('https://example.com')
qr.make(fit=True)
img = qr.make_image(fill_color='black', back_color='white')
img.save('output.png')
# Or output SVG
import qrcode.image.svg
img = qr.make_image(image_factory=qrcode.image.svg.SvgImage)
img.save('output.svg')
PHP (endroid/qr-code)
// composer require endroid/qr-code
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\ErrorCorrectionLevel;
$result = Builder::create()
->data('https://example.com')
->errorCorrectionLevel(ErrorCorrectionLevel::High)
->size(512)
->margin(40)
->build();
$result->saveToFile(__DIR__ . '/output.png');
Java (ZXing)
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
BitMatrix matrix = new MultiFormatWriter().encode(
"https://example.com",
BarcodeFormat.QR_CODE,
512, 512
);
MatrixToImageWriter.writeToPath(matrix, "PNG", Paths.get("output.png"));
Go (skip2/go-qrcode)
import qrcode "github.com/skip2/go-qrcode"
err := qrcode.WriteFile("https://example.com", qrcode.High, 512, "output.png")
// Or to bytes
png, _ := qrcode.Encode("https://example.com", qrcode.Medium, 256)
Rust (qrcode crate)
use qrcode::{QrCode, EcLevel};
use image::Luma;
let code = QrCode::with_error_correction_level("https://example.com", EcLevel::H)?;
let image = code.render::<Luma<u8>>().build();
image.save("output.png")?;
// Or as SVG
let svg = code.render::<qrcode::render::svg::Color>().build();
Bash (qrencode)
# Install: brew install qrencode (macOS) / apt install qrencode (Debian)
# Print to terminal (ANSI)
qrencode -t ANSI 'https://example.com'
# Save to PNG
qrencode -o output.png -s 10 -m 4 -l H 'https://example.com'
# WiFi credentials
qrencode -o wifi.png 'WIFI:T:WPA;S:MyNetwork;P:secret123;;'
# Pipe stdin (great for scripts)
echo 'https://example.com' | qrencode -o stdin.png
API approach (no library)
# goqr.me (deprecated as of 2024 — use a self-hosted alternative)
# Or qrserver.com:
curl 'https://api.qrserver.com/v1/create-qr-code/?data=https://example.com&size=512x512' \
-o output.png
# Better: self-host with the qrcode lib in your favorite language
WiFi QR code generator — share network access without typing
The fastest WiFi QR use case: print a small card and tape it inside a meeting room or guest reception. The format is WIFI:T:WPA;S:NetworkName;P:Password;; — Android's camera, iOS Camera (since iOS 11), and most modern Linux scanners auto-prompt to join. Special characters in the password (;, ,, :, ", \) must be backslash-escaped per the WiFi-Alliance spec; the WiFi tab above does this automatically. For home networks with rotating guest passwords, regenerate the QR weekly — it's a one-button update vs. typing a 16-character WPA passphrase on a phone keyboard.
vCard QR code for business cards and signatures
A vCard QR encodes name, title, org, phone, email, and URL into a single scan-and-save action. Pair the vCard with a unique-per-person UUID in a hidden NOTE field if you want server-side scan attribution. Generate any unique IDs you embed using the linked UUID generator so collisions are mathematically impossible.
QR code best practices for 2026 production use
- Test on real phones, multiple OSes. Print preview and dev-tool scanners are forgiving; real phone cameras under fluorescent lighting fail with low contrast or compression artifacts. Always test before mass-printing.
- Use SVG for the web, PNG for print. SVG scales infinitely, has tiny file size, and renders crisply at any DPI. PNG only when the rendering platform forces raster (some print drivers, certain CMS systems).
- Use level H if you add a logo. Below level H, even a small logo breaks scannability. With H, you can cover ~25–30% of the center.
- Maintain a 4-module quiet zone. The white margin around the code is required by the spec. Cropping it tight breaks scanning.
- Keep contrast high. Dark on light. Aim for 4.5:1 minimum (WCAG AA). Brand-color QR codes in pastels often fail.
- Don't shorten URLs aggressively. A bit.ly URL works, but it's an extra hop, can break, and obscures destination. For your own pages, use clean URLs and let the QR code be slightly bigger.
- Print at minimum 1 inch (~25mm) for arm's-length scanning. Larger for billboards (visible from across a room: 6+ inches; from across a parking lot: 12+ inches).
- Avoid dynamic QR services for permanent print. "Dynamic QR codes" route through a third-party service. If they shut down or change pricing, your printed materials break. Use static QR codes for anything you commit to print.
- Don't QR-encode tiny strings. A 5-character string makes a tiny, dense QR code that's hard to scan. For short data (a phone number, a coupon code), just print the text.
- Track scans with UTM parameters.
?utm_source=poster&utm_campaign=spring2026in the destination URL tells you which physical location drove which clicks. - Avoid scanning prompts. "Scan this QR code with your camera!" is no longer needed in 2026 — every modern phone scans QR codes natively. Trust users to know.