Skip to the content.

API Documentation

Complete reference for all Quagga2 methods, callbacks, and events.

Core Methods

Quagga.init(config, callback)

Initializes the library with the given configuration and requests camera access if using live stream mode.

Parameters:

Returns: void

Example - Live Camera:

Quagga.init({
  inputStream: {
    type: "LiveStream",
    target: document.querySelector('#scanner')  // Or '#scanner'
  },
  decoder: {
    readers: ["code_128_reader"]
  }
}, function(err) {
  if (err) {
    console.error("Initialization failed:", err);
    return;
  }
  console.log("Initialization successful, ready to start");
  Quagga.start();
});

Example - Static Images:

Quagga.init({
  inputStream: {
    type: "ImageStream",
    src: "/path/to/images/*.jpg",
    target: document.querySelector('#scanner')
  },
  decoder: {
    readers: ["ean_reader", "code_128_reader"]
  }
}, function(err) {
  if (err) {
    console.error(err);
    return;
  }
  Quagga.start();
});

Error Handling:

The callback receives an err parameter if initialization fails. Common causes:

Always check for errors before calling start():

Target Element:

If no target is specified, Quagga looks for an element matching the CSS selector #interactive.viewport (for backwards compatibility).

Quagga.start()

Starts the video stream and begins locating and decoding barcodes.

Parameters: None

Returns: void

Example:

Quagga.init(config, function(err) {
  if (!err) {
    Quagga.start();
  }
});

Prerequisites:

Note: Call this in the init() callback after checking for errors.

Quagga.stop()

Stops the decoder from processing images and disconnects the camera if one was requested.

Parameters: None

Returns: Promise<void> - Resolves when cleanup is complete

Example:

// Stop scanning
await Quagga.stop();
console.log("Scanner stopped");

// Or with .then()
Quagga.stop().then(() => {
  console.log("Scanner stopped");
});

Behavior:

Quagga.pause()

Pauses frame processing without stopping the camera or releasing resources.

Parameters: None

Returns: void

Example:

// Pause scanning temporarily
Quagga.pause();

// Later, resume scanning
Quagga.start();

Behavior:

Use Cases:

Difference from stop():

Aspect pause() stop()
Frame processing Stops Stops
Camera stream Continues Disconnects
Resources Retained Released
Resume with start() init() + start()

Note: Since pause() keeps the camera running, the user’s camera indicator light will remain on. If you want to fully release the camera, use stop() instead.

Quagga.onDetected(callback)

Registers a callback that is triggered when a barcode is successfully located and decoded.

Parameters:

Returns: void

Example:

Quagga.onDetected(function(result) {
  const code = result.codeResult.code;
  const format = result.codeResult.format;

  console.log(`Detected ${format} barcode: ${code}`);

  // Process the barcode
  processBarcode(code);
});

Multiple Handlers:

You can register multiple handlers - all will be called:

Quagga.onDetected(handler1);
Quagga.onDetected(handler2);  // Both execute on detection

Quagga.onProcessed(callback)

Registers a callback that is called for each processed frame, regardless of detection success.

Parameters:

Returns: void

Example:

Quagga.onProcessed(function(result) {
  const drawingCtx = Quagga.canvas.ctx.overlay;
  const drawingCanvas = Quagga.canvas.dom.overlay;

  if (result) {
    // Draw boxes and lines for visualization
    if (result.boxes) {
      drawingCtx.clearRect(0, 0,
        drawingCanvas.width, drawingCanvas.height);

      result.boxes.forEach(function(box) {
        Quagga.ImageDebug.drawPath(box, {x: 0, y: 1},
          drawingCtx, {color: "blue", lineWidth: 2});
      });
    }

    if (result.box) {
      Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1},
        drawingCtx, {color: "green", lineWidth: 2});
    }

    if (result.codeResult && result.codeResult.code) {
      // Successfully decoded
      console.log("Code detected:", result.codeResult.code);
    }
  }
});

Use Cases:

