When building web applications that require QR or barcode scanning, developers historically had to rely on native plugins or paid wrappers. Today, html5-qrcode is the most popular open-source library for client-side scanning on the web.
In this post, we discuss the core features of html5-qrcode and why we chose it to power ScanApp.org.
What makes html5-qrcode stand out?
Developed as an open-source project, html5-qrcode provides a lightweight wrapper around browser camera APIs and decoding libraries:
- No Server Dependency: All image processing and mathematical matrix calculations run in the user’s browser via WebWorkers and JavaScript.
- Broad Code Support: Decodes standard QR codes alongside common 1D retail barcodes (UPC, EAN, Code 39, Code 128, etc.).
- Cross-Browser Compatibility: Handles camera controls across iOS (Safari), Android (Chrome/Firefox), and desktop operating systems smoothly.
- Adaptive Scanning: Dynamically scales scanning areas and adjusts frames-per-second (FPS) to optimize battery life on mobile devices.
Integrating It Into Your Project
To add standard web camera scanning to your own website:
// Install library via npm or include via CDN script
const html5QrCode = new Html5Qrcode("reader");
html5QrCode.start(
{ facingMode: "environment" }, // Use back camera
{
fps: 10, // 10 frames per second
qrbox: { width: 250, height: 250 }
},
(decodedText, decodedResult) => {
// Success callback
console.log(`Scan result: ${decodedText}`);
},
(errorMessage) => {
// Silent parsing errors or camera warnings
}
).catch((err) => {
// Permission or hardware errors
});
Why ScanApp Picked html5-qrcode
When the ScanApp team evaluated scanning libraries in early development, we benchmarked five options:
- html5-qrcode (maintained by @mebjas)
- ZXing-js (port of the Java ZXing library)
- Quagga2 (community fork of QuaggaJS, focused on 1D barcodes)
- jsQR (lightweight QR-only decoder)
- Dynamsoft Barcode Reader JS (commercial)
html5-qrcode won on three axes that matter:
- Format breadth. Handles QR plus the full 1D barcode set (UPC, EAN, Code 128, Code 39) and 2D formats like Aztec and Data Matrix in a single bundle.
- Camera handling on iOS Safari. This is the single biggest source of failure in browser scanning.
html5-qrcodehandles iOS quirks (orientation, permission re-prompts, picture-in-picture stalls) better than the alternatives. - Active maintenance. Issues get triaged, PRs get reviewed, and breaking changes are clearly documented.
jsQR is faster for QR-only use cases but doesn’t decode any 1D barcodes. ZXing-js matches the format set but ships a larger bundle and is less actively maintained. Quagga2 is excellent for retail barcode work but lacks QR support. Dynamsoft is technically excellent but requires a paid license — incompatible with our free, open-source positioning.
Bundle Size and Performance
html5-qrcode is approximately 230 KB minified + gzipped (varies slightly by version). On a modern phone, decoding runs at 10–30 FPS depending on camera resolution and viewport size. ScanApp pins FPS at 10 to balance speed against battery life.
For comparison:
jsQR: ~50 KB (QR only)ZXing-js(full): ~400 KBQuagga2: ~120 KB (1D barcodes only)Dynamsoft: ~600 KB + WASM
The 230 KB cost gets you everything in one library, which beats stitching together three libraries to cover the format matrix.
Common Integration Patterns
Drag-and-drop image scanning
const fileInput = document.getElementById('file-input');
const html5QrCode = new Html5Qrcode("reader");
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
try {
const result = await html5QrCode.scanFile(file, true);
console.log("Decoded:", result);
} catch (err) {
console.error("Decode failed:", err);
}
});
Switching cameras
const cameras = await Html5Qrcode.getCameras();
// Pick the back camera if available
const backCam = cameras.find(c => c.label.toLowerCase().includes('back')) || cameras[0];
html5QrCode.start({ deviceId: backCam.id }, config, onSuccess, onError);
Restricting to specific formats
const config = {
fps: 10,
qrbox: 250,
formatsToSupport: [
Html5QrcodeSupportedFormats.QR_CODE,
Html5QrcodeSupportedFormats.EAN_13,
Html5QrcodeSupportedFormats.UPC_A
]
};
This is how ScanApp’s ISBN scanner restricts itself to ISBN-13 — by filtering formats client-side after the standard EAN-13 decode.
Pitfalls to Watch For
- iOS Safari camera permission UX is unique. The first time the user grants permission, Safari prompts inline; afterward it’s cached. Test the “denied” path carefully — your error UI should explain how to re-enable in Settings.
- The
qrboxconfig affects performance. Smaller decode windows are faster but require the user to aim more precisely. ScanApp uses 250×250 px at standard density for a balance. - HTTPS is required for browser camera APIs. Local development on
localhostworks; deploying to plain HTTP breaks camera access entirely. facingMode: "environment"doesn’t always select the back camera on Android. On multi-camera phones (ultrawide + standard + telephoto), Android may pick the ultrawide, which has the wrong focal length. Always enumerate cameras explicitly and pick by label.
When to Pick a Different Library
- QR-only use case, bundle-size critical: Use
jsQR. - 1D retail barcode only, no QR: Use
Quagga2. - Enterprise commercial product with budget:
Dynamsofthas the highest accuracy and best support, but requires licensing. - Need to ship in a native app via WebView: Either
html5-qrcodeworks, or use the platform-native scanner (Apple Vision, ML Kit) and avoid web entirely.
For most open-source web projects that need a scanner, html5-qrcode is the right default.
Frequently Asked Questions
Is html5-qrcode open source?
Yes. It’s released under the Apache 2.0 license and developed publicly on GitHub.
Does html5-qrcode work on iPhone?
Yes. It uses the standard WebRTC getUserMedia API which is supported in Safari on iOS 11+. Camera permission must be granted by the user on first use.
What barcode formats does html5-qrcode support?
QR Code, Aztec, Code 39, Code 93, Code 128, Codabar, Data Matrix, EAN-13, EAN-8, ITF, MaxiCode, PDF417, RSS-14, UPC-A, and UPC-E.
Does html5-qrcode upload images to a server?
No. All decoding runs in the user’s browser. Nothing is uploaded.
Why does ScanApp use html5-qrcode?
Format breadth, iOS Safari handling, active maintenance, and open-source licensing — all in a single 230 KB bundle.