Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Build a QR Code Generator and Reader in FlutterFlow

Build both a QR code generator and reader in FlutterFlow using Custom Widgets. The generator uses the qr_flutter package to render a QR code from any string input. The reader uses the mobile_scanner package to decode QR codes from the device camera, parsing URLs, plain text, vCard, and WiFi configurations. Add save-to-image functionality using RepaintBoundary to export generated QR codes as shareable images.

What you'll learn

  • How to generate QR codes from text input using the qr_flutter Custom Widget
  • How to scan and decode QR codes with the mobile_scanner Custom Widget
  • How to parse different QR data types (URL, vCard, WiFi, plain text)
  • How to save a generated QR code as an image for sharing
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read20-25 minFlutterFlow Free+ (Custom Widgets required)March 2026RapidDev Engineering Team
TL;DR

Build both a QR code generator and reader in FlutterFlow using Custom Widgets. The generator uses the qr_flutter package to render a QR code from any string input. The reader uses the mobile_scanner package to decode QR codes from the device camera, parsing URLs, plain text, vCard, and WiFi configurations. Add save-to-image functionality using RepaintBoundary to export generated QR codes as shareable images.

QR code generation and scanning with data type detection

QR codes are used everywhere: event tickets, product lookups, WiFi sharing, contact exchange, and payment links. This tutorial builds both sides in FlutterFlow. The generator takes any string input and renders a scannable QR code using the qr_flutter package, with the option to save it as an image. The reader uses mobile_scanner to decode QR codes from the camera and automatically detects the data type (URL, vCard, WiFi config, or plain text) to take the appropriate action.

Prerequisites

  • A FlutterFlow project (any plan that supports Custom Widgets)
  • Basic understanding of Custom Widgets and Action Parameters
  • Camera permissions configured for your app (for the scanner)
  • Physical device or emulator with camera for testing the reader

Step-by-step guide

1

Create the QR code generator Custom Widget

In FlutterFlow, go to Custom Code and create a new Custom Widget named QRCodeGenerator. Add a parameter: data (String) for the content to encode, and an optional size (Double, default 200). Add the qr_flutter package as a dependency. In the widget body, return a QrImageView widget with data set to widget.data, version set to QrVersions.auto, and size set to widget.size. Wrap it in a Container with a white background and padding of 16 for a clean border around the QR code. This widget can encode any string: URLs, plain text, contact info, or WiFi credentials.

qr_code_generator.dart
1// Custom Widget: QRCodeGenerator
2import 'package:qr_flutter/qr_flutter.dart';
3
4class QRCodeGenerator extends StatelessWidget {
5 final String data;
6 final double? size;
7
8 const QRCodeGenerator({
9 required this.data,
10 this.size = 200,
11 super.key,
12 });
13
14 @override
15 Widget build(BuildContext context) {
16 return Container(
17 padding: const EdgeInsets.all(16),
18 decoration: BoxDecoration(
19 color: Colors.white,
20 borderRadius: BorderRadius.circular(12),
21 ),
22 child: QrImageView(
23 data: data,
24 version: QrVersions.auto,
25 size: size ?? 200,
26 gapless: true,
27 errorCorrectionLevel: QrErrorCorrectLevel.M,
28 ),
29 );
30 }
31}

Expected result: A Custom Widget that renders a QR code from any string data, usable on any page by passing the data parameter.

2

Build the generator page with text input and QR display

Create a QRGeneratorPage with a TextField at the top for entering the data to encode (hint text: 'Enter URL, text, or data'). Below, add the QRCodeGenerator Custom Widget with its data parameter bound to the TextField value via Page State. Add a DropDown for quick data templates: URL, WiFi, Contact (vCard), Plain Text. When WiFi is selected, show additional TextFields for network name, password, and encryption type (WPA/WEP/none), then compose the WiFi QR format: 'WIFI:T:{encryption};S:{ssid};P:{password};;'. For vCard, show name, phone, and email fields and compose: 'BEGIN:VCARD\nVERSION:3.0\nN:{name}\nTEL:{phone}\nEMAIL:{email}\nEND:VCARD'. The QR code updates in real time as the user types.

Expected result: Users can type or compose data and see the QR code update in real time. Templates help format WiFi and vCard data correctly.

3

Add save-to-image functionality for the generated QR code

Create a Custom Action named saveQRCodeAsImage. This action wraps the QR widget in a RepaintBoundary with a GlobalKey, renders it to an image using boundary.toImage(), converts to PNG bytes, and saves to the device gallery using the image_gallery_saver package (or shares directly via share_plus). In the QRGeneratorPage, add a Button labeled 'Save QR Code' below the QR widget. On Tap, call this Custom Action. Alternatively, use a simpler approach: add a Share button that calls a Custom Action composing the QR data into a shareable format and opens the native share sheet, or use the screenshot package to capture the widget area.

