How to use QuaggaJS – a barcode scanner example for your website or web app

app store

QuaggaJS is a popular open-source barcode scanner written in JavaScript that locates and decodes various 1D barcode symbologies in the user’s camera stream.

While the original project is no longer maintained, it lives on as Quagga2, which is what we’ll be using in our tutorial.

Since Quagga is a JavaScript-only library, it is easy to integrate into any website or web app. In this tutorial, we’ll show you how to set up the barcode scanner in a single HTML file.

Step 1: Setting up the HTML file

Let’s start by creating the basic structure of the HTML document:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title>QuaggaJS</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
</head>

<body>
</body>
</html>

💡 The line <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/> ensures that the page fits the device’s resolution and that users cannot zoom into it.

The first thing we’ll put into the body is a div into which we’ll later render the camera stream:

<body>
    <div id="camera"></div>
</body>

Step 2: Configuring Quagga

Next, we’ll add Quagga itself. We’re including the quagga.min.js script from jsDelivr, but you can of course also host the script on your own web server.

<body>
    <div id="camera"></div>
    // new
    <script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.min.js"></script>
</body>

Now, we need to configure QuaggaJS. First, we have to specify the DOM element where the video stream will be displayed. Next, we also need to specify the barcode decoders we want to use.

To accomplish the first part, we create a config object, which we will call quaggaConf. We use document.querySelector to select the div we created above as the target where the video stream will be displayed.

<script>
    const quaggaConf = {
        inputStream: {
            target: document.querySelector("#camera")
        }
    }
</script>

Now we specify which barcode symbologies our QuaggaJS app will read (to optimize performance, it’s recommended to only include those you expect to scan). In this tutorial, we’ll be sticking to the common barcode type Code 128. You can find a list of all supported symbologies in the Quagga2 GitHub repository.

<script>
    const quaggaConf = {
        inputStream: {
            target: document.querySelector("#camera"),
        },
        // new
        decoder: {
            readers: ['code_128_reader']
        },
    }
</script>

The next step is to prepare the initialization function. We provide our Quagga configuration and an error handler. If the initialization is successful, Quagga.start() will begin the barcode scanning process.

We have also added a function to display an alert with the barcode result when a barcode is detected and read.

<script>
    const quaggaConf = {
        inputStream: {
            target: document.querySelector("#camera"),
        },
        decoder: {
            readers: ['code_128_reader']
        },
    }

    // new
    Quagga.init(quaggaConf, function (err) {
        if (err) {
            return console.log(err);
        }
        Quagga.start();
    });

    Quagga.onDetected(function (result) {
        alert("Detected barcode: " + result.codeResult.code);
    });
</script>

Step 3: Configuring the video stream

Now we’ll add LiveStream as the input stream type, since we want to process and display the live video as captured by the user’s camera. Other possible values for the stream type are described in the Quagga docs.

We’ll also have to define the constraints for the video stream. To do that, we need to specify the width, height, aspect ratio, and camera for the input stream.

💡 A lower resolution will result in faster scanning speeds at the cost of accuracy.

<script>
    const quaggaConf = {
        inputStream: {
            target: document.querySelector("#camera"),
            // new
            type: "LiveStream",
            constraints: {
                width: { min: 640 },
                height: { min: 480 },
                facingMode: "environment",
                aspectRatio: { min: 1, max: 2 }
            }
        },
        decoder: {
            readers: ['code_128_reader']
        },
    }

    Quagga.init(quaggaConf, function (err) {
        if (err) {
            return console.log(err);
        }
        Quagga.start();
    });

    Quagga.onDetected(function (result) {
        alert("Detected barcode: " + result.codeResult.code);
    });
</script>

Next, we add some styling to display the video in the resolution we requested from the camera to ensure it fits the screen.

<head>
    <meta charset="utf-8"/>
    <title>QuaggaJS</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
    // new
    <style>
        #camera video{
            width:100%;
            max-width: 640px;
        }
    </style>
</head>

Lastly, we’re going to apply a style attribute to our camera div to make it take up the entire width of the body.

<body>
    <div id="camera" style="width:100%"></div>
</body>

And we’re done! 🎉

The final result looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title>QuaggaJS</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
    <style>
        #camera video{
            width:100%;
            max-width: 640px;
        }
    </style>
</head>

<body>
<div id="camera" style="width:100%"></div>
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.min.js"></script>
<script>
    const quaggaConf = {
        inputStream: {
            target: document.querySelector("#camera"),
            type: "LiveStream",
            constraints: {
                width: { min: 640 },
                height: { min: 480 },
                facingMode: "environment",
                aspectRatio: { min: 1, max: 2 }
            }
        },
        decoder: {
            readers: ['code_128_reader']
        },
    }

    Quagga.init(quaggaConf, function (err) {
        if (err) {
            return console.log(err);
        }
        Quagga.start();
    });

    Quagga.onDetected(function (result) {
        alert("Detected barcode: " + result.codeResult.code);
    });
</script>
</body>
</html>

Try scanning a Code 128 to see if everything works as intended.

Code 128 barcode example

Drawbacks of using QuaggaJS

As impressive as this JavaScript-based barcode scanner implementation is, QuaggaJS does have its disadvantages.

The biggest drawback is that it only supports 1D barcodes. Two-dimensional symbologies like QR Code, Data Matrix, and Aztec encode much more data while taking up less space, which makes them a valuable alternative to their one-dimensional counterparts.

As useful as it is to have a barcode scanner written in JavaScript, the performance of the detection algorithm would also benefit from an implementation in WebAssembly. Especially on low-end devices, this could result in increased scanning speeds.

Quagga’s feature set is also not on par with that of professional solutions. Enterprise-grade barcode scanner software often includes dedicated modules for scanning many barcodes simultaneously or in rapid succession, as well as UI elements, all of which this open-source solution lacks.

If you plan to use Quagga in production, you should also keep in mind that you will depend entirely on the open-source community for its maintenance and for support. If you run into a problem, you might have to find a solution on your own.

Conclusion

QuaggaJS is a useful free barcode scanning solution with high compatibility, thanks to it being written in JavaScript. 

However, Quagga’s speed, accuracy, and UX features can’t hold a candle to proprietary offerings. For companies that heavily rely on barcode scanning in their business processes, we recommend using an enterprise-grade solution instead.

Developers, ready to get started?

Adding our free trial to your app is easy. Download the Scanbot SDK now and discover the power of mobile data capture