Quagga.drawScannerArea()

Manually draws the scanner area overlay on the overlay canvas using the configured inputStream.area.

Parameters: None (uses the area configuration from Quagga.init())

Returns: void

Behavior:

Example:

// Configure area during init
Quagga.init({
  inputStream: {
    area: {
      top: "30%",
      right: "10%",
      bottom: "30%",
      left: "10%",
      borderColor: "#0F0",
      borderWidth: 2,
      backgroundColor: "rgba(255,0,0,0.15)"
    }
  },
  locate: false
});

// Later, manually redraw if you've cleared the overlay
Quagga.drawScannerArea();

Quagga.offDetected(handler)

Removes a previously registered onDetected handler.

Parameters:

Returns: void

Example:

function myHandler(result) {
  console.log(result.codeResult.code);
}

Quagga.onDetected(myHandler);

// Later: remove specific handler
Quagga.offDetected(myHandler);

// Or remove all handlers
Quagga.offDetected();

Quagga.offProcessed(handler)

Removes a previously registered onProcessed handler.

Parameters:

Returns: void

Example:

function processHandler(result) {
  // Process frame
}

Quagga.onProcessed(processHandler);

// Remove specific handler
Quagga.offProcessed(processHandler);

// Or remove all handlers
Quagga.offProcessed();

Quagga.decodeSingle(config, callback)

Decodes a single image without using getUserMedia. Useful for processing uploaded images or static images.

Parameters:

Returns: void

Important - Default Scaling: decodeSingle has a built-in default of inputStream.size: 800. This means images are automatically scaled to 800px on their longest side (both larger images scaled down AND smaller images scaled up). The result’s box, boxes, and line coordinates are returned in this scaled coordinate space, not the original image dimensions. To use the original image dimensions without scaling, set inputStream.size to 0.

Example:

Quagga.decodeSingle({
  src: '/images/barcode.jpg',  // Or data URL
  decoder: {
    readers: ["code_128_reader", "ean_reader"]
  },
  locate: true  // Try to locate barcode in image
  // Note: inputStream.size defaults to 800; images are scaled to 800px (up or down)
}, function(result) {
  if (result && result.codeResult) {
    console.log("Detected:", result.codeResult.code);
    console.log("Format:", result.codeResult.format);
  } else {
    console.log("No barcode detected");
  }
});

Using Data URLs:

// From file input
document.querySelector('#file-input').addEventListener('change', function(e) {
  const file = e.target.files[0];
  const reader = new FileReader();

  reader.onload = function(event) {
    Quagga.decodeSingle({
      src: event.target.result,  // Data URL
      decoder: {
        readers: ["code_128_reader"]
      }
      // Default size: 800 applies - image scaled if larger
    }, function(result) {
      if (result && result.codeResult) {
        alert("Barcode: " + result.codeResult.code);
      }
    });
  };

  reader.readAsDataURL(file);
});

Node.js Usage:

const Quagga = require('@ericblade/quagga2').default;

Quagga.decodeSingle({
  src: "./barcode.jpg",
  inputStream: {
    size: 800  // This is actually the default; shown explicitly here
  },
  decoder: {
    readers: ["code_128_reader"]
  }
}, function(result) {
  if (result && result.codeResult) {
    console.log("Code:", result.codeResult.code);
  }
});

Result Object

The result object passed to onDetected, onProcessed, and decodeSingle callbacks contains detailed information about the detection and decoding process.

Complete Result Structure

