Skip to main content
RapidDev - Software Development Agency
App Featuresscanning-devices18 min read

How to Add a Barcode Scanner to Your App (Copy-Paste Prompts Included)

A barcode scanner needs three pieces: camera access, a decoding engine (html5-qrcode for web, ML Kit for native mobile), and a handler that does something useful with the result. With Lovable or V0 you can ship a working scanner in 3–6 hours for $0/month — the decoding libraries are free and run on-device. Costs only appear if you add a third-party product lookup API to identify unknown retail barcodes.

4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members

Feature spec

Intermediate

Category

scanning-devices

Build with AI

3–6 hours with Lovable or FlutterFlow

Custom build

3–5 days custom dev

Running cost

$0/mo (scanning only) · $25–50/mo at 10K users with Supabase Pro

Works on

WebMobile

Everything it takes to ship a Barcode Scanner — parts, prompts, and real costs.

TL;DR

A barcode scanner needs three pieces: camera access, a decoding engine (html5-qrcode for web, ML Kit for native mobile), and a handler that does something useful with the result. With Lovable or V0 you can ship a working scanner in 3–6 hours for $0/month — the decoding libraries are free and run on-device. Costs only appear if you add a third-party product lookup API to identify unknown retail barcodes.

What a Barcode Scanner Feature Actually Is

A barcode scanner turns your user's camera into an input device — point at a barcode or QR code, and the app reads the encoded value instantly. Inventory apps use it to pull up stock items, fitness apps to log food, retail apps to compare prices, event apps to check in guests. The scanning itself is a solved problem: free libraries decode EAN-13, UPC-A, Code 128, and QR formats in the browser without any server round-trip. The real product decisions are what happens after the scan — lookup, validation, history, and what to do when the camera can't read the code at all.

What users consider table stakes in 2026

  • Scan completes in under one second with a visible viewfinder overlay showing the alignment target
  • Haptic vibration or audible beep confirms a successful read before any screen transition
  • Continuous scanning mode — no tap required between codes, viewfinder stays open
  • Duplicate protection — holding the camera on the same code for 5 seconds doesn't create duplicate records
  • Torch (flashlight) toggle for scanning in low-light environments like warehouses
  • Manual entry fallback so users can type a barcode when a label is damaged or too small to scan

Anatomy of the Feature

Six components, four of which AI tools generate correctly on the first prompt. The camera access layer and barcode format configuration are where first builds actually fail.

Layers:UIDataBackendService

Camera access layer

UI

Requests camera permission via the browser's getUserMedia() API on web (html5-qrcode library) or uses native ML Kit BarcodeScanning on Android and AVFoundation VNDetectBarcodesRequest on iOS. Renders the live video stream in a canvas element or native SurfaceView with the viewfinder overlay composited on top.

Note: Requires HTTPS — camera access silently fails on http:// URLs and inside most preview iframes including Lovable and V0. Always test on the published URL.

Barcode detection engine

Backend

Reads frames from the video stream at approximately 10fps and decodes barcodes. Web standard: html5-qrcode v2 (wraps ZXing) handles QR plus all major retail formats. Native mobile: Google ML Kit BarcodeScanning runs on-device with hardware acceleration, producing results noticeably faster than the web counterpart. Detection loop fires the success callback on each decoded frame.

Note: Always configure an explicit format list — html5-qrcode defaults to QR-only. Pass [Html5QrcodeSupportedFormats.EAN_13, UPC_A, CODE_128, QR_CODE] to enable retail scanning.

Scan result handler

Backend

Receives the decoded string, deduplicates consecutive reads using a 500ms cooldown (store last value + timestamp, reject repeats within the window), validates the format, and routes the result — look up a product, check in a guest, add inventory. Emits a structured event containing barcode value, format string, and timestamp.

Note: This is business logic unique to your app. Be explicit in your prompt about what should happen after a successful scan — AI tools default to just displaying the value.

Viewfinder overlay

UI

SVG or Canvas overlay drawn on top of the camera preview showing a focus rectangle, animated scanning line, and current format label. Built with React or Flutter's CustomPainter. The overlay communicates to the user where to aim and signals when a scan is in progress.

Note: Keep the decode region tight: cropping detection to the overlay box area improves speed and battery life significantly.

