webdevpuneet.com

Barcode Detector API Demo — Free window.BarcodeDetector Scanner

Barcode Detector API Demo · Tools · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<section class="bcd-wrap">
  <span class="bcd-tag">window.barcodedetector</span>
  <h1>Barcode / QR detection</h1>
  <p id="bcdStatus">Click "Detect on canvas" to run the real BarcodeDetector API against a generated code below — no camera needed.</p>

  <div class="bcd-stage">
    <canvas class="bcd-canvas" id="bcdCanvas" width="360" height="220"></canvas>
    <video class="bcd-video" id="bcdVideo" width="360" height="220" autoplay muted playsinline hidden></video>
  </div>

  <div class="bcd-actions">
    <button class="bcd-btn primary" id="bcdCanvasBtn" type="button">Detect on canvas</button>
    <button class="bcd-btn" id="bcdCameraBtn" type="button">Use camera instead</button>
  </div>

  <div class="bcd-result" id="bcdResult" hidden>
    <span class="bcd-result-label">Detected</span>
    <div class="bcd-result-row"><span>Format</span><strong id="bcdFormat">—</strong></div>
    <div class="bcd-result-row"><span>Raw value</span><strong id="bcdValue">—</strong></div>
  </div>

  <p class="bcd-note">Camera mode requires getUserMedia permission and a Chromium-based browser — both frequently unavailable inside a sandboxed preview, so the canvas path above is the reliable way to see the API work.</p>
</section>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Real BarcodeDetector.detect()
Genuine API call against real canvas or video pixels.
No-permission primary path
Canvas detection needs zero camera access.
Deterministic sample pattern
Seeded PRNG draws a repeatable QR-style grid.
Honest no-match reporting
Explains why an unencoded pattern won't decode.
Optional live camera scan
getUserMedia-backed scanning as a secondary mode.
Feature-detected fallback
Clear messaging when BarcodeDetector is unsupported.
Graceful camera failure
try/catch names the exact getUserMedia rejection.
Clean stream teardown
Camera tracks stop on unload.

About this UI Snippet

Barcode Detector API Demo — Detecting Codes Without Needing Camera Access

Screenshot of the Barcode Detector API Demo snippet rendered live

The BarcodeDetector API is genuinely useful but almost every demo of it online requires camera permission to show anything at all — which fails silently in a huge number of contexts (sandboxed iframes, denied prompts, no camera device). This snippet flips the primary path: it runs BarcodeDetector.detect() against a canvas image drawn at runtime, so the real API call is exercised and demonstrable with zero permissions required, then offers live camera scanning as a clearly secondary option.

The real call: BarcodeDetector.detect()

new window.BarcodeDetector({ formats: ['qr_code', 'ean_13', 'code_128'] }) constructs a detector scoped to specific symbologies. Its detect() method accepts an ImageBitmapSource — a <canvas>, <video>, or <img> element — and returns a promise resolving to an array of { format, rawValue, cornerPoints, boundingBox } objects for every code it decodes. The "Detect on canvas" button passes the page's own <canvas> directly, so this is a genuine call against real pixel data, not a mocked result.

Why the canvas pattern may not decode — and that's honest, not broken

drawSampleCode() paints a QR-style grid: three finder squares in the standard corner positions plus a pseudo-random module field, generated with a seeded PRNG so it's deterministic. It visually resembles a QR code's structure but is not validly encoded data (it skips error-correction, format/version info, and real payload encoding) — so a real decoder correctly reports zero matches on it. The status message says exactly that rather than pretending a false positive, which matters: the point of this snippet is showing detect() actually run against real pixels, not showing a canned "success."

Camera mode: secondary, and honestly gated

useCamera() requests getUserMedia({ video: { facingMode: 'environment' } }), wraps it in try/catch, and on any rejection — denied permission, no device, or (very common for a sandboxed preview <iframe>) a Permissions-Policy that never grants camera to the frame — explains the specific failure and points back at the canvas path, which needs no camera at all. On success, a requestAnimationFrame loop repeatedly calls detect(video) against the live stream. Pair this with a QR code generator for a complete "generate and scan" pairing.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA QR-style pattern draws to canvas immediately.
  2. 2
    Click "Detect on canvas"The real BarcodeDetector.detect() runs against those pixels.
  3. 3
    Read the resultA match shows format and raw value; no match is explained honestly.
  4. 4
    Click "Use camera instead"Optionally request live camera scanning.
  5. 5
    Point at a real codeA supporting browser with camera access decodes it live.
  6. 6
    No camera available?The status message explains why and points back at canvas mode.

Real-world uses

Common Use Cases

Warehouse scanning prototypes
Prototype a scanning interface for inventory tools without needing a camera first, running a real BarcodeDetector.detect() against a canvas-drawn code.
Ticket check-in apps
Pair with a QR code generator so passes can be created and then verified in the same demo environment.
Retail point-of-sale prototypes
Detect EAN-13 product barcodes from images, with an optional live camera mode and honest fallbacks when the API is unsupported.
API support demos
Show a real browser API working even inside sandboxed iframes or when camera permission is denied, using a seeded pattern for repeatable results.
Detector testing harnesses
Feed known canvas patterns to test detection logic, including a clear explanation when an unencoded pattern correctly fails to decode.
Related: Clipboard Paste Button
See the Clipboard Paste Button for a related buttons pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

The canvas draws a QR-style pattern -- three finder squares in the correct positions plus a pseudo-random module grid -- purely to visually resemble a QR code's structure. It is not validly encoded data (no real error correction, format info, or payload encoding), so a real decoder correctly reports zero matches. The point is that BarcodeDetector.detect() genuinely runs against real pixels either way; the status message says exactly what happened rather than faking a match.

It currently ships in Chromium-based browsers -- Chrome, Edge, and Opera -- and is not implemented in Firefox or Safari. The snippet feature-detects with typeof window.BarcodeDetector === 'function' and shows a clear message when it's missing, both for the canvas path and before requesting camera access.

Camera access via getUserMedia is frequently unavailable in the exact contexts this snippet is likely to be viewed in -- sandboxed preview iframes commonly block camera permission via Permissions-Policy, and even outside a sandbox users often deny the prompt. Making canvas detection the primary path means the real BarcodeDetector API is demonstrably exercised regardless of camera availability; camera mode is offered as a bonus for browsers and contexts where it works.

useCamera() wraps the getUserMedia call in a try/catch. Any rejection -- a denied permission prompt, no camera device, or a sandboxed iframe's Permissions-Policy blocking the camera feature entirely -- is caught and reported by name in the status message, which also points the user back to the no-permission canvas detection path instead of leaving the UI stuck on "Requesting camera access…".

Feature-detect window.BarcodeDetector once, create the detector instance in a ref or memoized value, and call detector.detect(canvasOrVideoElement) from a click handler or an animation-frame loop scoped to a mounted ref. For camera mode, request the stream in a handler triggered by user interaction, assign it to a video element's srcObject, and stop every track in a cleanup function on unmount or when switching away from camera mode.