Document Scanner in FlutterFlow

In the digital age, being able to scan and store documents on-the-go is more than a convenience — it’s a necessity. Whether it’s students scanning their notes, professionals saving receipts, or individuals digitizing important papers, having a document scanner built directly into a mobile app adds incredible value.
In this blog, we’ll explore how to create a fully functional document scanner inside FlutterFlow, using a native plugin (cunning_document_scanner
) and custom widgets/actions for scanning, previewing, and downloading images.
What You’ll Build
We’re going to build a FlutterFlow Document Scanner app that:
- 📸 Scans books or documents via the camera.
- 🖼️ Shows the scanned image in a bottom sheet.
- ⬇️ Lets users download the scanned image to their device.
All this will be built using:
- 2 Widgets:
DocumentScanner
andScannerDoc
- 1 Custom Action:
takeScanner
- Plugin:
cunning_document_scanner: ^1.2.3
🛠️ Tools & Packages Required
To enable scanning and saving functionality, we’ll use:
dependencies:
cunning_document_scanner: ^1.2.3
Make sure these packages are added in your FlutterFlow project’s pubspec.yaml file via the “Custom Code > Dependencies” tab.
Widget Structure
DocumentScanner
Widget
This is the main screen of the app. It contains a button or icon that initiates the scan process.
What it does:
- Calls the
takeScanner
custom action when tapped. - Stores the list of scanned image paths.
- Navigates to the
ScannerDoc
screen to show results.

🔧 Dart Code:
// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/custom_code/actions/index.dart'; // Imports custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'dart:io';
import 'package:cunning_document_scanner/cunning_document_scanner.dart';
class DocumentScanner extends StatefulWidget {
const DocumentScanner({
super.key,
this.width,
this.height,
});
final double? width;
final double? height;
@override
State<DocumentScanner> createState() => _DocumentScannerState();
}
class _DocumentScannerState extends State<DocumentScanner> {
List<String> _pictures = [];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: SingleChildScrollView(
child: Column(
children: [
ElevatedButton(
onPressed: onPressed, child: const Text("Add Pictures")),
for (var picture in _pictures) Image.file(File(picture))
],
)),
),
);
}
void onPressed() async {
List<String> pictures;
try {
pictures = await CunningDocumentScanner.getPictures() ?? [];
if (!mounted) return;
setState(() {
_pictures = pictures;
});
} catch (exception) {
// Handle exception here
}
}
}
ScannerDoc
Widget
This widget displays the scanned images in a bottom sheet.
Features:
- Scrollable image viewer (for multiple scans).
- Tappable image preview.
Download
button next to each image for saving.
🔧 Dart Code:
// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/custom_code/actions/index.dart'; // Imports custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'package:cunning_document_scanner/cunning_document_scanner.dart';
import 'dart:io';
class ScannerDoc extends StatefulWidget {
const ScannerDoc({
super.key,
this.width,
this.height,
});
final double? width;
final double? height;
@override
State<ScannerDoc> createState() => _ScannerDocState();
}
class _ScannerDocState extends State<ScannerDoc> {
List<String> _pictures = [];
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: SingleChildScrollView(
child: Column(
children: [
ElevatedButton(
onPressed: onPressed, child: const Text("Add Pictures")),
for (var picture in _pictures) Image.file(File(picture))
],
)),
),
);
}
void onPressed() async {
List<String> pictures;
try {
pictures = await CunningDocumentScanner.getPictures() ?? [];
if (!mounted) return;
setState(() {
_pictures = pictures;
});
} catch (exception) {
// Handle exception here
}
}
}
Custom Action: takeScanner
This action integrates the cunning_document_scanner
plugin and launches the native camera interface.
🔧 Dart Code:
// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'dart:io';
import 'dart:async';
import 'package:cunning_document_scanner/cunning_document_scanner.dart';
Future<List<FFUploadedFile>?> takeScanner() async {
// Add your function code here!
try {
// Panggil scanner untuk mengambil gambar dokumen
List<String>? pictures = await CunningDocumentScanner.getPictures();
// Jika hasilnya kosong, return null
if (pictures == null || pictures.isEmpty) {
return null;
}
// Konversi hasil path gambar menjadi List<FFUploadedFile>
List<FFUploadedFile> uploadedFiles = pictures.map((path) {
File file = File(path);
return FFUploadedFile(
name: path.split('/').last, // Mengambil nama file dari path
bytes: file.readAsBytesSync(), // Membaca file sebagai bytes
);
}).toList();
return uploadedFiles;
} catch (e) {
print('Error scanning document: $e');
return null;
}
}
How It Works:
- Calls the scanner.
- Returns a list of scanned image paths.
- Passes these paths back to the widget for display.
Adding the Download Button
Inside the ScannerDoc
bottom sheet, we add a Download button. This button triggers another custom action that saves the image to the user’s gallery.
Putting It All Together (User Flow)
- Open App → DocumentScanner widget.
- Click “Scan” → launches camera via
takeScanner
. - User scans pages → list of image paths returned.
- Navigate to ScannerDoc → show images in bottom sheet.
- User taps “Download” → image saved to gallery.
Customizing the UI
FlutterFlow allows you to:
- Use custom containers to style your bottom sheet
- Add animation when showing the scanned image
- Support light/dark themes
- Add optional text fields (e.g. label your scans)
You can also:
- Combine this with OCR tools to extract text
- Convert images to PDF using another custom action
- Sync with Firebase to store scanned files in the cloud
Permissions to Handle
Be sure to request permissions for:
- Camera Access
- Storage Access (Android only)
Use permission_handler
to manage this properly in custom code.
Final Testing Tips
- Test on a real device (scanning and file saving might not work on emulators).
- Verify permissions are granted.
- Check for multiple image support if needed.
- Add error handling for denied permissions.
Conclusion
By combining FlutterFlow’s visual development power with native Flutter packages like cunning_document_scanner
, you can create a production-ready document scanner in just a few hours. With reusable widgets, clean actions, and smooth UI, your app can offer a premium scanning experience without depending on third-party apps.
From Our Parent Company Aeologic
Aeologic Technologies is a leading AI-driven digital transformation company in India, helping businesses unlock growth with AI automation, IoT solutions, and custom web & mobile app development. We also specialize in AIDC solutions and technical manpower augmentation, offering end-to-end support from strategy and design to deployment and optimization.
Trusted across industries like manufacturing, healthcare, logistics, BFSI, and smart cities, Aeologic combines innovation with deep industry expertise to deliver future-ready solutions.
Feel free to connect with us:
And read more articles from FlutterDevs.com.
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire Flutterflow developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! For any flutter-related queries, you can connect with us on Facebook, GitHub, Twitter, and LinkedIn.
We welcome feedback and hope that you share what you’re working on using #FlutterDevs. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences.