Scan history log

Data

Supabase table scan_events storing user_id, barcode_value, barcode_format, context_id, optional metadata JSONB, and scanned_at. Powers the history screen, analytics dashboards, and cross-session duplicate detection. Indexed on (user_id, scanned_at DESC) for fast history queries.

Note: Row-level security ensures each user can only read and insert their own scan rows — AI tools sometimes generate the table without enabling RLS.

Product/asset lookup service

Service

Optional: translates a scanned EAN or UPC into a product name, image, and metadata. A Supabase Edge Function queries an internal products table or calls Open Food Facts REST API (free, no auth) for food items, or a paid catalog API for general retail. Results cached in a local products table to avoid repeat API calls.

Note: Skip entirely if your app scans its own codes — inventory labels, event tickets, and access passes encode an ID you resolve against your own database.

The data model

Two tables: a scan log for audit history and a products cache for lookup results. Run this in the Supabase SQL editor — it creates both tables with RLS policies and the index needed for fast history queries.

schema.sql
1create table public.scan_events (
2 id uuid primary key default gen_random_uuid(),
3 user_id uuid references auth.users(id) on delete cascade not null,
4 barcode_value text not null,
5 barcode_format text not null,
6 context_id text,
7 metadata jsonb,
8 scanned_at timestamptz not null default now()
9);
10
11alter table public.scan_events enable row level security;
12
13create policy "Users can view own scan events"
14 on public.scan_events for select
15 using (auth.uid() = user_id);
16
17create policy "Users can insert own scan events"
18 on public.scan_events for insert
19 with check (auth.uid() = user_id);
20
21create index scan_events_user_recent_idx
22 on public.scan_events (user_id, scanned_at desc);
23
24create table public.products (
25 barcode text primary key,
26 name text,
27 description text,
28 price numeric(10,2),
29 image_url text,
30 fetched_at timestamptz not null default now()
31);
32
33alter table public.products enable row level security;
34
35create policy "Authenticated users can read products"
36 on public.products for select
37 to authenticated
38 using (true);
39
40create policy "Service role can upsert products"
41 on public.products for all
42 to service_role
43 using (true);

Heads up: The products table acts as a lookup cache — Edge Functions write to it using the service role key, while authenticated users can read. Never expose the service role key to the browser.

Build it — pick your path

Each tool fits this feature differently. Switch tabs to compare fit, time, the exact steps, and a copy-paste prompt.

Native iOS + AndroidFit for this feature:

Best path for mobile: FlutterFlow's native Scan Barcode/QR Action wraps mobile_scanner (which uses ML Kit on Android and AVFoundation on iOS) — point-and-click setup with hardware-accelerated scanning.

Step by step

  1. 1Add a Scan Barcode/QR Action to your scan button in the Action editor — choose 'Scan Barcode' from the Camera section
  2. 2Store the scan result in a page state variable (type: String); bind it to a Text widget to display the decoded value
  3. 3Add a Supabase Backend Action after the scan action to insert a row into scan_events with user_id (from auth), barcode_value, barcode_format, and scanned_at
  4. 4Enable camera permissions in Settings → Permissions → iOS Permissions: add NSCameraUsageDescription with a descriptive message; do the same for Android
  5. 5Test on a physical iOS or Android device via the FlutterFlow mobile app — the browser preview cannot scan barcodes

Where this path bites

  • The built-in Scan Barcode action is one-shot — it closes the camera after the first successful scan; continuous scanning mode requires a Custom Action with a MobileScannerController stream listener
  • Torch toggle is not exposed by the built-in scanner action — it requires a one-line Custom Action calling MobileScannerController.toggleTorch()
  • FlutterFlow's Flutter Web output for the scanner widget is unreliable — use FlutterFlow only for iOS and Android targets; add a manual entry fallback page for web

Third-party services you'll need

Scanning itself is free — the decode libraries run on-device. You only pay if you need to identify unknown products from their barcode value:

