Published on: 10/14/2026 by Alex Suzuki

Overview

In this article we’ll have a look at the Open Source barcode scanning SDK landscape.

Instead of the usual AI-generated “10 Best <something>” lists, we’ll try to give in-depth information from a domain expert, along with recommendations on which SDK is best suited for which use case, and short, interactive code snippets illustrating their use. All the code snippets are live, and actually exercise the libraries.

We’ll look at the following characteristics:

  • History: how did the project come to be? Who built it?
  • Freshness: is the SDK actively maintained? Have there been published releases in recent years?
  • Coverage: does the SDK support only a certain type of code (e.g. QR code), or does it attempt to be broad?
  • Licensing: does the license make the SDK suitable for commercial use? Does using the SDK in your code require attribution?
  • Support: is support available? Do maintainers accept donations or offer contracting services?

Let’s dive in!

Quagga2

Quagga2 is a fork of QuaggaJS, which was originally created by Christoph Oberhofer in 2015, right around the time WebRTC and camera access became available in the browser. QuaggaJS uses a barcode localization approach described in the paper “Locating and decoding EAN-13 barcodes from images captured by digital cameras”, and which Christoph very nicely illustrated in a blog post.

Christoph seems to have long since stopped working on QuaggaJS (he lists 2014–2016 as the time frame he worked on it). Luckily, a fork called Quagga2 exists and is actively maintained. At the time of writing (October 2026), the last release was version 1.12.1 in December 2025, so not that long ago.

By its nature, Quagga2 only supports linear (1D) barcodes. The supported symbologies are Code 128, EAN, UPC, Code 39, Code 32, Code 93, Codabar, ITF and Pharmacode.

2D matrix codes such as QR Code, Data Matrix or Aztec Code are not supported. There is a plugin that allows plugging in a QR decoder (backed by jsQR), but there’s no release and its status is unclear. Stacked barcode symbologies like PDF417 or GS1 DataBar are also not supported.

Quagga2 is MIT-licensed, making it suitable for commercial use. Separate attribution is not required, as long as the copyright notice is shipped with the code.

Support is best-effort via GitHub issues. The maintainer has a PayPal sponsorship link on the GitHub repository. If you use Quagga2, consider sponsoring the project!

Example: using Quagga2 to decode a single image

To decode a static image from an <img> tag using Quagga2, the decodeSingle() API can be used. It accepts as input an image, in data URL format or as an RGBA Uint8Array. To get there from our img tag, we need to do the awkward draw to Canvas dance:

// helper function to convert contents of an <img> tag to a PNG data URL
function imgToDataURL(img) {
    const c = document.createElement('canvas');
    c.width = img.naturalWidth;
    c.height = img.naturalHeight;
    c.getContext('2d').drawImage(img, 0, 0);
    return c.toDataURL('image/png');
}

// load Quagga from a CDN
const Quagga = await loadQuagga(); // load Quagga dynamically from CDN (omitted for brevity, View Source if interested)
const res = await Quagga.decodeSingle({
    src: imgToDataURL(root.querySelector('img')),
    locate: false, // apparently required for pure codes?
    decoder: {
        readers: ['code_128_reader'] // sample is Code 128
    }
});
if (res && res.codeResult) {
    output.innerText = `Decoded value: ${res.codeResult.code}`;
}

To run the above code, simply click the button and observe the result.

Sample Code 128 barcode
Press button to decode the image

To decode from a live video stream, you’d use the inputStream option in the config object and pass a reference to a DOM element to host the video feed.

jsQR

The jsQR is an MIT-licensed library by Cosmo Wolfe implements a QR decoder in pure JavaScript.

The library has not seen updates in more than 5 years and is considered dead. It was forked and integrated into the qr-scanner project.

Only QR codes can be decoded with this library, no other code types are supported.

As the library has been superseded by another project, we have not looked at it further, and we also do not recommend using it.

qr-scanner

qr-scanner by Nimiq is based on the previously mentioned jsQR library, with modifications targeting size, providing a native BarcodeDetector fallback and support for scanning from a video stream.

Unfortunately, this library too appears to be unmaintained. The last commit on the GitHub repository was in 2022, four years ago at the time of writing.