{
  codeResult: {
    code: "FANAVF1461710",       // The decoded barcode string
    format: "code_128",           // Barcode format
    start: 355,                   // Start position
    end: 26,                      // End position
    codeset: 100,                 // Code 128 specific
    startInfo: {
      error: 1.0,
      code: 104,
      start: 21,
      end: 41
    },
    decodedCodes: [               // Individual code segments
      { code: 104, start: 21, end: 41 },
      // ... more segments
      { error: 0.88, code: 106, start: 328, end: 350 }
    ],
    endInfo: {
      error: 0.88,
      code: 106,
      start: 328,
      end: 350
    },
    direction: -1                 // Scan direction
  },
  line: [                         // Scan line coordinates
    { x: 25.97, y: 360.56 },
    { x: 401.92, y: 70.88 }
  ],
  angle: -0.657,                  // Rotation angle in radians
  pattern: [0, 0, 1, 1, ...],     // Bar pattern (0=space, 1=bar)
  box: [                          // Primary bounding box (4 corners)
    [77.41, 410.93],              // Top-left
    [0.05, 310.54],               // Top-right
    [360.16, 33.06],              // Bottom-right
    [437.51, 133.45]              // Bottom-left
  ],
  boxes: [                        // All detected boxes
    [/* box 1 */],
    [/* box 2 */],
    // ...
  ]
}

Result Properties

Property Type Description
codeResult Object Decoded barcode information (may be undefined if detection failed)
codeResult.code String The decoded barcode value
codeResult.format String Barcode format (e.g., “code_128”, “ean_13”)
codeResult.start Number Start position in pattern
codeResult.end Number End position in pattern
codeResult.direction Number Scan direction (1 or -1)
codeResult.supplement Object (Optional) Supplement barcode data for EAN-13/UPC-A with EAN-2 or EAN-5 extensions
codeResult.supplement.code String The decoded supplement value (2 or 5 digits)
codeResult.supplement.format String Supplement format: “ean_2” or “ean_5”
line Array Two points defining the scan line
angle Number Barcode rotation angle (radians)
pattern Array Binary pattern (0=space, 1=bar)
box Array Bounding box coordinates (4 corner points)
boxes Array All candidate boxes found during localization. When locate is false, this contains a single box representing the actual adjusted scanning area (after patch alignment)

Note: boxes with locate: false

When locate is false and an inputStream.area is configured, result.boxes contains a single box representing the actual scanning area dimensions. This box reflects the adjusted dimensions after patch alignment (which can differ slightly from the percentage-based area due to rounding to patch size multiples). Use these coordinates if you need to know the exact scanning rectangle:

Quagga.onProcessed(function(result) {
  if (result.boxes && result.boxes.length > 0) {
    // When locate=false, boxes[0] is the actual scanning area
    const scanArea = result.boxes[0];
    console.log("Scanning area corners:", scanArea);
  }
});

Important: Coordinate System

The box, boxes, and line coordinates are returned in processed canvas coordinates, not original image/video coordinates. If you’re using inputStream.size to scale the processing resolution (e.g., for performance), you’ll need to scale these coordinates to match your original video/image dimensions.

// Scale coordinates to original video size
const scaleX = video.videoWidth / Quagga.canvas.dom.image.width;
const scaleY = video.videoHeight / Quagga.canvas.dom.image.height;
const scaledBox = result.box.map(p => [p[0] * scaleX, p[1] * scaleY]);

See Working with Box Coordinates for complete examples.

Checking for Successful Detection

Quagga.onDetected(function(result) {
  // Always check if codeResult exists
  if (result && result.codeResult && result.codeResult.code) {
    console.log("Detected:", result.codeResult.code);
  }
});

Using Multiple Barcode Detection

When decoder.multiple is true, results are returned as an array:

Quagga.init({
  decoder: {
    readers: ["code_128_reader"],
    multiple: true
  }
});

Quagga.onDetected(function(result) {
  // result is an array of result objects
  result.forEach(function(item) {
    if (item.codeResult) {
      console.log("Code:", item.codeResult.code);
      console.log("Box:", item.box);
    }
  });
});

Canvas Access

Quagga automatically creates and manages two canvas elements for visualization. These are positioned over the video/image stream and sized to match the processing dimensions.

Canvas Structure

Quagga.canvas = {
  dom: {
    image: HTMLCanvasElement,           // Canvas for processed image data
    overlay: HTMLCanvasElement | null   // Transparent canvas for drawing overlays
  },
  ctx: {
    image: CanvasRenderingContext2D,           // Context for image canvas
    overlay: CanvasRenderingContext2D | null   // Context for overlay canvas
  }
};

