# How to Create a Barcode Scanner in FlutterFlow

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 20-25 min
- Compatibility: FlutterFlow Pro+ (Custom Code required)
- Last updated: March 2026

## TL;DR

Create a barcode scanner in FlutterFlow using a Custom Widget with the mobile_scanner package. Initialize MobileScannerController with back camera and normal detection speed. Handle the onDetect callback to extract barcode.rawValue and pass the scanned result to the parent via an Action Parameter callback. Add a scanner frame overlay using a Stack with a transparent center rectangle for visual targeting.

## Building a Barcode and QR Code Scanner in FlutterFlow

Barcode scanning is essential for inventory management, retail apps, event ticketing, and product lookup. FlutterFlow does not have a built-in scanner widget, so you need a Custom Widget using the mobile_scanner package. This tutorial covers the full implementation including camera setup, barcode detection, overlay UI, and data passing.

## Before you start

- FlutterFlow Pro plan or higher (Custom Code required)
- A FlutterFlow project open in the builder
- A physical device for testing (camera does not work in simulator)
- Camera permissions configured in your app settings

## Step-by-step guide

### 1. Add the mobile_scanner dependency to your project

Navigate to Custom Code in the left Navigation Menu and click the Pubspec Dependencies tab. Add mobile_scanner with version ^5.0.0. Click Save. This package is the recommended successor to qr_code_scanner and supports QR codes, UPC, EAN, Code128, and all major barcode formats on both iOS and Android.

**Expected result:** The mobile_scanner package appears in your Pubspec Dependencies without errors.

### 2. Create the Custom Widget with MobileScannerController

Go to Custom Code → Custom Widgets → Add. Name it BarcodeScannerWidget. Add parameters: onBarcodeScanned (Action, required) to pass the result back to the parent. In the code editor, create a StatefulWidget. In initState, create a MobileScannerController with detectionSpeed set to DetectionSpeed.normal, facing set to CameraFacing.back, and torchEnabled set to false. In build, return a MobileScanner widget with the controller and an onDetect callback that extracts the barcode value.

```
import 'package:mobile_scanner/mobile_scanner.dart';

class BarcodeScannerWidget extends StatefulWidget {
  const BarcodeScannerWidget({
    super.key,
    this.width,
    this.height,
    required this.onBarcodeScanned,
  });
  final double? width;
  final double? height;
  final Future Function(String barcodeValue) onBarcodeScanned;

  @override
  State<BarcodeScannerWidget> createState() => _BarcodeScannerWidgetState();
}

class _BarcodeScannerWidgetState extends State<BarcodeScannerWidget> {
  final MobileScannerController _controller = MobileScannerController(
    detectionSpeed: DetectionSpeed.normal,
    facing: CameraFacing.back,
    torchEnabled: false,
  );
  bool _hasScanned = false;

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: widget.width ?? double.infinity,
      height: widget.height ?? 400,
      child: MobileScanner(
        controller: _controller,
        onDetect: (capture) {
          if (_hasScanned) return;
          final barcode = capture.barcodes.firstOrNull;
          if (barcode?.rawValue != null) {
            _hasScanned = true;
            widget.onBarcodeScanned(barcode!.rawValue!);
          }
        },
      ),
    );
  }
}
```

**Expected result:** The Custom Widget compiles and detects barcodes via the camera feed.

### 3. Add a scanner frame overlay with a transparent center target area

Wrap the MobileScanner in a Stack. Add a second child to the Stack: a CustomPaint or a Column of Containers creating a darkened overlay with a transparent rectangular cutout in the center. The cutout acts as a visual target — users aim the barcode within this frame. Use Container widgets with semi-transparent black background around the edges, leaving the center open. Add a thin border Container (2px, white) around the cutout for the scanning frame indicator.

**Expected result:** A darkened overlay with a clear center rectangle shows over the camera preview, guiding where to aim the barcode.

### 4. Add a torch toggle button and result display

Below or overlaying the scanner, add an IconButton for torch/flash toggle. On Tap, call controller.toggleTorch(). Use a StreamBuilder on controller.torchState to toggle the icon between flash_on and flash_off. Below the scanner, add a Text widget bound to a Page State variable scannedResult that updates when the onBarcodeScanned callback fires. After scanning, you can automatically navigate to a product detail page or show the result in a dialog.

**Expected result:** Users can toggle the flashlight for low-light scanning and see the scanned barcode value displayed on screen.

### 5. Handle the scanned result in the parent page action flow

On the page where you placed the BarcodeScannerWidget, bind the onBarcodeScanned Action Parameter to an action flow. In the flow: update Page State scannedResult with the barcode value, then either navigate to a lookup page passing the value as a Route Parameter, or call an API/Backend Query to look up the product by barcode. Add a reset mechanism — a Scan Again button that sets _hasScanned back to false (via a Custom Action calling a method on the widget, or by rebuilding the widget).