No support is provided. GitHub issues are going unanswered, including an offer from someone to take over maintenance of the library.

Example: using qr-scanner to decode a single image

To decode QR codes from a static image from an <img> tag using qr-scanner, the scanImage() API can be used. It already accepts a variety of different input types, including a plain image tag, so no conversion via Canvas is necessary.

try {
    const QrScanner = await loadQrScanner();
    const res = await QrScanner.scanImage(img);
    output.innerText = `Decoded value: ${res.data}`;
} catch (e) {
    output.innerText = `Decoding failed: ${e?.message ?? e}`;
}

Try it out by clicking on the Decode QR code button below.

Sample QR code
Press button to decode the image

ZXing and friends

ZXing is the OG of barcode decoding libraries. It was originally released for Java, back in 2007, as a 20% project of a Google developer called Sean Owen. To our great surprise, the announcement post on Google’s developer blog is still online.

In a testament to its quality, the library is still maintained, even if activity is low. The original author still occasionally contributes to it.

ZXing and its derivatives and ports all use the Apache 2.0 license, making them suitable for commercial use. Make sure you attribute the dependency properly by including the NOTICE file.

Due to its age and popularity, several community-maintained forks and ports to other languages exist. In many ways, ZXing is considered the Open Source reference implementation.

ZXing-JS

In the JavaScript world, ZXing-JS is arguable the most popular library for barcode decoding. It started as a continuation of the zxing-typescript project by Adrian Toșcă in 2017, which initially only ported the QR decoder, and apparently abandoned the effort afterward. The work was then picked up in 2018 by David Werth and Luiz Barni which ported the rest of the barcode types.

The library is currently looking for new maintainers as the existing team no longer has time to maintain it. ZXing-JS recommends using our STRICH Barcode Scanning SDK as a replacement if maintenance and support guarantees are required, for which we kindly thank them! ❤️

Example: using ZXing-JS to decode a single image

To decode QR codes from a static image from an <img> tag using ZXing-JS, the BrowserQRCodeReader.decodeFromImageElement() API can be used.

try {
    const { BrowserQRCodeReader } = await loadZXing();
    const result = await new BrowserQRCodeReader().decodeFromImageElement(img);
    output.innerText = `Decoded value: ${result.getText()}`;
} catch (e) {
    output.innerText = `Decoding failed (no code found or other error)`;
}

Try it out by clicking on the Decode QR code button below.

Sample QR code
Press button to decode the image

zxing-cpp and zxing-wasm

ZXing-cpp started out as a C++ port of the original Java codebase but was independently developed further, with Axel Waggershauser being the lead developer and maintainer.

As of today, zxing-cpp is under active development and the maintainer is responsive to GitHub issues.

Using the Emscripten toolchain, projects written in C and C++ can be compiled to WebAssembly and run in the browser (check out our fun blog post on Embedding WebAssembly in QR codes if you’re interested in the technology).

The zxing-wasm project publishes a WebAssembly build of zxing-cpp.

Example: Using zxing-wasm to decode a single image

To scan an image using zxing-wasm, use the readBarcodes() API. This API expects an ImageData object (a wrapper for the pixel values), which can be similarly obtained using a Canvas.

function imgToImageData(img) {
    const c = document.createElement('canvas');
    c.width = img.naturalWidth;
    c.height = img.naturalHeight;
    const ctx = c.getContext('2d');
    ctx.drawImage(img, 0, 0);
    return ctx.getImageData(0, 0, c.width, c.height);
}

const { readBarcodes } = await loadZXingWasm();
const results = await readBarcodes(imgToImageData(img), { formats: ['QRCode'] });
if (results.length > 0) {
    output.innerText = `Decoded value: ${results[0].text}`;
} else {
    output.innerText = 'Decoding failed: no QR code found';
}

Try it out by pressing the Decode with zxing-wasm button!

Sample QR code
Press button to decode the image

html5-qrcode

The somewhat oddly named html5-qrcode project embeds ZXing-JS and provides a UI layer and support for decoding from a live video stream. We say oddly named because judging from only the name, you might think that only QR codes are supported, but in fact the entire set of code types supported by ZXing-JS is supported.

The project is no longer actively developed, and the current maintainer is looking for a new owner. Obviously, you shouldn’t expect support in this situation.

