# quagga2 and the case for browser-native barcode reading

> quagga2 is a TypeScript rewrite of the abandoned QuaggaJS library that locates and decodes barcodes in a live camera stream without a native plugin. It suits web teams that need scanning on a page today, and it does not suit backends or mobile apps that want a compiled scanner.

**ericblade/quagga2** — An advanced barcode-scanner written in Javascript and TypeScript - Continuation from https://github.com/serratus/quaggajs

- Repository: https://github.com/ericblade/quagga2
- Stars: 911 · Forks: 97
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/ericblade-quagga2

## A fork that exists because the original author stopped

quagga2 is maintained by ericblade as a continuation of the original QuaggaJS project, and the project notes are explicit about the reason: the fork will be kept alive until the original author and maintainer returns, or until the work is replaced by built in browser and node functionality. That framing matters for anyone evaluating dependency risk, because the project is not trying to outcompete the upstream design, it is trying to keep a working decoder available while the platform catches up.

The scope is a barcode scanner written entirely in JavaScript and TypeScript. The supported symbologies listed in the documentation are EAN, CODE 128, CODE 39, EAN 8, UPC-A, UPC-C, I2of5, 2of5, CODE 93, CODE 32, CODABAR and PHARMACODE. The library can also reach the camera directly through getUserMedia, and the project claims that although the code relies on heavy image processing, recent smartphones are able to locate and decode barcodes in real time.

The target user is a web developer who needs a scanner in a page, a component library, or a single page application, and who does not want to require an installable native module on the user's machine. There is no homepage listed for the project and the documentation site is marked as under construction, so the readme and the API surface are the main orientation points.

## The locator is what separates it from a straight decode call

Quagga is described as an extension to zxing rather than another port of it. The distinguishing piece is a barcode locator that finds a barcode like pattern anywhere in an image and returns an estimated bounding box, including the rotation of the code. The project puts the practical consequence plainly: this reader is invariant to scale and rotation, whereas other libraries require the barcode to be aligned with the viewport.

That single property changes what a user has to do. A user holding a phone does not have to line the code up with a guide rectangle, and a photo of a shelf label does not have to be deskewed by hand before it is submitted. The pipeline is a two stage one, find first and then decode inside the region the locator chose.

The supported set is broad enough for retail, logistics and pharmacy style use cases, since it includes the EAN and UPC families, the Code set including 39, 93, 128 and 32, the two of five variants, CODABAR and PHARMACODE. The documentation does not list 2D symbologies such as QR codes, so a requirement for QR would need checking elsewhere before you plan around it. The blog post the project links to, on how barcode localization works in QuaggaJS, is the place to go for the algorithm detail.

## Installing the package and wiring a first camera scan

The package is published under the scoped name @ericblade/quagga2, which differs from the bare quagga name many older examples still use. Install it with npm:

```console
> npm install --save @ericblade/quagga2
```

Then import it, choosing the module system your bundle expects. The CommonJS line carries a real warning in its own comment, since the export sits on the default property:

```javascript
import Quagga from '@ericblade/quagga2'; // ES6
const Quagga = require('@ericblade/quagga2').default; // Common JS (important: default)
```

If your page is not built with a bundler, the library can be included with a plain script tag, and the script exposes the library on the global namespace under Quagga. Two CDN forms are given, the full file and the minified one:

```html
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.js"></script>
```

```html
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.min.js"></script>
```

A version can be pinned in the URL, which matters for long lived pages, as the sample for version 1.2.6 shows:

```html
<!-- Link for Version 1.2.6 -->
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.2.6/dist/quagga.js"></script>
```

The npm install path also gives you the unminified quagga.js file from the dist folder if you prefer to self host it.

## Two operating modes and the secure origin trap

The library runs in two distinct modes, and the browser requirements differ between them. Static image analysis needs canvas, typed arrays, blob URLs and blob builder. Live stream mode needs all of those plus the MediaDevices API, and a caniuse compatibility page is linked for each combination so you can check the exact set of features a target browser needs.

There is a catch that catches teams during deployment. Accessing getUserMedia requires a secure origin in most browsers, so http:// works only on localhost, and every other hostname has to be served over https. A scanner that works fine in local development can fail on an internal staging host that has no certificate. The repository even includes server.pem and a simple-https-server.py at the top level, which points at how the maintainer handles local testing over TLS.

A second rough edge is browser inconsistency in how mediaDevices.getUserMedia is implemented. The project therefore recommends including webrtc-adapter in your project, and gives a feature detection snippet you can use to test the browser before you ask for camera permission:

```javascript
if (navigator.mediaDevices && typeof navigator.mediaDevices.getUserMedia === 'function') {
  // safely access `navigator.mediaDevices.getUserMedia`
}
```

Separate community integrations are listed for React, Redux, Angular, ThingWorx, Vue 2 and Vue 3, and docs/examples/ holds live browser examples.

## In node only file based decoding is available

This is the sharpest boundary in the project. The documentation states that the full functionality is only available through the browser, and that when using QuaggaJS within node, only file based decoding is available. There is a node example section to follow, but the headline remains: no camera stream, no live decoding, in node.