**Expected result:** Scanned barcode data flows from the Custom Widget to the parent page for display or database lookup.

## Complete code example

File: `barcode_scanner_widget.dart`

```dart
import 'package:mobile_scanner/mobile_scanner.dart';

class BarcodeScannerWidget extends StatefulWidget {
  const BarcodeScannerWidget({
    super.key,
    this.width,
    this.height,
    required this.onBarcodeScanned,
  });

  final double? width;
  final double? height;
  final Future Function(String barcodeValue) onBarcodeScanned;

  @override
  State<BarcodeScannerWidget> createState() => _BarcodeScannerWidgetState();
}

class _BarcodeScannerWidgetState extends State<BarcodeScannerWidget> {
  final MobileScannerController _controller = MobileScannerController(
    detectionSpeed: DetectionSpeed.normal,
    facing: CameraFacing.back,
    torchEnabled: false,
  );
  bool _hasScanned = false;

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _onDetect(BarcodeCapture capture) {
    if (_hasScanned) return;
    final barcode = capture.barcodes.firstOrNull;
    if (barcode?.rawValue == null) return;
    setState(() => _hasScanned = true);
    widget.onBarcodeScanned(barcode!.rawValue!);
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: widget.width ?? double.infinity,
      height: widget.height ?? 400,
      child: Stack(
        children: [
          MobileScanner(
            controller: _controller,
            onDetect: _onDetect,
          ),
          // Overlay with transparent center
          Center(
            child: Container(
              width: 250,
              height: 250,
              decoration: BoxDecoration(
                border: Border.all(color: Colors.white, width: 2),
                borderRadius: BorderRadius.circular(12),
              ),
            ),
          ),
          // Torch toggle button
          Positioned(
            bottom: 16,
            right: 16,
            child: IconButton(
              icon: const Icon(Icons.flash_on, color: Colors.white, size: 28),
              onPressed: () => _controller.toggleTorch(),
            ),
          ),
        ],
      ),
    );
  }
}
```

## Common mistakes

- **Using the deprecated qr_code_scanner package** — qr_code_scanner is unmaintained and crashes on newer Flutter versions (3.x+). It also has limited barcode format support compared to mobile_scanner. Fix: Use mobile_scanner (version 5.x) which is actively maintained, supports all barcode formats, and works with current Flutter versions.
- **Not preventing multiple scans of the same barcode** — The onDetect callback fires continuously while a barcode is in view. Without a guard, your callback triggers dozens of times for one scan, causing duplicate navigation or API calls. Fix: Add a boolean _hasScanned flag that blocks further callbacks after the first successful detection. Reset it when the user wants to scan again.
- **Testing barcode scanning in the iOS simulator or FlutterFlow preview** — Camera access is not available in simulators or the FlutterFlow web preview. The scanner shows a black screen or crashes. Fix: Test barcode scanning on a physical iOS or Android device. Use Run mode or a test APK/IPA build.

## Best practices

- Use mobile_scanner package version 5.x for the most reliable barcode detection
- Add a visual scanner frame overlay to guide users where to aim the camera
- Prevent duplicate scans with a boolean flag that blocks callbacks after first detection
- Include a torch/flash toggle button for scanning in low-light environments
- Always dispose the MobileScannerController in the widget's dispose method
- Test on physical devices — camera scanning does not work in simulators
- Handle the case where camera permission is denied with a friendly message and settings link

## Frequently asked questions

### What barcode formats does mobile_scanner support?

mobile_scanner supports QR Code, UPC-A, UPC-E, EAN-8, EAN-13, Code 39, Code 93, Code 128, ITF, Codabar, Data Matrix, Aztec, and PDF417.

### Can the scanner read barcodes from images instead of the live camera?

Yes. mobile_scanner supports analyzing static images via MobileScannerController.analyzeImage(path). The user selects an image and the scanner detects barcodes in it.

### Does the barcode scanner work on web?

mobile_scanner has limited web support using the device webcam. It works best on mobile (iOS and Android) where it uses the native camera APIs.

### How do I scan only QR codes and ignore other barcode types?

In the onDetect callback, check barcode.format. Only process the result if format equals BarcodeFormat.qrCode. Ignore other formats by returning early.

### Can I customize the scanner overlay frame size?

Yes. The overlay is just a Container with a border. Change the width and height to match the barcode size you expect — larger for QR codes, narrower for linear barcodes.

### Can RapidDev help build a scanning workflow for my business?

Yes. RapidDev can build end-to-end scanning workflows including barcode detection, product database lookup, inventory management, and receipt generation.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-create-a-barcode-scanner-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-create-a-barcode-scanner-in-flutterflow
