October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
automated screenshots

How to Automate Screenshots in Flutter (Integration Tests, Goldens, and CI)

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The most reliable way to automate screenshots of a Flutter app running on Android, iOS, or the web is integration_test. Start the app in an integration test, wait for a settled frame with pumpAndSettle(), and call takeScreenshot(). The test driver receives PNG bytes on the host, where you can save them as CI artifacts. Android targets also require convertFlutterSurfaceToImage() before the first pump and capture.

Choose the screenshot layer before writing code

Different screenshot goals call for different Flutter tools. A widget golden is not a substitute for a device screenshot, and a store-asset generator is not the same as a visual-regression test.

Goal Best fit What you gain Trade-off
Check a widget or screen against a baseline quickly Flutter golden test Fast, repeatable widget-level comparisons Does not exercise real-device system rendering
Capture the rendered app on Android, iOS, or web integration_test Uses the target runtime, device, emulator, or browser Needs a target environment and takes longer than a widget test
Generate framed, multi-device store images golden_screenshot Device profiles, custom devices, frames, and store-oriented output Adds package configuration and generated golden files
Run the same flow across many device models integration_test plus Firebase Test Lab Broad device and OS coverage More infrastructure and execution cost

Set up an integration screenshot test

1. Add the test dependencies

In pubspec.yaml, place both packages under dev_dependencies:

dev_dependencies:
  flutter_test:
    sdk: flutter
  integration_test:
    sdk: flutter

Run flutter pub get. Keep the Flutter SDK and these dependencies pinned in CI so a framework update does not silently change pixels.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Create the test entry point

Create integration_test/screenshot_test.dart. The following example starts the production app, waits for its first stable frame, and captures the home screen:

import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart' as app;

void main() {
  final binding =
      IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('capture home screen', (tester) async {
    app.main();

    // Required when the target is Android. Keep this before the first pump.
    await binding.convertFlutterSurfaceToImage();

    await tester.pumpAndSettle();
    await binding.takeScreenshot('home');
  });
}

Replace my_app with your package name. takeScreenshot receives a deterministic name; use names such as home-light-en-US when locale, theme, or state is part of the matrix.

3. Make the state deterministic

  • Seed a known account and database state instead of using data from a previous run.
  • Mock or await network requests before capture.
  • Disable tutorial overlays, random content, and time-dependent labels.
  • Navigate to the exact screen and set the intended orientation and theme.
  • Wait for animations and lazy-loaded images. pumpAndSettle is useful only when the app can actually become idle; an endlessly repeating animation requires a targeted pump or a test-only animation switch.

Save the PNG bytes on the host

The screenshot is returned to the host process rather than automatically written into the app’s sandbox. Add a driver such as test_driver/integration_test.dart:

import 'dart:io';

import 'package:integration_test/integration_test_driver_extended.dart';

Future<void> main() async {
  await integrationDriver(
    onScreenshot: (name, bytes, [args]) async {
      File('$name.png').writeAsBytesSync(bytes);
      return true;
    },
  );
}

The callback runs on the host, so it can read CI environment variables, create directories, attach metadata, or upload the byte buffer to an artifact store. The callback receives the screenshot name, PNG bytes, and optional JSON-serializable arguments.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run locally

Start an emulator, simulator, or browser target, then run the integration test with the driver pattern:

flutter drive 
  --driver=test_driver/integration_test.dart 
  --target=integration_test/screenshot_test.dart

Use the current integration-test runner supported by the Flutter SDK version pinned by your project. On a physical device, enable the platform’s developer mode and USB or network debugging, then verify that flutter devices lists it before starting the run.

Capture more than one screen

Capture after an interaction

Drive the UI exactly as a user would, settle again, and then capture:

testWidgets('capture checkout states', (tester) async {
  app.main();
  await binding.convertFlutterSurfaceToImage();
  await tester.pumpAndSettle();
  await binding.takeScreenshot('cart');

  await tester.tap(find.text('Checkout'));
  await tester.pumpAndSettle();
  await binding.takeScreenshot('checkout');
});

Use finders that identify semantics or stable labels rather than coordinates. A coordinate tap can break when text scale, device size, or system insets change.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for a known condition

If the screen loads asynchronously, wait for a visible marker before capturing. For example, poll until a success label appears, then call pumpAndSettle. For network-heavy screens, make the test data local or inject a fake client; a fixed sleep alone creates slow and flaky tests.

Keep names and paths collision-free

Include the dimensions of your matrix in the name or output directory: home-pixel7-dark-de-DE.png. If parallel jobs write to one workspace, give each job its own directory or include the device identifier. Deterministic names make artifact comparison and cleanup predictable.

Golden tests versus device screenshots

Use ordinary Flutter goldens when the question is “did this widget’s pixels change relative to its baseline?” They are quick and deterministic, but they do not reproduce every detail of Android, iOS, or browser rendering.

