There are several methods you can create screenshots of a Flutter app, depending on whether you want manual screenshots, automated screenshots, or marketing-ready assets. Here’s a breakdown:
📱 1. Manual Screenshots
- Device Emulator/Simulator
- Run your app in Android Emulator or iOS Simulator, then use their built-in screenshot tools.
- Android Studio →
Device Manager→ Take Screenshot - Xcode Simulator →
⌘ + S(or menu →File > New Screenshot)
- Real Device
- Run the app on your phone and use the system screenshot shortcut (e.g.
Power + Volume Downon Android,Side + Volume Upon iPhone).
- Run the app on your phone and use the system screenshot shortcut (e.g.
🤖 2. Automated Screenshots (for multiple devices/languages)
integration_test+screenshotspackage (deprecated)- screenshots plugin lets you automate capturing screenshots for different devices and locales.
- Useful for app store previews.
- Runs Flutter integration tests and captures frames programmatically.
flutter_driver(deprecated)- Older method with
flutter_driver, but now replaced byintegration_test.
- Older method with
🎨 3. Programmatic Screenshots Inside Flutter
RepaintBoundary+RenderRepaintBoundary.toImage()- Wrap any widget in a
RepaintBoundaryand capture it as an image. - Example:
GlobalKey key = GlobalKey(); RepaintBoundary( key: key, child: MyWidget(), ); Future<void> capturePng() async { RenderRepaintBoundary boundary = key.currentContext!.findRenderObject() as RenderRepaintBoundary; var image = await boundary.toImage(); ByteData? byteData = await image.toByteData(format: ImageByteFormat.png); Uint8List pngBytes = byteData!.buffer.asUint8List(); // Save or share pngBytes } - Great for capturing widgets rather than the whole device screen.
- Wrap any widget in a
🛠 4. Tools for Marketing Screenshots
- fastlane + frameit https://docs.fastlane.tools/actions/frameit/
- Automate generating app store screenshots with device frames.
- Third-party tools (e.g. Previewed.app, DaVinci, Shotbot)
- Let you place screenshots into polished device mockups.
👉 Quick recommendation:
- For simple one-off screenshots → use emulator/device built-in tools.
- For many locales/devices for app store → use the
screenshotspackage. - For in-app widget exports (e.g. custom cards) → use
RepaintBoundary.
Instructions for fastlane
✅ You want to capture Flutter app screenshots with Fastlane. That’s a great choice if you’re preparing App Store / Google Play screenshots across devices and languages.
Here’s a step-by-step guide:
🔧 Prerequisites
- Install Fastlane (Ruby gem)
sudo gem install fastlane -NVOr with
brewon macOS:brew install fastlane - Xcode & Android Studio installed (since Fastlane runs simulators/emulators).
- Your Flutter project should have integration tests or flows you want to capture.
📸 Step 1. Add the Fastlane folder
In your Flutter project root:
cd ios
fastlane init
This creates ios/fastlane/ with Fastfile.
Do the same in android/ if you want Play Store automation.
📸 Step 2. Add the snapshot (iOS) / screengrab (Android) plugin
For iOS (Xcode UI tests):
fastlane add_plugin snapshot
For Android (UI Automator tests):
fastlane add_plugin screengrab
📸 Step 3. Configure UI Tests for Screenshots
iOS – snapshot
- In
ios/RunnerUITests/, create a UI test (Swift):import XCTest class RunnerUITests: XCTestCase { func testScreenshot() { let app = XCUIApplication() setupSnapshot(app) app.launch() // Navigate to screen snapshot("01Home") // Example: tap a button, then capture app.buttons["Next"].tap() snapshot("02Details") } } Fastfilelane for iOS:lane :ios_screenshots do capture_screenshots( devices: ["iPhone 14 Pro", "iPad Pro (12.9-inch) (6th generation)"], languages: ["en-US", "de-DE"] ) end
Android – screengrab
- Add
screengrabdependency inandroidTest:androidTestImplementation 'tools.fastlane:screengrab:2.1.1' - Example test in
android/app/src/androidTest/java/.../MainActivityTest.java:import com.facebook.testing.screenshot.Screenshot; import tools.fastlane.screengrab.Screengrab; import tools.fastlane.screengrab.locale.LocaleTestRule; import org.junit.Rule; import org.junit.Test; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.matcher.ViewMatchers.withId; public class MainActivityTest { @Rule public LocaleTestRule localeTestRule = new LocaleTestRule(); @Test public void testTakeScreenshot() { Screengrab.screenshot("home_screen"); } } Fastfilelane for Android:lane :android_screenshots do screengrab( locales: ["en-US", "de-DE"], devices: ["Pixel_5"], clear_previous_screenshots: true ) end
📸 Step 4. Run Screenshot Capture
- iOS:
cd ios fastlane ios ios_screenshots - Android:
cd android fastlane android android_screenshots
This will launch simulators/emulators, run your test flows, and save screenshots.
📸 Step 5. Add Device Frames (Optional, but nice for App Store)
Use frameit:
fastlane frameit
It overlays your screenshots onto Apple device frames.
📂 Where screenshots go
They’ll be stored under:
- iOS →
ios/screenshots/ - Android →
android/fastlane/metadata/android/en-US/images/phoneScreenshots/
You can upload them directly to App Store Connect / Google Play Console.
What are the Flutter way to make screenshots
🖼️ 1. Programmatically capture a widget (best for in-app screenshots)
You can wrap any widget in a RepaintBoundary and convert it to an image:
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
class ScreenshotExample extends StatefulWidget {
@override
_ScreenshotExampleState createState() => _ScreenshotExampleState();
}
class _ScreenshotExampleState extends State<ScreenshotExample> {
final GlobalKey _globalKey = GlobalKey();
Future<void> _captureAndSave() async {
RenderRepaintBoundary boundary =
_globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
ui.Image image = await boundary.toImage(pixelRatio: 3.0);
ByteData? byteData =
await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List();
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/screenshot.png');
await file.writeAsBytes(pngBytes);
print("Screenshot saved: ${file.path}");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Flutter Screenshot")),
body: Center(
child: RepaintBoundary(
key: _globalKey,
child: Container(
padding: EdgeInsets.all(20),
color: Colors.amber,
child: Text("Hello Screenshot!"),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _captureAndSave,
child: Icon(Icons.camera),
),
);
}
}
👉 This captures only the widget inside the RepaintBoundary, not the whole screen.
🖼️ 2. Capture the whole screen
Wrap the entire Scaffold or app in a RepaintBoundary, or use a screenshot package (see below).
🖼️ 3. Use packages
screenshot
Simplifies capturing any widget or screen. Example:ScreenshotController screenshotController = ScreenshotController(); Screenshot( controller: screenshotController, child: MyWidget(), ); // Later Uint8List image = await screenshotController.capture();widgets_to_image
Similar, but with simpler widget-to-image mapping.flutter_native_screenshot
Captures the entire screen (not just widgets). Useful if you want a system-level screenshot.
What about with maestro.dev framework
Using Maestro.dev is a modern, Flutter-friendly way to automate screenshots (and UI tests) across devices and languages — similar to Fastlane’s snapshot/screengrab, but simpler and cross-platform.
Let’s go through how to do Flutter screenshots with Maestro step-by-step 👇
🧩 What Maestro Is
Maestro is a lightweight UI testing & automation framework for mobile apps (Android & iOS).
It can:
- Launch your Flutter app
- Simulate taps, text inputs, and navigation
- Capture screenshots programmatically
- Work in CI pipelines (GitHub Actions, etc.)
⚙️ Step 1: Install Maestro CLI
Run:
curl -Ls "https://get.maestro.mobile.dev" | bash
Then verify:
maestro --version
⚙️ Step 2: Connect Your App
- Run your Flutter app in debug or install the
.apk/.ipa.flutter build apk --debug maestro devices maestro appsThis lists connected devices and apps (you can get the bundle ID).
- Optionally, install the app automatically:
maestro install build/app/outputs/flutter-apk/app-debug.apk
📜 Step 3: Write a Maestro Flow (test script)
Create a folder:
.maestro/
└── main_flow.yaml
Example (main_flow.yaml):
appId: com.example.myapp
name: Take screenshots of main screens
onFlowStart:
- clearState
- launchApp
steps:
- takeScreenshot: home_screen
- tapOn: "Next"
- takeScreenshot: details_screen
- tapOn: "Profile"
- takeScreenshot: profile_screen
This script will:
- Launch your Flutter app
- Navigate between screens (based on visible text or accessibility labels)
- Save screenshots automatically
📸 Step 4: Run the Flow
Run:
maestro test .maestro/main_flow.yaml
Screenshots will be saved by default in:
maestro/results/<timestamp>/screenshots/
⚙️ Step 5: (Optional) Multi-language or Device Setup
You can run multiple locales or devices using CLI arguments or in CI:
maestro test .maestro/main_flow.yaml --env LANG=en-US
maestro test .maestro/main_flow.yaml --device "Pixel_5"
In GitHub Actions, you can even generate screenshots for all locales and upload them as artifacts.
💡 Step 6: Add Accessibility IDs in Flutter
Maestro locates widgets by text or accessibility labels.
For robust automation, add Key or semantics labels:
Text('Next', key: Key('nextButton'));
Then Maestro can reliably tap:
- tapOn: "nextButton"
✅ Why Maestro Is Great for Flutter
- Works seamlessly on Android + iOS
- No need for native test frameworks (like Espresso/XCUITest)
- Cross-platform YAML syntax
- Works well in CI/CD pipelines
- Can generate consistent screenshots for app stores
- Side bonus is – better accessibility of your app
