# How QR scanning works in a browser

> Browser QR scanning combines getUserMedia camera access with a decoder, the native BarcodeDetector API in Chromium browsers, or a WebAssembly decoder such as zxing everywhere else. Frames are processed in the page, so a well-built scanner never uploads your camera image — decoding happens entirely on your device.

Source: https://useqr.app/docs/scanning/qr-scanning-in-a-browser · Last reviewed 2026-08-21 · UseQR is free forever, MIT licensed, no signup.

---

## Two building blocks

Every web-based QR scanner is the same sandwich:

1. **Getting pixels** — either `getUserMedia` for a live camera stream, or a file input
   / drag-and-drop for images. Camera access requires HTTPS and a permission grant,
   which has [its own page](/docs/scanning/camera-permissions-and-qr-scanning).
2. **Decoding pixels** — turning a frame into text. This is where implementations
   differ, and where the privacy question lives.

## Decoder option 1: the BarcodeDetector API

Chromium-based browsers ship a native decoder behind a small API:

```js
if ('BarcodeDetector' in window) {
  const detector = new BarcodeDetector({ formats: ['qr_code'] });
  const results = await detector.detect(imageBitmap);
  // results[0].rawValue is the decoded text
}
```

It is fast — the decoding is compiled browser code, not JavaScript — and handles
detection inside larger images. The catch is coverage: **Chrome and Edge support it;
Firefox does not, and Safari support has been inconsistent**. No production scanner can
rely on it alone, which is why the feature-detect in the snippet matters.

## Decoder option 2: WebAssembly libraries

Where `BarcodeDetector` is missing, scanners bundle a decoder compiled to WebAssembly —
typically a build of [ZXing](/glossary/zxing) (zxing-wasm) or another C++ decoder.
The page draws video frames to a canvas, hands the pixel buffer to the wasm module, and
gets text back, usually well under 50 ms per frame on a laptop. Same result as the
native API, at the cost of shipping a few hundred kilobytes of decoder.

A well-built scanner does both: native API when present, wasm fallback otherwise. If you
want to build one, the working code is in
[reading QR codes from a webcam in the browser](/docs/developers/read-qr-codes-from-a-webcam-in-the-browser).

## The privacy question: where do the frames go?

Nothing in the pipeline above requires a server. Both decoder options run **on your
device, inside the page** — which means a browser scanner can honestly promise that your
camera frames and uploaded images are never transmitted. Our [scanner](/scan) works this
way: the decode happens client-side and the image goes nowhere.

But "can" is not "does". Some scanner sites upload every frame or image to a backend and
return the result — technically identical from the outside, completely different in what
the operator sees. Two checks anyone can run:

- **Open the network tab** in developer tools while scanning. A client-side scanner
  sends no image data — you will see the page load and then silence.
- **Cut the network** after the page loads. A client-side decoder keeps working.

The same distinction — local versus server processing — applies to generation too, and
matters for the same reason; the argument is laid out in
[client-side vs server-side QR generation](/docs/security/client-side-vs-server-side-qr-generation).

## What a browser scanner should show you

The decoded **text**, before anything opens. Live camera apps race you to the
destination; a scanner that displays the raw payload first gives you the one beat needed
to [read the domain before visiting it](/docs/security/how-to-check-a-qr-code-before-opening).
For anything security-sensitive, that pause is the point.

## FAQ

### How does a website scan QR codes without an app?
It requests camera access through the browser's getUserMedia API and decodes the video
frames with either the native BarcodeDetector API (Chromium) or a WebAssembly decoder
bundled with the page. No installation is involved.

### Is it safe to use an online QR scanner?
Prefer one that decodes client-side, meaning frames are processed in the page and never
uploaded. You can verify this yourself: watch the browser's network tab while scanning —
a client-side scanner transmits no image data.

### What is the BarcodeDetector API?
A native browser API that detects and decodes barcodes, including QR codes, from images
and video frames. Chrome and Edge support it; Firefox does not, so real-world scanners
ship a WebAssembly fallback decoder.

### Which browsers can scan QR codes from a webcam?
Any modern browser on a secure (HTTPS) page — Chrome, Edge, Firefox and Safari all
support camera capture. The page supplies the decoder, so support depends on the
scanner site handling both the native API and wasm paths.

## Try it

- https://useqr.app/scan
- https://useqr.app/validate
