QR Codes for Developers: Generation, Error Correction, and Best Practices
QR codes are one of the most successful 2D barcode formats ever created. Originally designed in 1994 by Denso Wave for tracking automotive parts in Japan, they have become ubiquitous — product packaging, restaurant menus, payment systems, conference badges, and transit tickets all use them. As a developer, understanding how QR codes work internally lets you make better decisions about error correction levels, data capacity, output format, and design customization.
This guide covers the internals, data capacity limits, encoding modes, error correction tradeoffs, and practical code for generating QR codes in JavaScript.
QR Code Anatomy
A QR code is not just a random grid of black and white squares. Every region has a defined purpose. Understanding the structure helps you understand why certain design rules exist.
Finder patterns are the three large squares in the top-left, top-right, and bottom-left corners. They are 7x7 modules with a specific black-white-black border pattern. Scanners use them to detect the QR code’s position and orientation — the finder patterns are intentionally asymmetric (there are only three, not four) so the scanner knows which corner is which.
Alignment patterns appear in larger QR codes (version 2 and above) as small 5x5 squares scattered across the data area. They help scanners correct for perspective distortion when the QR code is photographed at an angle.
Timing patterns are alternating black and white stripes running horizontally and vertically between the finder patterns. They define the grid coordinate system and tell the scanner the module size.
Format information is stored in two locations adjacent to the finder patterns. It encodes the error correction level and the mask pattern used. It is duplicated in case one region is damaged.
The data area fills the remaining modules. It stores the actual encoded data along with error correction codewords, both interleaved according to a specific algorithm.
The quiet zone is the blank border around the entire code — at least four modules wide on all sides. Without it, scanners cannot reliably detect where the QR code ends and the background begins. This is the rule most often violated by designers who place QR codes too close to other elements.
Encoding Modes and Data Capacity
QR codes support four encoding modes, each optimized for a different type of data. The mode determines how efficiently the data is packed into the code.
Numeric mode encodes digits 0-9 only, using approximately 3.3 bits per character. This is the most efficient mode. A version 1 QR code (the smallest, 21x21 modules) can hold up to 41 numeric characters at error correction level L.
Alphanumeric mode encodes uppercase letters, digits, and nine special characters (space, $, %, *, +, -, ., /, :). It uses approximately 5.5 bits per character. A version 1 code holds up to 25 alphanumeric characters at level L.
Byte mode encodes arbitrary binary data, typically UTF-8 text. It uses 8 bits per character. A version 1 code holds only 17 bytes at level L. This is the mode used for URLs, since URLs contain lowercase letters and special characters not supported by alphanumeric mode.
Kanji mode encodes double-byte Japanese characters (Shift JIS encoding) in 13 bits per character, which is more efficient than encoding them in byte mode. A version 1 code holds 10 Kanji characters at level L.
QR codes scale from version 1 (21x21 modules) to version 40 (177x177 modules), increasing by 4 modules per version in each dimension. A version 40 code at error correction level L can hold 7,089 numeric characters, 4,296 alphanumeric characters, or 2,953 bytes. In practice, most QR codes encode short URLs (under 200 characters) and use version 3 through 10, which scan faster and more reliably than large codes.
A practical capacity rule: keep URLs under 200 characters. Longer URLs require higher version codes that are harder to scan, especially in print. Use a URL shortener if your target URL exceeds this limit.
Error Correction Levels
QR codes use Reed-Solomon error correction, which allows them to be read even when partially damaged, obscured, or printed with imperfect fidelity. There are four error correction levels:
Level L (Low): Can recover from up to 7% of codeword errors. The smallest data overhead — more space is available for payload data, so you can fit more content or use a smaller code. Use this for clean, controlled environments where the code is printed clearly and scanned digitally.
Level M (Medium): Can recover from up to 15% of codeword errors. A good default for most use cases. Balances data capacity with damage tolerance.
Level Q (Quartile): Can recover from up to 25% of codeword errors. Useful when codes are printed on products that may get scratched or dirty — retail packaging, outdoor signage.
Level H (High): Can recover from up to 30% of codeword errors. This is required when you embed a logo or image in the center of the QR code, since the logo deliberately damages a portion of the data area. The high error correction ensures the code remains scannable despite the obstruction.
Choosing a higher error correction level increases the size of the code for the same amount of data. A URL that fits in a version 3 code at level L may require a version 5 code at level H. For logo embedding, always use level H and keep the logo to at most 30% of the code area.
Common Use Cases
Understanding what data to encode affects which encoding mode gets selected and how large the resulting code will be.
URLs are the most common use case. Encode the full URL as a byte-mode string. If your URL contains uppercase letters only and digits, the encoder may use alphanumeric mode for efficiency, but most URL encoders default to byte mode for compatibility.
WiFi credentials use a structured string format: WIFI:T:WPA;S:NetworkName;P:password;;. Scanners that support WiFi QR codes parse this format and offer to join the network. Note that this format is a convention, not an official QR standard — most modern phone cameras support it.
vCard contact information uses the vCard 3.0 format encoded as bytes. This allows a single scan to add a complete contact to the phone’s address book.
Payment systems vary by provider. QR-based payments like WeChat Pay, Alipay, and various banking apps use their own proprietary formats, sometimes encoding a URL that redirects to a payment flow, sometimes encoding structured payment data directly.
App store links are just URLs pointing to the App Store or Google Play. Use a universal link that redirects to the correct store based on the user’s device to avoid maintaining two separate QR codes.
Generating QR Codes in JavaScript
The qrcode npm package is a well-maintained library for Node.js and browsers. It supports all four encoding modes, all error correction levels, and multiple output formats.
Install it:
npm install qrcode
Generate a data URL for use in an <img> tag:
import QRCode from 'qrcode';
const dataUrl = await QRCode.toDataURL('https://example.com', {
errorCorrectionLevel: 'M',
margin: 4, // Quiet zone in modules
width: 256, // Output width in pixels
color: {
dark: '#000000', // Module color
light: '#ffffff' // Background color
}
});
document.getElementById('qr').src = dataUrl;
Generate an SVG string:
const svg = await QRCode.toString('https://example.com', {
type: 'svg',
errorCorrectionLevel: 'M',
margin: 4
});
document.getElementById('container').innerHTML = svg;
Generate a PNG file in Node.js:
await QRCode.toFile('qrcode.png', 'https://example.com', {
errorCorrectionLevel: 'H',
margin: 4,
width: 512
});
For browser use without a build step, the library is available via CDN:
<script src="https://cdn.jsdelivr.net/npm/qrcode/build/qrcode.min.js"></script>
<script>
QRCode.toCanvas(document.getElementById('canvas'), 'https://example.com');
</script>
SVG vs PNG: When to Use Which
Both formats work for QR codes, but they have different tradeoffs.
SVG is resolution-independent. A QR code SVG looks sharp at any size — whether displayed as a 100px thumbnail or printed at 10 inches. SVG files are smaller than PNG for most QR codes (a typical URL QR code in SVG is under 5KB). SVG is the right choice for web display, digital signage, and anywhere the display size is variable. SVG can also be styled with CSS or embedded directly in HTML without a separate HTTP request.
PNG is a raster format. It looks correct only at the size it was generated or at integer multiples. For print use, generate at high resolution: at least 300 DPI at the intended print size. A 2-inch printed QR code at 300 DPI requires a 600x600 pixel PNG. PNG is the correct choice when delivering to print shops, embedding in PDFs, or working with design tools that do not support SVG well.
Never use JPEG for QR codes. JPEG’s lossy compression creates artifacts around the sharp black-and-white edges of modules, which reduces scannability.
Design Best Practices
Most QR code scanning failures in production come from design and implementation decisions, not from the QR code generation itself.
Minimum size: A QR code should be at least 2 cm x 2 cm (roughly 0.8 inches) at its smallest dimension for reliable scanning with a typical smartphone camera. Smaller codes require the user to hold the phone very close, which makes scanning awkward.
Contrast: Black modules on white background is the maximum contrast and the most reliable. Dark modules on a light background work; light modules on a dark background (inverted QR codes) work less reliably with some scanners. Avoid low-contrast color combinations — a dark blue code on a dark background may look attractive but will fail in poor lighting.
Quiet zone: Always maintain the four-module quiet zone. In print design, this means keeping the QR code away from other design elements, borders, and the edge of the page.
Testing before deployment: Always test the generated QR code with multiple devices and scanner apps before deploying. Test under the actual conditions it will be used — if it will be printed on matte paper under fluorescent light, test under those conditions. Do not only test on a screen with a perfect scan environment.
Avoid over-customization: Rounded modules, gradient colors, and embedded logos all reduce scannability. If you use any of these, test exhaustively and use error correction level H. Keep logo coverage under 30% of the code area.
FAQ
What is the maximum URL length I should encode?
Stay under 200 characters for reliable scanning. A 200-character URL at error correction level M requires approximately a version 9 code. Longer URLs work but produce larger, denser codes that are harder to scan in imperfect conditions.
Why does my QR code look different from another tool’s output for the same data?
QR codes for the same data can look visually different due to different mask patterns. The QR standard defines 8 mask patterns and requires encoders to evaluate all 8, selecting the one that best balances dark and light modules. Different tools may select different masks, or may not implement mask selection correctly.
Can I put color in a QR code?
Yes, but the contrast between module color and background color must remain high. Dark modules on a light background. The closer the colors are in luminance, the less reliably it scans.
How do I add a logo to a QR code?
Generate the code at error correction level H, then overlay the logo in the center. The logo should cover no more than 30% of the total code area. Test thoroughly — the error correction allows the obscured data codewords to be reconstructed, but only up to the 30% recovery limit.
Conclusion
QR codes are a mature, well-specified format that is easy to generate correctly once you understand the core tradeoffs: encoding mode affects data capacity, error correction level balances capacity against damage tolerance, output format depends on the use case, and design decisions directly affect scan reliability.
For most web applications, a URL encoded at error correction level M, output as SVG, with a four-module quiet zone, will work correctly in every common scanning environment. Start there and adjust only when your specific requirements demand it.
Ready to generate a QR code? Use the QR Code Generator to create and download QR codes for any URL or text, with configurable error correction levels and sizes.