Use integration_test when you need the app as rendered by the target runtime: platform fonts, system composition, plugins, navigation, permissions, and real image loading. When an integration test compares goldens on Android or iOS, Flutter’s documented default comparator proxies to the host filesystem; configure a custom comparator only when your workflow needs different storage or comparison behavior.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For framed store artwork, golden_screenshot adds common device profiles, custom devices, frames, and store-oriented output. Regenerate its baselines with:

flutter test --update-goldens

Keep generated goldens under version control when they are reviewable test assets. A baseline update should be a deliberate change, not an automatic response to a failing CI job.

Build a device matrix in CI

  1. Pin inputs. Pin the Flutter SDK, lock dependencies, and record the target OS or browser versions.
  2. Reset state. Clear app data, seed deterministic fixtures, and set the locale, theme, orientation, and text scale explicitly.
  3. Launch targets. Start the selected emulator, simulator, browser, or hosted device and wait until it is ready.
  4. Run the test. Invoke flutter drive or the integration-test runner with the screenshot test and host driver.
  5. Wait, then capture. Await network and lazy images, settle animations, and call takeScreenshot only after the intended state is visible.
  6. Publish artifacts. Save the driver callback’s PNG bytes and retain logs alongside them.
  7. Compare where required. Run golden comparisons for visual regression; do not use a screenshot merely as a pass/fail signal without a baseline or review step.
  8. Repeat the matrix. Run the same flow for every locale, theme, orientation, and device profile you intend to publish.

For broad hardware coverage, Flutter’s integration-test guidance names Firebase Test Lab as an option. It increases setup and infrastructure complexity, so begin with a small, representative matrix and expand when a device-specific risk justifies it.

Troubleshoot failed or inconsistent captures

The screenshot is blank or never arrives

On Android, confirm that convertFlutterSurfaceToImage() is called before the first pump and capture. Also verify that the driver is the extended integration-test driver and that the host callback returns true. A target that crashed or lost its connection will not produce valid PNG bytes; inspect device logs before changing timing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The image captures too early

Replace arbitrary delays with a deterministic readiness condition, then call pumpAndSettle. Ensure that image providers, fonts, and API requests have completed. If an infinite animation prevents settling, disable it in the test configuration or pump a bounded number of frames after the required content appears.

Runs pass locally but fail in CI

Compare Flutter and OS versions, locale, text scale, GPU mode, and font availability. Reset app data between jobs, avoid wall-clock-dependent content, and store the failing screenshot and logs as artifacts. A host callback can include CI metadata in its output path without changing the bytes.

Golden comparisons change unexpectedly

Check whether a framework, font, device pixel ratio, or platform renderer changed. Review the diff before running --update-goldens; updating baselines hides regressions if done automatically.

Only some devices fail

Look for assumptions about safe areas, keyboard visibility, orientation, permissions, and platform-specific fonts. Capture the same named state on the failing target and a known-good target, then compare viewport and system-inset information before changing application layout.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Performance, reliability, and cost considerations

Integration captures are slower than widget goldens because they boot an app and a target runtime. Reduce wasted runs by using goldens for every pull request and reserving a device matrix for release branches or targeted changes. Reuse a warmed emulator when isolation permits, but reset application state so one test cannot contaminate another.

There is no universal performance or success-rate number for this workflow: duration depends on the app, device, image and network workload, and CI environment. Measure your own pipeline, retain timestamps, and treat a timeout as an actionable failure rather than silently accepting a missing image.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a screenshot of a web page rather than the Flutter runtime itself, ScreenshotNeo provides a single HTTP request. It can accept cookie and consent banners like a visitor, then remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.

See the parameter reference and integration details in the ScreenshotNeo documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
require('fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Every plan includes its features: full-page and element captures, device and viewport controls, retina scale, PDF options, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Existing parameter names used by other screenshot APIs also work, which can simplify migration.

Plan Included screenshots Price
Free 1,000 per month $0, no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Yearly billing gives two months free. Start with 1,000 free screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Practical checklist

  • Dependencies: integration_test and flutter_test are in dev_dependencies.
  • Binding: IntegrationTestWidgetsFlutterBinding.ensureInitialized() runs before tests.
  • Android: surface conversion runs before pumping.
  • Readiness: network, images, fonts, and animations are settled.
  • Names: screenshot names encode the state and matrix dimensions.
  • Driver: host callback writes PNG bytes and returns success.
  • CI: SDK, device, locale, theme, orientation, and test data are controlled.
  • Baselines: golden updates are reviewed rather than generated blindly.

Frequently Asked Questions

Can integration_test capture Flutter Web screenshots?

Yes. Flutter documents integration-test screenshots for a Web browser as well as Android and iOS; run the test against the browser target and keep the same host-side callback.

Where are screenshot files created?

The app sends PNG bytes to the host. Your driver callback decides the path, workspace, or artifact store; the example writes name.png in the driver’s working directory.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should App Store screenshots use golden tests?

Use a real-device integration capture for runtime-faithful images, then use golden_screenshot when you need standardized frames and store-oriented device output.

Why does a screenshot name need to be unique?

The name is the identifier passed to the host callback. Unique, deterministic names prevent matrix jobs from overwriting one another and make artifacts easy to match to a test state.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.