The dependency list in package.json reinforces that reading. The optional dependencies are fsevents at 2.3.3, ndarray-pixels at ^5.0.1 and sharp at ^0.35.3. The sharp entry is a native image processor, and ndarray-pixels is a pixel buffer helper, both of which point to a file oriented image decoding path rather than a device oriented one.

There is also a packaging detail worth checking in your own build. The package main field is lib/quagga.js and the types field points at type-definitions/quagga.d.ts, but the browser field is set to dist/quagga.min.js. Bundlers that respect the browser field will therefore hand your application the minified distribution instead of the main entry. If you plan to read stack traces, or you need source maps, or you need to tree shake, that substitution is worth verifying in your own build output rather than assuming.

For a backend service that already receives images by upload or by camera batch, the file based path may be exactly what you want. For a backend that has to pull frames from a device, it is not.

## A MIT licence, a rolling release train and an ageing container base

The licence field on the repository says MIT, so the code can be used in commercial and closed source products, subject to the usual obligation to keep the licence and copyright notice in copies of the software. This is a permissive licence with no copyleft obligation on your application code, and it is the same footing the original QuaggaJS code was released under.

The release history is dense and recent. Version 1.11.0 was published on 2025-12-01, 1.12.0 on 2025-12-16 and 1.12.1 on 2025-12-20, and the last push to the repository was on 2026-10-19. A badge in the project marks rolling versions as enabled, which tells you the maintainer expects to keep publishing under a rolling tag scheme rather than freeze the line.

The container story is less current. The Dockerfile in the repository starts from an ARG NODE_VERSION of 13, which is a long superseded Node release, and the docker-compose file builds that image and runs the build command npm run build with the working directory mounted. A Docker build for a production deployment therefore needs the base image updated, and the compose file is more of a developer convenience than a deployable unit. The repository also carries migration notes for Cypress and Playwright, a HALFSAMPLE_PERFORMANCE_ANALYSIS.md file and a DEPENDENCIES.md file, which suggests the test and dependency surface is maintained with some care even though the container base is not.

## Where quagga2 is the wrong tool

The honest cases against it are specific rather than general.

First, if you need 2D codes such as QR or Data Matrix, the listed symbologies do not cover them, and the project description centres on one dimensional barcodes. Second, if your scanning has to happen in node or in a native mobile application, the browser only feature set rules it out. Third, if you need to work offline from a native camera, you would need a compiled engine rather than a page that asks the browser for a media stream.

The alternative to understand is zxing, which the project names as the library it extends rather than ports. A plain zxing style decode call expects an image with a readable code and no preprocessing, while quagga2 adds a locator stage that estimates position and rotation before decoding, which is what allows an unaligned handheld shot to succeed. Another realistic option is the native platform capability, on a phone that can be pointed at a barcode directly, which avoids the browser permission dance and the https requirement but ties the scanning to the platform.

A final practical caution: the documentation site is labelled under construction, and the project points to an API reference, tutorials and guides that are still being written. If your team needs a supported reference for every configuration key, you will be reading the source and the type definitions in type-definitions/ rather than a finished manual.

## Conclusion

quagga2 is worth adopting for a browser-based scanning flow, especially where the team wants rotation and scale tolerance without a native camera module, and it is the wrong choice for a server side pipeline or a mobile app that can use a compiled engine. Before committing, verify the symbologies you actually need, confirm that the pages you serve are on a secure origin, and check that your bundler resolves the browser field in package.json to the browser build rather than the node build.

## FAQ

### What is the difference between quagga2 and the original QuaggaJS library?

quagga2 is a fork of QuaggaJS that the maintainer says will be kept alive until the original author returns or until built in browser and node functionality replaces the work. The upstream project is not being extended from inside its own repository, so the two are separate code bases that you should not expect to be interchangeable.

### How do I install quagga2 and import it in JavaScript?

Run npm install --save @ericblade/quagga2, then import Quagga from '@ericblade/quagga2' for ES6 or use require('@ericblade/quagga2').default for CommonJS. The default property is marked as important for the CommonJS form.

### Can quagga2 decode barcodes from a live camera in node?

No. The documentation says the full functionality is only available through the browser, and that within node only file based decoding is available. Camera streams, which rely on the MediaDevices API and getUserMedia, are a browser capability.

### Which barcode formats does quagga2 support?

The listed symbologies are EAN, CODE 128, CODE 39, EAN 8, UPC-A, UPC-C, I2of5, 2of5, CODE 93, CODE 32, CODABAR and PHARMACODE. The set covers one dimensional barcodes, and QR or other 2D formats do not appear among them.

### Why does the camera fail on my staging site but work on localhost?

Accessing getUserMedia requires a secure origin in most browsers, so http:// works only on localhost and every other hostname must be served over https. The repository includes server.pem and a simple-https-server.py, which are the maintainer's own way of running local testing over TLS.

## Sources

- [ericblade/quagga2 on GitHub](https://github.com/ericblade/quagga2)
- [Issues](https://github.com/ericblade/quagga2/issues)
- [License: MIT](https://github.com/ericblade/quagga2/blob/master/LICENSE)
- [README](https://github.com/ericblade/quagga2/blob/master/README.md)
- [Releases](https://github.com/ericblade/quagga2/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ericblade-quagga2
