Design a Mobile QR Scanner: Camera, Detection, and Action

Updated · techinterview.org

QR scanners are a deceptively rich mobile system design problem. Camera capture in real time, edge case handling (low light, glare, partial occlusion), security screening for malicious URLs, and the lightweight UX patterns expected from “open camera, point, done.”

Functional requirements

  • Detect a QR code in the camera feed in real time — the detector runs per frame on a background queue so the preview never stutters
  • Decode the contents into a typed payload (URL, vCard, Wi-Fi, plain text) rather than a raw string
  • Take an appropriate action: open URL, add contact, copy text, etc.
  • Security check: warn on suspicious URLs before any navigation happens
  • Multi-code support: detect and let user pick if multiple visible

Architecture

Three steps: capture, detect, act.

Camera capture

iOS: AVCaptureSession at 30fps. Each frame is a CVPixelBuffer.

Android: CameraX library, simpler API.

Use the back camera, autofocus on the center, set white balance auto. Resolution: 720p or 1080p — higher does not improve detection meaningfully but costs battery.

Detection

Native APIs handle this:

  • iOS: AVMetadataMachineReadableCodeObject — built into AVFoundation, delivered on the metadata output delegate with the code already decoded
  • Android: ML Kit Barcode Scanning — runs on-device, no network needed, and lets you restrict the formats you accept up front

Both run on every camera frame. Detection latency <100ms. Returns the decoded payload + bounding box in image coordinates.

Decoding edge cases

  • Low light: flash toggle. Detect the dark scene from the frame’s average luminance and surface the torch button automatically instead of making the user hunt for it.
  • Glare: ask user to adjust angle. Glare off a laminated card or a code shown on a screen reflects the light source as a bright saturated blob over the pattern; a prompt to tilt the phone a few degrees usually clears it.
  • Partially occluded: QR has error correction; works with up to 30% damage. That comes from built-in Reed–Solomon codewords at four levels (L/M/Q/H), so a code with a logo in the middle or a torn corner still decodes at the higher levels.
  • Multiple codes in frame: highlight all, let user tap to pick. Draw a box around each and wait for the tap — auto-picking the largest or first code is a common wrong answer interviewers will push back on.
  • Wrong code type detected (barcode vs QR): support multiple types. Users point the camera at product barcodes, Data Matrix, and Aztec codes too, so configure the detector to accept the formats your product needs and ignore the rest.

Action handling

QR payloads can be:

  • URL → open in browser (or app deep link if matches a known scheme). Check the scheme against your registered deep links first so an in-app link opens the app, then send everything else to the default browser after the security check below.
  • vCard → add contact. Parse the fields and show a contact preview before writing to the address book, since the code can carry arbitrary names, numbers, and notes.
  • Wi-Fi credentials → join network. The WIFI: payload holds the SSID, auth type, and password; prompt before joining because a malicious code can silently connect the phone to an attacker’s access point.
  • SMS / mailto → compose message. Pre-fill the recipient and body but never send automatically — a code that targets a premium SMS number is a classic abuse.
  • Plain text → copy to clipboard, and show what was copied so the user can confirm it before pasting.
  • App-specific (e.g., shared content) → open in your app, validating the payload against your own format before acting on it.

Security: malicious URLs

QR codes are a common phishing vector. Mitigations:

  • Show the URL prominently before opening. Render the full URL rather than a truncated one and make the host segment visually distinct, so the domain is the first thing the user reads.
  • Warn on URL shorteners (bit.ly, t.co). Shorteners hide the real destination, so resolve them ahead of time or warn the user that the final target is unknown before following.
  • Check against known-bad-URL lists (Safe Browsing API). Do the lookup with a hashed URL prefix so the full address never leaves the device, and block or warn on any match.
  • Warn on punycode / IDN homograph URLs (e.g., аpple.com using Cyrillic а). Detect mixed scripts in the hostname and display the raw punycode form (xn--…) so a lookalike domain can’t pass as the real one.

UX patterns

  • Open camera with QR scanner mode highlighted so the user lands in scan mode without an extra tap.
  • Reticle overlay to suggest aiming, dimming the area outside it to draw the code toward the center where autofocus is sharpest.
  • Haptic feedback when a code is detected, giving instant confirmation before the modal even renders.
  • Modal with decoded content + action button, showing the payload and a single clear primary action rather than firing the action automatically.

Battery

  • Detection only when the camera is open — tear down the capture session as soon as the scanner view disappears.
  • Stop detection after the first successful scan; the user takes action while the pipeline sits idle instead of decoding every frame.
  • Lower frame rate (15fps) is sufficient — QR decoding does not need 30fps, and halving the rate roughly halves the capture cost.

iOS Live Text and Camera Continuity

iOS automatically detects QR codes in the system Camera app since iOS 15. Apps can use VisionKit’s DataScannerViewController for the same UX in their own apps.

Frequently Asked Questions

Why do some QR scanners detect codes faster than others?

Differences in frame rate, ROI cropping, and image preprocessing. Native APIs are usually faster than custom solutions.

How does Apple Pay use QR codes?

For merchant present codes: user scans, app produces a payment from the encoded merchant info. Different from displaying a code for the merchant to scan.

Should I implement QR codes manually for special cases?

No. Native APIs are mature. Custom decoders are slower and brittle to edge cases.

newsletter

What's actually being asked right now

Interview patterns & comp trends, straight to your inbox.

No spam. Unsubscribe anytime.

newsletter

What's actually being asked right now

Interview patterns & comp trends, straight to your inbox.

No spam. Unsubscribe anytime.

1972 Soviet postage stamp commemorating the Mars 2 probe

worth a read

Mars For The Rest of Us — a weekly-or-more deep dive on the technical side of Mars exploration: rocket propulsion, microbiology, mission architecture, and everything in between. Written by Maciej Ceglowski.

Read it on Substack
Scroll to Top