The great JavaScript barcode scanning library shoot-out

We compare real-life 1D/2D barcode scanning performance of STRICH with its open-source competitors, ZXing and QuaggaJS.

Cover image containing all missions

Introduction

A question we often hear:

"Why should we pay for STRICH, if we can use other libraries for free?"

It's a valid question — and 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 its main open-source competitors in real-life 1D/2D barcode scanning.

Meet the competition: ZXing and QuaggaJS

ZXing and QuaggaJS are two popular open-source alternatives to commercial barcode scanning libraries like STRICH. Both libraries are open-source and available under a permissive license.

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 was ported to JavaScript in 2017 by volunteer. It is currently looking for new maintainers.

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, mainly Eric Blade. Quagga (we will use this name to refer to the current version) only supports 1D barcodes.

The rules of the game

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"
    }
  ]
}
Sample mission containing two Code 128 and one Data Matrix code

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.

Missions

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), which is a fairly high-spec Android phone at the time of writing. The operating system is Android 13 and the browser is Chrome 112.

Mission 1: DHL Barcodes (good quality)

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.

DHL package label (good quality)
DHL package label (good quality). Full-res image
Implementation Codes read Elapsed time Misreads
Quagga 3/3 0.7 seconds 1
ZxingJS 2/3 abort 0
STRICH 3/3 0.5 seconds 0

Results

Unsurprisingly, all three libraries manage to complete this mission successfully, although STRICH wins first place for both shortest elapsed time and zero misreads.

Quagga performed on-par with STRICH in this benchmark, but we had to manually change the default configuration to request a stream with HD resolution (1280x720). Also Quagga returned a misread code value of F%$B56t+46210000816C. Misreads can be problematic if an application can not perform validation of the barcode value without contacting a backend service.

To our surprise, ZXing appears to be unable to read the finer Code 128 barcode in the middle. We suspect this is also due to insufficient camera resolution being requested, but ZXing does not expose an API to change this.

Mission 2: DHL Barcodes (degraded print)

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.

DHL package label (degraded print)
DHL package label (degraded print). Full-res image
Implementation Codes read Elapsed time Misreads
Quagga 0/3 abort 0
ZxingJS 1/3 abort 0
STRICH 3/3 1.7 seconds 0

Results

The degraded print poses significant challenges for both ZXing and Quagga, which both fail to read the Code 39 and the middle Code 128 barcode. ZXing manages to read the bottom Code 128 barcode but only after a delay and a precise distance.

STRICH manages to read all three barcodes, albeit with a slightly longer elapsed time. STRICH has image processing algorithms that can clean up an image and fix "broken bars", a capability which ZXing and Quagga are presumably lacking.

Mission 3: DPD package label (1x Code 128, 1x Aztec)

In this mission, a Code 128 barcode and an Aztec code (a 2D code that has a pyramidal shape) need to be scanned. Only ZXing will be considered, as Quagga does not support 2D barcodes.

DPD package label (Code 128 and Aztec)
DPD package label (Code 128 and Aztec). Full-res image
Implementation Codes read Elapsed time Misreads
Quagga - - -
ZXing 1/2 abort -
STRICH 2/2 1.7 seconds 0

Results

Although Aztec is supported by ZXing, the library fails to read the Aztec code. We tried multiple times and aligned the code perfectly to the camera and made sure it was in focus. The Code 128 barcode is read successfully by ZXing.

STRICH manages to read both codes without issues.

Mission 4: Amazon package label (1x Code 128, 1x Data Matrix)

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, Quagga will not be considered, as it can not decode the Data Matrix code.

Amazon package label (Code 128 and Data Matrix)
Amazon package label (Code 128 and Data Matrix). Full-res image
Implementation Codes read Elapsed time Misreads
Quagga - - -
ZXing 3/3 1.7 seconds -
STRICH 3/3 0.8 seconds 0

Results

Both ZXing and STRICH complete the mission without issues. However, ZXing can only read the Data Matrix code if it is positioned at a right angle. STRICH manages to read the code regardless of its rotation.

Quagga and ZXing configuration

Quagga in its default configuration did not manage to read even the barcodes of the first mission. A problem we noticed was that the camera resolution requested was not sufficient. Manually specifying appropriate MediaTrackConstraints for the getUserMedia invocation was necessary. This is a major hurdle for developers that are not familiar with the inner workings of getUserMedia. In addition, we configured only the readers necessary for the formats occurring in the mission.

ZXing was configured to use the "try harder" option and only search for the barcode formats occurring in the mission. ZXing does not seem to expose a way to set a certain camera resolution.

Conclusions

As can be seen from the mission results, STRICH performs significantly better than the open-source competitors. STRICH's built-in scanning user interface and "out of the box" setup enables efficient and user-friendly scanning with low integration effort.

Crucially for businesses, STRICH is maintained and comes with support and integration assistance. And that is why we have to charge money for it.

Back to top