QR Code Scanner

Scan from camera, upload an image, or paste from clipboard. WiFi & vCard results are parsed automatically.

Drop a QR code image here

or click to browse

You can also Ctrl+V / ⌘V to paste a copied image

Result

Scan or upload a QR code to see results

Runs entirely in your browser. No uploads. Your files stay private.

How to Scan and Decode a QR Code

QR Scanner decodes the data inside a QR code image without sending anything to a server. The decoding work is done by the jsqr library, a pure JavaScript port of the ZXing reader that walks the pixel grid, locates the three position markers in the corners, samples the data modules, and reconstructs the original payload using Reed-Solomon error correction. Everything runs on your device's CPU inside the browser tab.
There are three ways to feed a code into the scanner. The camera path uses MediaDevices.getUserMedia with facingMode: 'environment' so phones default to the rear lens; the live video frames are drawn onto a hidden Canvas API element each animation frame, then the raw ImageData buffer is handed to jsqr. The upload path uses FileReader.readAsDataURL to load JPG, PNG, or WebP files into an Image, paint it onto the canvas, and decode the same way. The clipboard path listens for the document paste event and pulls image blobs out of ClipboardEvent.clipboardData.
Camera scanning needs explicit user permission. The first time you click Start Camera, the browser shows a native permission prompt; if you deny it, the only recovery is to reopen site permissions in your browser settings. The page must also be served over HTTPS for getUserMedia to be exposed at all — that is a hard requirement of the modern web platform, not a tool choice.
Decoding speed is bounded by image size and lighting. jsqr inspects every pixel, so a 4K phone screenshot takes longer than a 720p video frame. Poor focus, low light, glare, or a tilted angle of more than about 30 degrees cause the position markers to fall below the detection threshold and decoding silently fails. Steady the phone, fill more of the frame with the code, and avoid reflective laminates.
Payload parsing happens after decoding. The tool inspects the prefix of the decoded string and routes it to a specialised renderer: http:// or https:// becomes a URL with an Open button, mailto:, tel:, and sms: are stripped to their raw value, WIFI:T:WPA;S:Network;P:pass;; is split into SSID, password, and security fields, and a BEGIN:VCARD block is parsed into name, phone, email, organisation, and URL plus a Save Contact button that builds a .vcf Blob via URL.createObjectURL. geo: links and plain text fall through as-is.
Mobile and desktop behaviour diverges in two places. Phones expose a rear camera with autofocus and often a torch — when track.getCapabilities() reports torch: true, a flashlight button appears and toggles the LED through track.applyConstraints. Laptops typically only have a front-facing camera with no torch, so the rear-camera request silently falls back to facingMode-agnostic capture and the torch button never appears.
Nothing leaves your tab. Scan history is held in component state, exporting it produces a CSV via a client-side Blob, and stopping the camera releases every MediaStreamTrack so the recording indicator in your OS disappears immediately. Closing the tab discards the history; this tool has no backend to persist it to.

Common Use Cases

01

Verify a printed URL before visiting

Scan a QR code from a poster, receipt, or restaurant menu and read the destination URL in plain text before deciding whether to open it.

02

Recover a Wi-Fi password

Point the camera at a router label or guest-network card; the WIFI: payload is parsed into SSID, password, and security type that you can copy individually.

03

Save a business card contact

Decode a vCard QR from a name badge or signature and download a .vcf file that imports cleanly into iOS Contacts, Google Contacts, or Outlook.

04

Test QR codes during development

Drop generated PNGs straight from your build folder to confirm the encoded payload matches expectations before printing or shipping.

Frequently Asked Questions

Camera access requires HTTPS and explicit permission. If the site is loaded over plain http:// the MediaDevices API is not exposed at all. If it is over HTTPS, check that you did not previously deny camera permission for the site — browsers remember that decision and silently reject future requests until you reset it in site settings.
No. Decoding runs entirely client-side via the jsqr library on your CPU. Camera frames are read from a local MediaStream into a hidden canvas, jsqr reads the ImageData, and the decoded string stays in component state. There is no upload endpoint, no analytics on the payload, and the scan history CSV is built with a client-side Blob.
The tool detects URL (http/https), Email (mailto:), Phone (tel:), SMS (sms:), Wi-Fi (WIFI:T:...;S:...;P:...;;), and vCard (BEGIN:VCARD ... END:VCARD) prefixes and renders each with a tailored UI. Anything that does not match a known prefix — including geo: links, calendar events, and plain text — is shown as raw text with a copy button.
jsqr needs to find the three square position markers in the corners of the code with enough contrast and not too steep an angle. Glare on glossy laminates, focus hunting in macro mode, low light, motion blur, and tilts beyond roughly 30 degrees all push the markers below threshold. Hold steady, fill more of the frame, and avoid reflections.
Yes, when the active video track reports torch support via MediaStreamTrack.getCapabilities(). On most modern Android phones the rear camera exposes a torch capability and a Lightbulb button appears in the scanner overlay. iOS Safari historically did not expose this capability; if no button shows, your browser or device does not support programmatic torch control.
The tool requests facingMode: 'environment' first, but if the device only has one camera or the browser cannot honour the constraint it falls back to a generic video request. Most laptops only have a front camera, so the fallback path is the only option there. On a phone, check that another app is not holding the rear camera.
There is no enforced size limit, but jsqr runs in a single thread and inspects every pixel, so a 50 megapixel photo will lock up the tab for several seconds. For best speed, crop to roughly the QR code area before uploading, or take the photo at a lower resolution. 720p to 1080p is plenty for any standard QR code.
Yes. The tool listens for the document-level paste event and inspects ClipboardEvent.clipboardData.items for image MIME types. Press Ctrl+V on Windows or Cmd+V on macOS after copying a screenshot (Print Screen, Snipping Tool, macOS Cmd+Shift+Ctrl+4) and the file is fed straight into jsqr without ever touching the file system.
Up to a point. QR codes carry Reed-Solomon error correction with up to 30 percent recovery at level H, and jsqr applies it automatically. Small smudges, glare spots, or a sticker covering one quiet zone are usually fine; a missing position marker (any of the three corner squares) is fatal because the code geometry cannot be located.
It is discarded. The history is held in React state and never written to localStorage, IndexedDB, or any server. If you need a record, use the download icon next to Recent Scans to export a CSV with type, data, and ISO timestamp columns before closing the tab.

Advertisement