ServiceWhat it doesFree tierPaid from
html5-qrcodeClient-side barcode decoding for web apps (EAN-13, UPC-A, Code 128, QR, and more)Open source, fully freeFree
Google ML Kit Barcode ScanningOn-device barcode decoding for Android and iOS Flutter apps — faster and more accurate than web librariesFree, runs entirely on-deviceFree
Open Food Facts APIProduct lookup by EAN-13/UPC-A for food and cosmetic items — name, image, nutrition dataFully free, no auth requiredFree (donation-supported)
Supabasescan_events table, products cache, RLS, and Edge Functions for lookupFree tier: 2 projects, 500MB DB, 500K Edge Function invocations/moPro $25/mo (8GB DB, unlimited projects)

Swipe the table sideways to see pricing.

What it costs to run

Drag through the tiers to see how your monthly bill scales with users — no surprises later.

Estimated monthly running cost

$0/mo

html5-qrcode and ML Kit run on-device at no cost. Supabase free tier easily handles 100 users' scan history and lookup cache. Open Food Facts is free.

Estimates use verified 2026 pricing and assume typical usage per user. Your real bill depends on activity, storage, and third-party plans.

What breaks when AI tools build this

The failures people actually hit on their first build — the symptom, why it happens, and the exact fix.

Camera blocked in Lovable and V0 preview iframes

Symptom: Both Lovable and V0 run their previews inside sandboxed iframes that apply a restrictive permissions policy blocking getUserMedia(). The scanner component appears to render correctly in the editor, but the camera feed is black and no scan events fire. This is not a bug in the generated code.

Fix: Always test barcode scanning on the published or deployed HTTPS URL, not in the editor preview. In Lovable, publish the project and open the live URL on your phone. In V0, deploy to Vercel via the Git panel first.

Duplicate scan events — same barcode inserts hundreds of rows

Symptom: html5-qrcode and mobile_scanner fire the success callback on every video frame where the barcode is detected — typically 10+ times per second. Without a cooldown, one real scan inserts dozens of rows into scan_events and triggers the success toast repeatedly, producing a terrible user experience.

Fix: Implement a client-side cooldown: store the last scanned barcode_value and the timestamp of that scan in a ref or state variable. On each callback, reject new events where the value matches and less than 500ms has elapsed since the last accepted scan.

iOS Safari requires HTTPS — common on staging environments

Symptom: getUserMedia() is blocked on iOS Safari over HTTP, including on staging environments using self-signed certificates or http:// localhost tunnels. The camera permission dialog never appears and the scanner silently fails.

Fix: Ensure your deployed URL uses HTTPS. Vercel and Lovable publish URLs are HTTPS by default. For local development on iOS, use a tool like ngrok to expose localhost over HTTPS.

Barcode format mismatch — AI tools default to QR only

Symptom: When prompted to build a barcode scanner, AI tools frequently configure html5-qrcode with only QR code support, silently ignoring EAN-13 and UPC-A retail barcodes. Users try to scan a product barcode and nothing happens — there is no error, the scanner just doesn't trigger.

Fix: In your prompt, explicitly list every format you need as an array: [Html5QrcodeSupportedFormats.EAN_13, Html5QrcodeSupportedFormats.UPC_A, Html5QrcodeSupportedFormats.CODE_128, Html5QrcodeSupportedFormats.QR_CODE]. Pass this array to the formatsToSupport option in the scanner config.

FlutterFlow web scanner crashes on Flutter Web output

Symptom: FlutterFlow's mobile_scanner package does not compile correctly for Flutter Web. The scanner widget crashes on load in web mode with a plugin missing exception, leaving users on web with a broken screen.

Fix: Use FlutterFlow's barcode scanner only for iOS and Android deployment targets. For users on web, add a conditional visibility check (Platform.isWeb) and show a manual barcode entry text field as the fallback on web.

Best practices

1

Restrict the decode format list to only the formats your app actually uses — scanning EAN-13 and QR only roughly doubles detection speed compared to enabling all formats

2

Give haptic feedback (navigator.vibrate(200) on web, HapticFeedback.mediumImpact() on Flutter) the instant a scan succeeds, before any network call, so the user knows the scan was captured

3

Cache product lookup results in your own products table — the second user scanning the same barcode should never hit an external API

4

Always ship a manual entry fallback input below the scanner — damaged, tiny, or curved labels are a daily reality in inventory and field workflows

5

Stop the camera stream when the scanner component unmounts — a stuck camera indicator in the browser toolbar destroys user trust and wastes battery

6

Log scan failures (barcode format, time spent scanning, error type) so you can see whether users struggle before they submit support tickets