Note: The overlay canvas can be null if canvas.createOverlay is set to false in the configuration. See Canvas Configuration for details.

Overlay Canvas

The overlay canvas (Quagga.canvas.dom.overlay) is a transparent canvas element positioned over the video stream. It’s automatically created when Quagga initializes (unless canvas.createOverlay is false) and is designed for drawing bounding boxes, scan lines, and other visual feedback.

Key characteristics:

Accessing the overlay:

const overlay = Quagga.canvas.dom.overlay;
const overlayCtx = Quagga.canvas.ctx.overlay;

// Always check if overlay exists before using
if (overlayCtx && overlay) {
  // Clear overlay
  overlayCtx.clearRect(0, 0, overlay.width, overlay.height);

  // Draw custom shapes
  overlayCtx.strokeStyle = "red";
  overlayCtx.lineWidth = 3;
  overlayCtx.strokeRect(10, 10, 100, 100);
}

Image Canvas

The image canvas (Quagga.canvas.dom.image) contains the processed grayscale image data used for barcode detection. This is primarily for internal use and debugging.

Key characteristics:

When to Use Each Canvas

Use Case Canvas to Use
Drawing bounding boxes overlay
Highlighting detected barcodes overlay
Custom scan line visualization overlay
Debugging image processing image
Checking processed resolution Either (they have same dimensions)

Important: Coordinate System

When drawing on the overlay canvas, use result.box and result.boxes coordinates directly - no scaling is needed. These coordinates are already in the overlay canvas’s coordinate space.

Quagga.onProcessed(function(result) {
  const ctx = Quagga.canvas.ctx.overlay;
  const canvas = Quagga.canvas.dom.overlay;

  // Clear previous drawings
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // Draw box directly - coordinates already match the overlay canvas
  if (result && result.box) {
    Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, ctx, {
      color: "green", lineWidth: 2
    });
  }
});

Note: Scaling is only needed when drawing on a different canvas (like a custom overlay on the original video element). See Working with Box Coordinates for details.

CSS Styling

The overlay canvas can be styled with CSS for positioning:

/* Default positioning (handled automatically by Quagga) */
canvas.drawingBuffer {
  position: absolute;
  top: 0;
  left: 0;
}

/* Ensure proper stacking */
#scanner-container {
  position: relative;
}

ImageDebug Helper

Quagga provides a helper for drawing debug visualizations:

// Draw a path (array of points)
Quagga.ImageDebug.drawPath(points, offset, ctx, options);

// Example
Quagga.ImageDebug.drawPath(
  result.box,
  { x: 0, y: 1 },
  overlayCtx,
  { color: "green", lineWidth: 2 }
);

Complete Example

// Initialize
Quagga.init({
  inputStream: {
    type: "LiveStream",
    target: document.querySelector('#scanner'),
    constraints: {
      width: 640,
      height: 480,
      facingMode: "environment"
    }
  },
  decoder: {
    readers: ["code_128_reader", "ean_reader"]
  }
}, function(err) {
  if (err) {
    console.error(err);
    return;
  }

  // Start scanning
  Quagga.start();
});

// Handle detections
Quagga.onDetected(function(result) {
  console.log("Barcode detected:", result.codeResult.code);

  // Stop after first detection
  Quagga.stop();

  // Cleanup
  Quagga.offDetected();
  Quagga.offProcessed();
});

// Visualize processing
Quagga.onProcessed(function(result) {
  const ctx = Quagga.canvas.ctx.overlay;
  const canvas = Quagga.canvas.dom.overlay;

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  if (result && result.box) {
    Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, ctx, {
      color: "green",
      lineWidth: 2
    });
  }
});

// Stop button
document.querySelector('#stop').addEventListener('click', function() {
  Quagga.stop();
  Quagga.offDetected();
  Quagga.offProcessed();
});

← Back to Reference