QR Codes Explained: Complete Guide for Developers and Marketers
QR codes are simple on the surface and surprisingly deep underneath. This guide covers how they actually work—modules, error correction, encoding modes—and the practical decisions that determine whether your code scans reliably or fails in the field.
Anatomy of a QR Code
A QR code is a 2D matrix of black and white squares called modules. Not all modules carry data—several structural elements help scanners locate, orient, and decode the code reliably regardless of angle or partial damage.
Structural Elements
| Element | Location | Purpose |
|---|---|---|
| Finder patterns | Three corners | Three 7×7 squares that let cameras detect the code's presence and orientation in any direction |
| Separators | Around finder patterns | White border isolating finder patterns from data modules |
| Timing patterns | Between top finder patterns | Alternating black/white strips that establish the module grid coordinates |
| Alignment patterns | Lower-right area (Version 2+) | Smaller square markers that correct for perspective distortion in larger codes |
| Format information | Adjacent to finder patterns | Encodes the error correction level and mask pattern used |
| Data and ECC modules | Remaining area | The actual encoded content plus error correction codewords |
| Quiet zone | Outer border | Minimum 4 modules of white space all around—scanners need this to detect code edges |
The finder patterns are the most recognizable feature—those three identical squares in the corners. They're specifically designed so the scanner can detect the 1:1:3:1:1 black/white ratio from any scan angle.
QR vs. Traditional Barcodes
| Feature | 1D Barcode | QR Code |
|---|---|---|
| Dimensions | 1D (horizontal lines) | 2D (matrix grid) |
| Data capacity | ~20 characters | Up to 7,089 digits |
| Data types | Numeric primarily | Text, URLs, binary, Kanji |
| Error correction | None | 7–30% recovery |
| Scan direction | Must be aligned | Any angle |
| Damage tolerance | None | Reads even when partially obscured |
Versions and Capacity
QR codes come in 40 versions. Version 1 is 21×21 modules. Each subsequent version adds 4 modules per side, so Version 40 is 177×177. Higher versions hold more data but produce physically larger codes that take longer to scan.
| Version | Size | Max numeric (L) | Max alphanumeric (L) | Max bytes (L) |
|---|---|---|---|---|
| 1 | 21×21 | 41 | 25 | 17 |
| 5 | 37×37 | 154 | 93 | 64 |
| 10 | 57×57 | 652 | 395 | 271 |
| 20 | 97×97 | 2,061 | 1,249 | 858 |
| 40 | 177×177 | 7,089 | 4,296 | 2,953 |
The encoder selects the lowest version that fits your data. If you reduce the content length—say, by using a URL shortener—the encoder can use a smaller, faster-scanning version. For most URL-based QR codes, you'll land in Version 3–7.
Encoding Modes
The encoder picks the most efficient mode based on your content. Using the wrong mode wastes capacity—a code in byte mode can hold significantly less than the same characters in numeric mode.
| Mode | Characters | Bits per char | Best for |
|---|---|---|---|
| Numeric | 0–9 | 3.3 | Phone numbers, product codes, serial numbers |
| Alphanumeric | 0–9, A–Z, space, $%*+-./: | 5.5 | Uppercase URLs, codes, short references |
| Byte | Any UTF-8/ISO-8859-1 | 8 | Lowercase text, URLs with lowercase, most content |
| Kanji | Shift-JIS Japanese characters | 13 | Japanese text |
The practical consequence: if you uppercase your URL, it can encode in alphanumeric mode and fit more data. But most modern encoders handle mixed-mode segments, switching between modes mid-content when it saves space.
// Effect of mode on capacity (same Version 5, Level M):
"1234567890123456789012345" → Numeric mode → fits in ~version 2
"HTTPS://TOOLSDOCK.COM" → Alphanumeric → more efficient than byte
"https://toolsdock.com" → Byte mode → lowercase forces byte modeMasking
After encoding, the encoder applies one of 8 XOR mask patterns to the data area. The purpose: avoid large solid areas, regular patterns, or sparse regions that confuse scanners. The encoder evaluates all 8 masks and picks the one with the best score. This is automatic—you never need to think about it, but it explains why two identical-content QR codes from different generators may look slightly different.
Error Correction
QR codes use Reed-Solomon error correction—the same algorithm used on CDs and DVDs. It lets decoders reconstruct missing or corrupted data from the redundant codewords scattered through the data area.
| Level | Recovery capacity | Data overhead | When to use |
|---|---|---|---|
| L (Low) | ~7% | Minimal | Clean digital displays, maximum data density |
| M (Medium) | ~15% | Moderate | General purpose—most printed materials |
| Q (Quartile) | ~25% | Higher | Industrial environments, outdoor signage |
| H (High) | ~30% | Highest | Logo overlay, harsh conditions, expected damage |
Higher error correction means more of the code's area is dedicated to redundancy instead of data. For the same content, Level H produces a physically larger code than Level L. That's the tradeoff: robustness costs space.
Data Formats
QR codes are just containers for strings. Several URI schemes have become standard for triggering specific phone behaviors when scanned.
URL (most common)
https://toolsdock.com/code-generator/qr-code-generator/?utm_source=printWiFi credentials
WIFI:T:WPA;S:OfficeNetwork;P:MyPassword123;H:false;;
# Parameters:
# T = Security type: WPA, WEP, or nopass
# S = Network SSID (name)
# P = Password
# H = Hidden network: true or falseAndroid 10+ and iOS 11+ handle this natively without any app. Scanning prompts the user to join.
vCard (contact)
BEGIN:VCARD
VERSION:3.0
N:Smith;Jane
FN:Jane Smith
ORG:Acme Corp
TEL:+15551234567
EMAIL:jane@acme.com
URL:https://acme.com
END:VCARDCalendar event
BEGIN:VEVENT
SUMMARY:Product Launch
DTSTART:20260415T140000Z
DTEND:20260415T160000Z
LOCATION:Main Conference Hall
DESCRIPTION:Annual product launch event
END:VEVENTEmail, phone, SMS
mailto:contact@example.com?subject=Inquiry&body=Hello
tel:+15551234567
sms:+15551234567?body=I%20saw%20your%20signGeo location
geo:40.7128,-74.0060TOTP (two-factor auth setup)
otpauth://totp/Example:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=ExampleThis is the standard format used by authenticator apps when you scan a 2FA setup code.
Bitcoin payment
bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa?amount=0.001&label=DonationStatic vs. Dynamic QR Codes
| Static | Dynamic | |
|---|---|---|
| Data storage | Encoded directly in the code | Short URL that redirects to your destination |
| Changeable? | No—fixed at creation | Yes—change destination without reprinting |
| Trackable? | No | Yes—scans, location, device type |
| Code size | Grows with content length | Small and consistent (short URL) |
| Requires service? | No | Yes—a redirect service must stay live |
| Privacy | Complete—no tracking | Scan data collected by redirect service |
Dynamic QR codes solve the biggest practical problem with printed materials: you can't reprint a thousand brochures if the URL changes. Point the short redirect at a new destination and every old printed code works. The tradeoff is dependency on a service staying operational.
Design and Scanning Reliability
Size guidelines
| Viewing distance | Minimum code size | Typical use |
|---|---|---|
| 10 cm (4") | 2 cm (0.8") | Business cards |
| 30 cm (12") | 3 cm (1.2") | Flyers, table tents, menus |
| 1 m (3 ft) | 10 cm (4") | Posters, window clings |
| 5 m (16 ft) | 50 cm (20") | Billboards, banners |
Contrast
Dark modules on a light background. The scanner measures reflected light—low contrast means ambiguous readings. Black on white has a 21:1 contrast ratio. The minimum you can get away with is roughly 4:1.
Works well:
Black on white (best)
Dark navy on white
Dark green on white
Black on light yellowAvoid:
Red foreground (causes failures with some scanners)
Orange or yellow modules on white
Light gray on white
Inverted (white on black) without thorough testingQuiet zone
The quiet zone is the mandatory white border around the entire code. Minimum is 4 modules wide—roughly 10% of the total code size on each side. Printing text or graphics right up against the code's edge without quiet zone is the single most common reason professionally printed codes fail.
Adding a logo
- Set error correction to Level H before generating
- Keep the logo under 30% of total code area (width × height)
- Center it precisely—off-center logos can cover format information strips
- Add white padding around the logo so modules near it remain readable
- Test with at least 5 phones including older Android devices
File format for output
| Format | Best for | Notes |
|---|---|---|
| SVG | All print work | Scales to any size perfectly, edit in Illustrator or Inkscape |
| Print production | Vector, print-ready, can embed fonts | |
| PNG | Fixed-size digital use | Export at 300+ DPI; lossless compression preserves sharp edges |
| JPEG | Never | Compression blurs module edges and causes scan failures |
Generating QR Codes Programmatically
JavaScript (browser)
// qrcode npm package — works in Node and browser via bundler
import QRCode from 'qrcode';
// PNG data URL for use in <img src>
const dataUrl = await QRCode.toDataURL('https://toolsdock.com', {
errorCorrectionLevel: 'M',
width: 300,
margin: 2,
color: { dark: '#000000', light: '#ffffff' }
});
// SVG string
const svg = await QRCode.toString('https://toolsdock.com', {
type: 'svg',
errorCorrectionLevel: 'M'
});
// Write to file (Node.js only)
await QRCode.toFile('./qrcode.png', 'https://toolsdock.com', {
width: 400,
errorCorrectionLevel: 'H' // Use H if adding a logo afterward
});Python
import qrcode
from qrcode.image.svg import SvgPathImage
# Basic PNG
qr = qrcode.QRCode(
version=None, # Auto-select smallest version that fits
error_correction=qrcode.constants.ERROR_CORRECT_M,
box_size=10,
border=4,
)
qr.add_data('https://toolsdock.com')
qr.make(fit=True)
img = qr.make_image(fill_color='black', back_color='white')
img.save('qrcode.png')
# SVG output
qr_svg = qrcode.make('https://toolsdock.com', image_factory=SvgPathImage)
qr_svg.save('qrcode.svg')
# With custom colors (requires Pillow)
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.colormasks import SolidFillColorMask
img = qr.make_image(
image_factory=StyledPilImage,
color_mask=SolidFillColorMask(front_color=(0, 0, 128)) # Dark blue modules
)Node.js batch generation
const QRCode = require('qrcode');
const fs = require('fs');
const codes = [
{ data: 'https://example.com/product/1', filename: 'product-1.png' },
{ data: 'https://example.com/product/2', filename: 'product-2.png' },
{ data: 'WIFI:T:WPA;S:StoreWifi;P:pass123;;', filename: 'wifi.png' },
];
const options = { errorCorrectionLevel: 'M', width: 300, margin: 2 };
for (const code of codes) {
await QRCode.toFile(`./output/${code.filename}`, code.data, options);
console.log(`Generated ${code.filename}`);
}Real-World Use Cases
Restaurant menus
Post-pandemic, QR menus went from novelty to default in many restaurants. The practical advantage beyond hygiene: you can update prices or items without reprinting. Use a dynamic QR code pointing to your menu URL. Put it on table cards and the front window, not buried on a receipt.
WiFi sharing
Hotels, cafes, and offices print WiFi QR codes instead of writing passwords on whiteboards. The guest scans, phone joins automatically. No reading out "capital-P, lowercase-a, number-2..." Use the WIFI: format and set error correction to M or higher since these are often laminated.
Payments
Most payment QR codes work one of two ways: the merchant displays a QR code the customer scans (Stripe, PayPal), or the customer shows their payment app's QR code to a reader. The Bitcoin bitcoin: URI scheme and similar are used for crypto payments. UPI in India uses a standardized upi:// scheme.
Digital business cards (vCard)
Print a QR code on your physical card that encodes your full vCard. When scanned, the phone offers to add the contact directly. Much faster than typing. Keep the vCard data minimal—name, phone, email, URL—or the code becomes large and dense.
2FA setup
Every time you scan a QR code to set up an authenticator app (Google Authenticator, Authy, 1Password), you're scanning an otpauth://totp/ URI. The QR code just encodes that string. If you're building a 2FA system, generate QR codes with the standard TOTP URI and they'll work with all major authenticator apps.
Event tickets
Use a unique URL or encoded token per ticket. The scanner at the gate validates it server-side and marks it used. Don't encode all ticket data locally in the QR—a screenshot of someone else's ticket would work. The code should just be an opaque identifier that your system validates.
Asset tracking
Print QR codes on equipment, packages, or containers. Encode a URL pointing to the asset's record in your system. When the scanner scans it, they see current location, maintenance history, or check-out status. Version 1–3 codes are fine for short IDs, and they're small enough to print on adhesive labels.
Tools
QR Code Generator
Generate QR codes for URLs, WiFi, vCards, email, phone, and plain text. Download as PNG or SVG.
Generate QR CodeQR Code with Logo
Create branded QR codes with a logo in the center. Automatically sets Level H error correction.
Add Logo to QRWiFi QR Generator
Generate a WiFi connection QR code from your network name and password.
WiFi QR CodevCard QR Generator
Turn your contact details into a scannable QR code for digital business cards.
vCard QR CodeQuick Reference: QR Data Formats
| Type | Format |
|---|---|
| URL | https://example.com |
mailto:you@example.com?subject=Hi | |
| Phone | tel:+15551234567 |
| SMS | sms:+15551234567?body=Hello |
| WiFi | WIFI:T:WPA;S:SSID;P:pass;; |
| Geo | geo:40.7128,-74.0060 |
| TOTP | otpauth://totp/Label?secret=BASE32&issuer=App |
| Bitcoin | bitcoin:ADDRESS?amount=0.001 |