save_qr_as_image.dart
1// Custom Action: saveQRAsImage
2import 'dart:ui' as ui;
3import 'dart:typed_data';
4import 'package:flutter/rendering.dart';
5import 'package:share_plus/share_plus.dart';
6import 'dart:io';
7import 'package:path_provider/path_provider.dart';
8
9Future saveQRAsImage(GlobalKey repaintKey) async {
10 final boundary = repaintKey.currentContext!
11 .findRenderObject() as RenderRepaintBoundary;
12 final image = await boundary.toImage(pixelRatio: 3.0);
13 final byteData = await image.toByteData(
14 format: ui.ImageByteFormat.png,
15 );
16 final bytes = byteData!.buffer.asUint8List();
17 final dir = await getTemporaryDirectory();
18 final file = File('${dir.path}/qr_code.png');
19 await file.writeAsBytes(bytes);
20 await Share.shareXFiles([XFile(file.path)], text: 'QR Code');
21}

Expected result: Users can save or share the generated QR code as a PNG image from the generator page.

4

Create the QR code reader Custom Widget with camera scanning

Create a new Custom Widget named QRCodeReader. Add the mobile_scanner package as a dependency. Add an Action Parameter callback named onScanned (returns String) that sends the decoded data back to the parent page. In the widget body, return a MobileScanner widget with onDetect callback. When a barcode is detected, extract the rawValue, call the onScanned callback with the value, and optionally stop the scanner to prevent repeated scans by calling controller.stop(). Add a camera overlay with a transparent center square and semi-transparent borders to guide the user where to point the camera.

qr_code_reader.dart
1// Custom Widget: QRCodeReader
2import 'package:mobile_scanner/mobile_scanner.dart';
3
4class QRCodeReader extends StatefulWidget {
5 final Future Function(String scannedData) onScanned;
6 const QRCodeReader({required this.onScanned, super.key});
7
8 @override
9 State<QRCodeReader> createState() => _QRCodeReaderState();
10}
11
12class _QRCodeReaderState extends State<QRCodeReader> {
13 final MobileScannerController _controller = MobileScannerController();
14 bool _hasScanned = false;
15
16 @override
17 Widget build(BuildContext context) {
18 return MobileScanner(
19 controller: _controller,
20 onDetect: (capture) {
21 if (_hasScanned) return;
22 final barcode = capture.barcodes.firstOrNull;
23 if (barcode?.rawValue != null) {
24 _hasScanned = true;
25 _controller.stop();
26 widget.onScanned(barcode!.rawValue!);
27 }
28 },
29 );
30 }
31
32 @override
33 void dispose() {
34 _controller.dispose();
35 super.dispose();
36 }
37}

Expected result: A camera-based QR scanner widget that detects codes and sends the decoded string back via a callback.

5

Build the scanner page with data type detection and actions

Create a QRScannerPage with the QRCodeReader Custom Widget filling the screen. Wire the onScanned callback to set Page State scannedData with the result and show a BottomSheet displaying the decoded content. Create a Custom Function named detectQRDataType that analyzes the scanned string: if it starts with 'http://' or 'https://', return 'url'; if it starts with 'WIFI:', return 'wifi'; if it starts with 'BEGIN:VCARD', return 'vcard'; otherwise return 'text'. Based on the detected type, show different action buttons in the BottomSheet: URL shows 'Open Link' (Launch URL action) and 'Copy' (Clipboard); WiFi shows 'Connect' (parse SSID and password, display them); vCard shows 'Save Contact' (parse name, phone, email); plain text shows 'Copy to Clipboard'. Add a 'Scan Again' button that resets the scanner.

Expected result: The scanner reads QR codes and presents context-appropriate actions based on the data type: open URLs, display WiFi credentials, show contact info, or copy text.

Complete working example

