Barcode Detector API Demo — Free window.BarcodeDetector Scanner

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

Share & Support

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.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain why detector.detect() can accept a canvas, video, or image element interchangeably as an ImageBitmapSource, and why the hand-drawn QR-style pattern is expected not to decode even though it visually resembles a real code. It's also useful for reasoning about the permission design — ask why making the canvas path the primary, no-permission demo is a better pattern for a preview-embedded snippet than leading with a camera request that's likely to fail in a sandboxed iframe. For extensions, ask it to draw a genuinely valid QR code using a small encoding algorithm so the canvas demo can produce a real positive detection, add bounding-box overlay drawing using the cornerPoints of a detected code, or add a formats dropdown so the user can restrict detection to a single symbology. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "barcode detector demo" in plain HTML, CSS, and JavaScript using the real browser window.BarcodeDetector API — no libraries.

Requirements:
- Draw a QR-code-shaped pattern onto a <canvas> at page load: three finder squares (nested black/white/black concentric squares) in the standard top-left, top-right, and bottom-left corner positions, plus a pseudo-random module grid filling the rest, generated with a seeded PRNG so the pattern is deterministic across reloads. Clearly note in the UI that this is a hand-drawn visual approximation, not necessarily a validly encoded symbol.
- CRITICAL primary path: a "Detect on canvas" button that feature-detects typeof window.BarcodeDetector === 'function', and if supported, constructs new window.BarcodeDetector({ formats: [...] }) and calls await detector.detect(canvasElement) directly against the canvas — a real API call requiring no camera permission at all. Display the format and rawValue of any detected code; if detect() runs successfully but returns zero results (which is an expected, honest outcome if the drawn pattern isn't validly encoded data), say so explicitly rather than implying failure or faking a match.
- A secondary "Use camera instead" button that requests navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }), and on success streams into a <video> element and runs the same BarcodeDetector against video frames in a requestAnimationFrame loop, showing live detections.
- Wrap the camera path in a try/catch covering both missing getUserMedia support and a missing/unsupported BarcodeDetector, and on any failure (denied permission, no camera device, or a blocked Permissions-Policy — expected and common when this runs inside a sandboxed preview iframe) show a status message naming the specific failure and explicitly pointing the user back to the no-permission canvas detection path above.
- Stop all camera MediaStream tracks when the page unloads or when the user switches away from camera mode, so no camera indicator is left active.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

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

Inventory/warehouse tools
Prototype scanning UI without needing a camera to test.
Ticket/pass check-in apps
Pair with a QR code generator.
Retail POS prototypes
Detect EAN-13 product barcodes from a live camera.
Onboarding/demo pages
Show a real browser API working in a sandboxed preview.
Developer education
Teach the BarcodeDetector API without a camera requirement.
QA/testing harnesses
Feed known canvas patterns to test detection logic.

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.