diff --git a/static/index.html b/static/index.html
index 7eed1e0..574a532 100644
--- a/static/index.html
+++ b/static/index.html
@@ -2885,7 +2885,12 @@
if (!video) return;
// Create reader with 1D-only hints for fast, accurate scanning
- codeReader = new ZXing.BrowserMultiFormatReader(_barcodeHints(), _barcodeOptions());
+ // NOTE: BrowserMultiFormatReader constructor takes 0 args — hints and options
+ // must be set as instance properties for them to take effect.
+ codeReader = new ZXing.BrowserMultiFormatReader();
+ codeReader.reader.hints = _barcodeHints();
+ codeReader.timeBetweenScansMillis = 2000; // delayBetweenScanSuccess
+ codeReader._timeBetweenDecodingAttempts = 300; // delayBetweenScanAttempts
// Pick the rear-facing camera (environment-facing on phones)
let deviceId = null;
@@ -2927,8 +2932,13 @@
handleBarcode(val.trim());
}
} else if (err && scanningActive) {
- const msg = (err.message || err || '').toLowerCase();
- if (!msg.includes('multiformat') && !msg.includes('unable to detect')) {
+ // NotFoundException, ChecksumException, FormatException are normal
+ // "no barcode on this frame" results — silently continue scanning.
+ // We use instanceof because ZXing's minified exception classes all
+ // have message="undefined", making message-text filtering unreliable.
+ if (!(err instanceof ZXing.NotFoundException ||
+ err instanceof ZXing.ChecksumException ||
+ err instanceof ZXing.FormatException)) {
console.error('ZXing camera error:', err);
handleCameraError(new Error(err.message || err));
}