QR Code System Architecture
1Custom Widgets:
2 QRCodeGenerator
3 Package: qr_flutter
4 Parameters: data (String), size (Double?)
5 Renders: QrImageView with white Container wrapper
6 QRCodeReader
7 Package: mobile_scanner
8 Action Parameter: onScanned (String callback)
9 Renders: MobileScanner with single-scan guard
10
11QR Generator Page:
12 DropDown (template: URL | WiFi | vCard | Plain Text)
13 TextField (data input, or composed from template fields)
14 [WiFi mode] SSID + Password + Encryption fields
15 [vCard mode] Name + Phone + Email fields
16 QRCodeGenerator Widget (data: Page State qrData)
17 Button ("Save QR Code")
18 On Tap saveQRAsImage Custom Action
19 Button ("Share")
20 On Tap shareContent Custom Action
21
22QR Scanner Page:
23 QRCodeReader Widget (fills screen)
24 onScanned Set Page State: scannedData Show BottomSheet
25 BottomSheet (scan result)
26 Text (scanned data)
27 Text (detected type badge)
28 Actions (conditional by type):
29 URL Button "Open Link" (Launch URL) + "Copy"
30 WiFi Text (SSID + Password) + "Copy Password"
31 vCard Text (Name + Phone + Email) + "Save Contact"
32 Text Button "Copy to Clipboard"
33 Button ("Scan Again" reset scanner)
34
35Data Type Detection (Custom Function):
36 starts with 'http://' or 'https://' 'url'
37 starts with 'WIFI:' 'wifi'
38 starts with 'BEGIN:VCARD' 'vcard'
39 else 'text'
40
41QR Format Standards:
42 WiFi: WIFI:T:WPA;S:MyNetwork;P:MyPassword;;
43 vCard: BEGIN:VCARD\nVERSION:3.0\nN:Name\nTEL:+1234\nEMAIL:a@b.com\nEND:VCARD
44 URL: https://example.com/page

Common mistakes when building a QR Code Generator and Reader in FlutterFlow

Why it's a problem: Generating QR codes with too much data causing unreadable dense patterns

How to avoid: Keep encoded data short. For long content, store the data in Firestore and encode only the document ID or a short URL. Use a URL shortener for long web addresses.

Why it's a problem: Not stopping the scanner after a successful detection

How to avoid: Add a boolean _hasScanned flag. Set it to true on first detection and call controller.stop(). Only process the scan when _hasScanned is false. Add a Scan Again button that resets the flag and restarts the controller.

Why it's a problem: Forgetting to request camera permissions for the scanner

How to avoid: In FlutterFlow project settings, enable camera permissions for both iOS (NSCameraUsageDescription) and Android (CAMERA permission). Add a pre-check Custom Action that verifies permission is granted before navigating to the scanner page.

Best practices

  • Keep QR data under 500 characters for reliable scanning across all devices and camera qualities
  • Use error correction level M (15% recovery) for a balance between data density and scan reliability
  • Stop the scanner after first detection to prevent duplicate processing
  • Add a visible scanning guide overlay (transparent center square) to help users aim the camera
  • Support standard QR formats: WiFi (WIFI:T:...), vCard (BEGIN:VCARD...), and URLs for maximum interoperability
  • Add a white quiet zone (padding) around generated QR codes for better scanner recognition
  • Test scanning with both high-quality and low-quality phone cameras to verify readability

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Write a Flutter widget that generates a QR code from a string input using the qr_flutter package. Include options for size, error correction level, and a white border. Also write a scanner widget using mobile_scanner that detects QR codes and returns the decoded string via a callback.

FlutterFlow Prompt

Create a QR code generator page with a text input field and a QR code display that updates in real time. Add a dropdown to switch between URL, WiFi, and plain text modes with appropriate input fields for each.

Frequently asked questions

What is the maximum amount of data a QR code can hold?

A QR code can hold up to 7,089 numeric characters, 4,296 alphanumeric characters, or about 2,953 bytes of binary data. However, practical limits are much lower because dense codes are hard to scan. Keep data under 500 alphanumeric characters for reliable scanning.

Can I customize the QR code colors or add a logo in the center?

Yes. The qr_flutter package supports custom foreground and background colors via the dataModuleStyle and eyeStyle properties. For a center logo, use a Stack widget with the QR code and a small Image overlaid in the center. Error correction level H (30%) allows the logo to obscure some modules without losing scannability.

Does the scanner work offline without an internet connection?

Yes. The mobile_scanner package decodes QR codes locally on the device using the camera. No internet connection is needed for scanning. However, if the decoded content is a URL, the user will need internet to open it.

How do I scan QR codes from images in the photo gallery?

Use the MobileScannerController's analyzeImage method. Let the user pick an image from their gallery using FlutterFlowUploadButton, then pass the file path to analyzeImage(). This decodes QR codes from static images without the camera.

What is the WiFi QR code format standard?

The WiFi QR format is: WIFI:T:{encryption};S:{ssid};P:{password};; where T is WPA, WEP, or nopass; S is the network name; and P is the password. Most phones can auto-join WiFi networks when scanning this format.

Can RapidDev help build a QR-based ticketing or inventory system?

Yes. A production QR system for event tickets, inventory tracking, or access control needs secure encoded payloads, server-side validation, duplicate scan prevention, offline capability, and admin dashboards. RapidDev can design the full system beyond basic generation and scanning.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

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.