7

Write NSCameraUsageDescription in FlutterFlow under Settings → Permissions with a specific reason — 'Camera is used to scan product barcodes for inventory tracking' — generic descriptions lead to App Store rejection

When You Need Custom Development

AI tools comfortably cover scan-and-record features for everyday volumes. Specific workloads consistently outgrow what Lovable, V0, or FlutterFlow can produce:

  • Staff scan continuously for hours (warehouse, POS, field inspection) — you need native ML Kit performance, offline scan queues, and hardware Bluetooth or USB HID scanner support that web apps cannot provide
  • Scans must work with zero connectivity and sync later without data loss or duplicates — true offline-first requires a local SQLite outbox that AI tools cannot reliably wire
  • You need to decode damaged, curved, or poorly printed labels where free libraries plateau and evaluating commercial SDKs (Scandit-class) is necessary
  • The scanner feeds a multi-step business workflow — picking, packing, stock reconciliation — where a mis-scan costs real money and requires custom error recovery logic

RapidDev builds these features for production

Real auth, database, and payments — fixed price, delivered in weeks. You own 100% of the code.

Get a fixed-price quote

Frequently asked questions

Does barcode scanning work on mobile browsers without a native app?

Yes. html5-qrcode decodes EAN-13, UPC-A, Code 128, and QR codes through the browser camera on both iOS Safari (14.5+) and Chrome Android. Native apps win on scan speed and battery life for continuous-scanning workloads, but for occasional scan-to-look-up flows a web app works well.

What barcode formats does html5-qrcode support?

html5-qrcode supports QR Code, EAN-13, EAN-8, UPC-A, UPC-E, Code 39, Code 93, Code 128, ITF, Codabar, RSS-14, and PDF-417 among others. You must explicitly list the formats you want in the formatsToSupport config array — the default is QR-only, which silently ignores retail barcodes.

How do I stop duplicate scans from being saved to the database?

Store the last successfully scanned barcode value and the time it was accepted in a ref. On each decode callback, check whether the incoming value matches the stored value and whether the timestamp is less than 500ms ago. If both conditions are true, skip the database insert. This is the 500ms cooldown pattern — include it explicitly in your build prompt.

Can I scan barcodes in the Lovable or V0 preview without publishing?

No. Both preview environments run inside sandboxed iframes that block camera access via getUserMedia(). This is a browser security restriction, not a bug in your code. Always test scanning on the published or deployed HTTPS URL on a real phone.

How do I add product lookup when a barcode is scanned?

Create a Supabase Edge Function that receives the barcode value, queries your products table first (as a cache), and if not found calls the Open Food Facts API (for food items, free) or a paid catalog API. Return the product name and image to the client and cache the result in your products table so the next user scanning the same barcode doesn't hit the external API.

Is Google ML Kit barcode scanning free to use?

Yes, entirely free. ML Kit Barcode Scanning runs on-device on Android and iOS with no API calls, no quota, and no per-scan fee. It is bundled with Google Play Services on Android and part of the Vision framework on iOS.

How do I handle the camera permission denied state gracefully?

In html5-qrcode, catch the error callback and check for the NotAllowedError type. On denial, render a permission explainer screen explaining why the camera is needed, with a 'Try Again' button that calls Html5Qrcode.getCameras() again. In FlutterFlow, use permission_handler's Permission.camera.isPermanentlyDenied check and show an 'Open Settings' button calling openAppSettings() for users who chose 'Never Ask Again' on Android.

Can FlutterFlow build a barcode scanner for both iOS and Android?

Yes, and it is the easiest path for mobile — FlutterFlow's built-in Scan Barcode/QR action wraps mobile_scanner which uses ML Kit on Android and AVFoundation on iOS. Both platforms work with no code written. The limitation is that the built-in action is one-shot per tap; continuous scanning mode and torch control require a Custom Action.

RapidDev

Need this feature production-ready?

RapidDev builds a barcode scanner into real apps — auth, database, payments — at $13K–$25K.

Book a free consultation

30-min call. No commitment.

Want this built for you?

We ship production apps at a fixed price — $13K–$25K, 6–10 weeks, source code yours. You've seen what it takes; we do it every week.

Get a fixed-price quote

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.