The library uses the Apache 2.0 license, like its upstream ZXing-JS dependency.

The maintainer has a ko-fi link to incentivize feature development and bug fixing. If you use html5-qrcode, consider supporting them!

Example: using html5-qrcode to decode a single image

To decode QR codes from a static image from an image element using html5-qrcode, the Html5Qrcode.scanFile() API can be used. To complete the weirdness of getting image data in the browser, here we need to convert to a File object, using the now familiar draw to Canvas to get actual image data technique.

function imgToPngFile(img) {
    const c = document.createElement('canvas');
    c.width = img.naturalWidth;
    c.height = img.naturalHeight;
    c.getContext('2d').drawImage(img, 0, 0);
    return new Promise((resolve, reject) => {
        c.toBlob((blob) => blob
            ? resolve(new File([blob], 'image.png', { type: 'image/png' }))
            : reject(new Error('Canvas to PNG conversion failed')), 'image/png');
    });
}

try {
    const workArea = document.querySelector('...');
    const { Html5Qrcode, Html5QrcodeSupportedFormats } = await loadHtml5Qrcode();
    const scanner = new Html5Qrcode(workArea.id, {
        verbose: false,
        formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE]
    });
    const decodedText = await scanner.scanFile(await imgToPngFile(img), false);
    output.innerText = `Decoded value: ${decodedText}`;
} catch (e) {
    output.innerText = `Decoding failed`; // no code found, or other error
}

Try it out by clicking on the Decode QR code button below.

Sample QR code
Press button to decode the image

ZBar and zbar-wasm

ZBar by Jeff Brown is an older but highly performant and well-architected barcode reading library written in C, making it a popular choice for embedded environments where speed and predictable memory allocation behavior is important.

ZBar supports a range of 1D barcodes, as well as QR codes. Other 2D symbologies like Data Matrix, or stacked 1D symbologies like PDF417 are not supported.

Fun fact: the author intended to implement support for PDF417 barcodes (the decoder stub exists in the repository) but the implementation was never finished. The author of this article imagines that the Gaulois Field 929 and the general weirdness of PDF417 may have contributed to that.

ZBar was originally hosted on Sourceforge, but the content was last updated in 2010, more than 15 years ago. Development and maintenance continues on GitHub and the project seems active, with recent commits.

ZBar is LGPL-licensed (a weak copyleft license), making it in theory suitable for commercial settings, but care has to be taken to comply with the replaceability clause.

Similar to zxing-cpp, ZBar by itself is not suitable for use in a JavaScript environment. That’s where the zbar-wasm project comes in. It’s a relatively new project (first release in 2021) and it, too, uses the Emscripten toolchain to generate a WebAssembly build of ZBar for use in browser or Node.js environments.

Example: using zbar-wasm to decode a single image

To decode QR codes from a static image with zbar-wasm, use the scanImageData() API.

function imgToImageData(img) {
    const c = document.createElement('canvas');
    c.width = img.naturalWidth;
    c.height = img.naturalHeight;
    const ctx = c.getContext('2d');
    ctx.drawImage(img, 0, 0);
    return ctx.getImageData(0, 0, c.width, c.height);
}

const { zbar, scanner } = await loadZBar();
const symbols = await zbar.scanImageData(imgToImageData(img), scanner);
if (symbols.length > 0) {
    output.innerText = `Decoded value: ${symbols[0].decode()}`; // raw bytes
} else {
    output.innerText = 'Decoding failed: no QR code found';
}

To try it out, press the Decode with zbar-wasm button below.

Sample QR code
Press button to decode the image

Conclusion

If you’re looking for an Open Source barcode scanning SDK for use in the browser, there are quite a few to choose from, all human-made with specific quirks and a beautiful history.

Volunteers maintain these libraries in their free time, so you shouldn’t expect much in terms of maintenance and support. If you use one of these libraries, please consider supporting the maintainers through sponsorships or donations.

If barcode scanning powers important processes in your business, we recommend using STRICH Barcode Scanning SDK, which is actively maintained and supported, and read our comparison of STRICH vs ZXing-JS and Quagga.

Thanks for reading! This article was written by a human, and we hope you enjoyed it.