How to Generate & Embed QR Codes
You need to add a QR code to your web application. Maybe it’s for a payment flow, a shareable link, or event tickets. The question isn’t whether to use a QR code—it’s how to generate one reliably in the browser without introducing scanning issues or security problems.
This article covers client-side QR code generation in JavaScript, explains when to use SVG versus Canvas output, and addresses the practical constraints that affect scan reliability.
Key Takeaways
- Generate QR codes in JavaScript using established libraries—don’t build encoding logic from scratch
- Choose SVG for scalable web embedding, Canvas for programmatic image manipulation
- Respect quiet zones, maintain contrast, and test with actual scanning devices
- Provide visible fallbacks for accessibility and security
Understanding QR Code Generation vs. Scanning
Before writing any code, distinguish between two separate problems: generation and scanning.
Generation happens entirely within your control. You encode data into a QR code image using JavaScript libraries. This works reliably across all modern browsers.
Scanning is different. Native browser APIs for reading QR codes (like the Barcode Detection API) remain experimental and lack universal support. If your application needs scanning, plan for fallbacks—typically a camera-based JavaScript library or manual input fields.
This article focuses on generation. Don’t conflate the two when planning your implementation.
How to Generate QR Codes in JavaScript
Several JavaScript libraries handle QR code generation for frontend work. Common options include qrcode, which supports both client- and server-side generation, qrcode-generator, a lightweight pure JavaScript encoder, and the older but still widely used QRCode.js for simple Canvas or DOM output. None of these is “the standard”—each has trade-offs in bundle size, output formats, and customization options.
The general pattern looks like this:
- Import your chosen library
- Pass the data you want to encode (URL, text, vCard data)
- Specify output format and dimensions
- Render to a DOM element or extract as a data URL
Most libraries accept configuration for error correction levels (L, M, Q, H). Higher levels allow more of the code to be damaged while remaining scannable—useful if you plan to overlay logos or print on textured surfaces.
QR Codes: SVG vs Canvas
When you embed QR codes on the web, you’ll typically choose between three output formats: SVG, Canvas, or PNG/data URLs.
SVG Output
SVG is usually the best choice for web embedding. The vector format scales infinitely without pixelation, making it ideal for responsive layouts and print applications. File sizes stay small regardless of display dimensions. CSS styling works naturally.
Use SVG when:
- The QR code appears at varying sizes
- Print quality matters
- You need CSS-based styling or animation
Canvas Output
Canvas renders to a bitmap at a specific resolution. This works well when you need pixel-level control or plan to composite the QR code with other graphics programmatically.
Use Canvas when:
- You’re generating images for download
- You need to manipulate pixels directly
- You’re integrating with other Canvas-based graphics
PNG/Data URLs
Data URLs let you embed the QR code as a base64-encoded image string. This eliminates additional HTTP requests but increases HTML payload size. Useful for email templates or contexts where external resources aren’t reliable.
Discover how at OpenReplay.com.
Practical Constraints That Affect Scan Reliability
A QR code that looks correct might still fail to scan. Watch for these issues:
Quiet zones: QR codes require empty space around their borders—typically four modules wide. Cropping this margin breaks scanning.
Contrast: The specification assumes dark modules on a light background. Inverted colors or low-contrast combinations reduce reliability. Aim for at least a 4:1 contrast ratio.
Sizing: Minimum scannable size depends on viewing distance and camera quality. For screen display, smaller sizes may work on modern devices, but results depend on viewing distance and camera quality. For print, calculate based on expected scanning distance.
Logo overlays and heavy styling: Adding logos to the center exploits error correction—the scanner treats the logo as damage and reconstructs the data. This only works with higher error correction levels (Q or H), and aggressive styling can push past recoverable limits. Test thoroughly.
Security and UX Considerations
QR codes that encode URLs create phishing opportunities. Users can’t inspect the destination before scanning. If your application generates QR codes from user input, validate and sanitize that input. Consider displaying the encoded URL as visible text alongside the code.
For accessibility, always provide the encoded information in an alternative format. A visible link next to the QR code serves users who can’t or won’t scan.
Server-Side Generation
While this article focuses on client-side approaches, server-side generation has legitimate uses: reducing client bundle size, caching generated codes, or generating codes in environments without JavaScript. Libraries exist for Node.js, Python, Go, and most other backend languages. The output format considerations remain the same.
Conclusion
The technical implementation of QR code generation is straightforward. Use established JavaScript libraries rather than building encoding logic from scratch. Choose SVG for scalable web embedding and Canvas for programmatic image manipulation. The reliability of your QR codes comes from respecting the constraints: maintain quiet zones, ensure proper contrast, and test with actual scanning devices. Always provide visible fallbacks for both accessibility and security purposes.
FAQs
Error correction levels determine how much damage a QR code can sustain while remaining scannable. L recovers about 7% damage, M recovers 15%, Q recovers 25%, and H recovers 30%. Use higher levels (Q or H) when adding logo overlays or printing on textured surfaces, as the scanner treats these modifications as damage and reconstructs the missing data.
Common causes include cropped quiet zones (the empty border around the code), insufficient contrast between dark and light modules, or sizing that's too small for the scanning distance. Ensure at least four modules of empty space around the border, maintain a 4:1 contrast ratio minimum, and test at the actual viewing distance with real devices.
Client-side generation works well for most web applications and reduces server load. Server-side generation makes sense when you need to reduce client bundle size, cache generated codes for reuse, or generate codes in environments without JavaScript. Both approaches produce identical output—choose based on your architecture needs.
Yes, but only with higher error correction levels (Q or H). The scanner treats the logo as damage and uses error correction to reconstruct the data. Keep logos small, centered, and test thoroughly with multiple scanning apps. Aggressive styling or oversized logos can exceed recoverable limits and break scanning entirely.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.