We compare the real-life 1D/2D barcode scanning performance of STRICH to open-source alternatives ZXing-JS and QuaggaJS.
By Alex Suzuki · Published · Updated
“Why should we pay for STRICH, if we can use other libraries for free?”
It's a legitimate question! It's perfectly possible to build a scanning app using free and open-source libraries. But for some scenarios, especially when the scanning app fulfills a crucial role in your business process, it is worth considering a commercial library like STRICH.
The aim of this article is to illustrate the differences between STRICH and two popular open-source alternatives in real-life 1D/2D barcode scanning.
ZXing-JS and QuaggaJS are two popular open-source barcode scanning libraries, both available under a permissive license. They have helped countless developers add barcode scanning to their web apps.
ZXing is a (quote) open-source, multi-format 1D/2D barcode image processing library implemented in Java, with ports to other languages. ZXing has a long history, it was originally released in 2008 in Java, and in 2017 it was ported to JavaScript by a volunteer, with the port named ZXing-JS. The project is currently looking for new maintainers, and recommends STRICH for commercial applications. We're proud to sponsor ZXing-JS.
QuaggaJS was created by Christoph Oberhofer and first released in 2014. The last release of the original project was in 2017. It was forked and now lives on as Quagga2 and is maintained by volunteers. Quagga (we will use this name to refer to the current version) focuses on 1D barcodes.
We did not include Html5-QRCode in the comparison as it uses ZXing-JS under the hood, so we do not expect the performance to differ. Html5-QRCode is currently also looking for a new maintainer.
We will compare scanning performance by going through a set of real-life scanning scenarios which we will call missions. A mission is a set of 1D and 2D barcodes to scan, in any order. Expressed as a JSON structure (which is how we represent them):
{
"codes": [
{
"type": "code128",
"value": "996014597900176642"
},
{
"type": "code128",
"value": "0509"
},
{
"type": "datamatrix",
"value": "SUcfZvyQ2L_001_v"
}
]
} The mission starts when any of the barcodes contained in the mission are read. During the mission, the app keeps track of the elapsed time, remaining codes and misreads. Misreads are codes read that do not belong to the mission, and are usually 1D barcodes that the library misinterpreted. The avoid unnecessary processing, the libraries are configured to only detect the types of codes that occur in the mission. As elapsed time is dependent on the user's behavior, we repeat the mission at least three times to get and use the lowest time as elapsed time.
We built an app that can record missions and perform missions using any of the three scanning libraries.
In the following sections, we have a look at a set of representative scanning missions, all of which are included in the Benchmark app.
The device used for testing is a Samsung Galaxy S21 FE (model SM-G990B).
In this mission, the aim is to scan all three barcodes from a DHL package label. The label contains two Code 128 and one Code 39 barcode. All codes have good print quality.
| Implementation | Codes read | Elapsed time | Misreads |
|---|---|---|---|
| Quagga | 3/3 | 0.7 seconds | 1 |
| ZXing-JS | 2/3 | abort | 0 |
| STRICH | 3/3 | 0.5 seconds | 0 |
On a clean label, STRICH completes the mission in the shortest time, with zero misreads.
Quagga performed on par with STRICH after we tuned its configuration to request a stream with HD resolution (1280x720). Quagga returned one misread code value (F%$B56t+46210000816C). Avoiding misreads is a priority for STRICH, because they are hard to catch when an application can not validate a barcode value without contacting a backend service.
ZXing-JS read two of the three codes, but not the finer Code 128 barcode in the middle. We suspect the camera resolution is the limiting factor here, which ZXing-JS does not let you change. STRICH lets you configure the camera resolution, and its defaults are tuned for barcode scanning.
In this mission, we consider the same arrangement of barcodes, but with more challenging conditions. The bars are damaged and the print is generally faded, which is quite common.
| Implementation | Codes read | Elapsed time | Misreads |
|---|---|---|---|
| Quagga | 0/3 | abort | 0 |
| ZXing-JS | 1/3 | abort | 0 |
| STRICH | 3/3 | 1.7 seconds | 0 |
Degraded print is where STRICH's image processing pays off. STRICH cleans up the image and fixes "broken bars" before decoding, and reads all three barcodes. That takes a little longer than with a clean label, but the mission is completed.
Faded and damaged labels are a tough case for any barcode scanner. ZXing-JS read the bottom Code 128 barcode at a precise distance, while the Code 39 and the middle Code 128 barcode were not read by either open-source library.
In this mission, a Code 128 barcode and an Aztec code (a 2D code that has a pyramidal shape) need to be scanned. Quagga focuses on 1D barcodes, so only ZXing-JS and STRICH take part in this mission.
| Implementation | Codes read | Elapsed time | Misreads |
|---|---|---|---|
| Quagga | Not supported (1D barcodes only) | ||
| ZXing-JS | 1/2 | abort | - |
| STRICH | 2/2 | 1.7 seconds | 0 |
STRICH reads both codes without issues.
ZXing-JS reads the Code 128 barcode. It supports Aztec codes, but in our tests it did not read this one, even after several attempts with the code aligned to the camera and in focus.
The final mission consists of an envelope sent by Amazon, containing Data Matrix codes (actually the same code, in all four compass orientations) and two Code 128 barcodes containing a Swiss Post tracking number and a freight class. Again, only ZXing-JS and STRICH take part, as Quagga focuses on 1D barcodes.
| Implementation | Codes read | Elapsed time | Misreads |
|---|---|---|---|
| Quagga | Not supported (1D barcodes only) | ||
| ZXing-JS | 3/3 | 1.7 seconds | - |
| STRICH | 3/3 | 0.8 seconds | 0 |
Both ZXing-JS and STRICH complete the mission. STRICH reads the Data Matrix code in any orientation, while ZXing-JS read it when it was positioned at a right angle.
To give both open-source libraries the best possible chance, we tuned their configuration. Quagga managed to read the barcodes in the first mission after we requested a higher camera resolution, by specifying appropriate MediaTrackConstraints for the getUserMedia invocation. This requires some familiarity with the camera APIs of the browser, something STRICH takes care of for you. In addition, we configured only the readers necessary for the formats occurring in the mission.
ZXing-JS was configured to use the "try harder" option and only search for the barcode formats occurring in the mission. We did not find a way to set the camera resolution.
| Mission | Quagga | ZXing-JS | STRICH |
|---|---|---|---|
| DHL label, good quality | 3/3 | 2/3 | 3/3 |
| DHL label, degraded print | 0/3 | 1/3 | 3/3 |
| DPD label, Code 128 and Aztec | Not supported | 1/2 | 2/2 |
| Amazon label, Code 128 and Data Matrix | Not supported | 3/3 | 3/3 |
STRICH read every barcode in every mission, without misreads and without any tuning. Its built-in scanning user interface and "out of the box" setup enable efficient and user-friendly scanning with low integration effort.
ZXing-JS and Quagga are great projects, and for many use cases they are all you need. When scanning fulfills a crucial role in your business process, STRICH adds active maintenance, support and integration assistance. And that is why we have to charge money for it.
Full-resolution versions of the test images are available for download as a ZIP archive (download link), licensed under CC BY 4.0.
We are obviously biased, but in our benchmark STRICH was the only library that read every barcode in all four missions, with zero misreads and without any tuning.
ZXing-JS is a volunteer-run port of the Java ZXing library and is currently looking for new maintainers. Its README recommends STRICH for commercial applications, and we're proud to sponsor the project.
QuaggaJS was created by Christoph Oberhofer and had its last release in 2017. Quagga2 is a fork of QuaggaJS maintained by volunteers. When people refer to Quagga today, they usually mean Quagga2.
No. Quagga2 focuses on 1D barcodes such as Code 128, Code 39 and EAN. For QR codes, Data Matrix, Aztec or PDF417 you need a library with 2D support, like ZXing-JS or STRICH. See the barcode types STRICH supports.
STRICH cleans up the camera image and repairs broken bars before decoding, reads 2D codes in any orientation and configures the camera for barcode scanning out of the box. In our benchmark, that made the difference for fine 1D barcodes, degraded print and rotated Data Matrix codes.
Html5-QRCode builds on ZXing-JS and adds a scanning user interface, so we expect similar scanning performance. The project is currently looking for a new maintainer.
Each mission is a set of physical 1D and 2D barcodes that must all be scanned. The app records elapsed time, codes read and misreads, and each mission was repeated at least three times, using the fastest run. All libraries were configured to detect only the barcode types in the mission. A mid-range Android smartphone (Samsung Galaxy S21 FE) was used as the test device.
For prototypes, side projects and scanning good-quality codes in non-critical workflows, open-source libraries can be perfectly fine. When scanning is part of a business process, reliability, maintenance and support matter more. Our overview of open-source JavaScript barcode scanners covers the options.
Usually not hard. STRICH has no dependencies and works with any framework. Swiss Federal Railways migrated from QuaggaJS to STRICH, and the agency behind Kaufleuten's event scanning app replaced ZXing-JS with STRICH.
Yes. The demo app lets you scan your own codes right away, and the free 14-day trial lets you integrate STRICH into your app and compare it side by side with the library you use today.
Still have questions? Check out the full FAQ.
Integrating STRICH into your web app typically takes less than a day. Or try our free demo app and convince yourself that STRICH meets your needs.
Live demo ↗ Try for free ↗