Skip to content
FlightStack Docs
Sign in Start free

ScreenStack integration

ScreenStack is VooStack’s visual-regression product. The FlightStack integration captures Flutter test screenshots in CI, diffs them against your baseline branch, and (optionally) pushes the approved set to App Store Connect and Google Play.

  • Pixel diffs on every PR. Side-by-side view of changed widgets, light vs. dark, every device profile you configure.
  • Approval gates. Pull requests can be blocked until visual changes are explicitly approved.
  • Store sync. When you’re ready to ship, push the approved set directly to App Store Connect and Play Console — no manual screenshot wrangling.
  1. Create a ScreenStack project and link it to your FlightStack org.
  2. Instrument your tests with the screenstack Flutter package.
  3. Add the ScreenStack job to your CI pipelines.
  4. (Optional) Add the Upload Store Screenshots job to your release pipelines.

In the FlightStack dashboard, Settings → Integrations → ScreenStack. Authorize the connection, pick the project you want this org to default to. You can override per pipeline.

test/screens/login_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:screenstack/screenstack.dart';
import 'package:my_app/login_page.dart';
void main() {
testWidgets('Login — empty', (tester) async {
await tester.pumpWidget(const MyApp(home: LoginPage()));
await ScreenStack.capture(tester, 'login/empty');
});
testWidgets('Login — error', (tester) async {
await tester.pumpWidget(const MyApp(home: LoginPage(error: 'bad creds')));
await ScreenStack.capture(tester, 'login/error');
});
}

ScreenStack.capture() renders the current widget tree at the configured device profile + theme variant and queues it for upload. The actual upload happens through the job, so unit tests still run offline.

┌──────────┐ ┌────────┐ ┌──────────────┐
│ On PR │───▶│ Tests │───▶│ Screen Stack │
└──────────┘ └────────┘ └──────────────┘
┌──────────────┐
│ Notification │
│ (Slack PR) │
└──────────────┘

See the ScreenStack job for inputs.

┌────────────┐ ┌────────────┐ ┌──────────────┐ ┌────────────────────┐
│ On Tag │───▶│ Build iOS │───▶│ Screen Stack │───▶│ Approval │
│ v* │ │ │ │ │ │ "ship screenshots?"│
└────────────┘ └────────────┘ └──────────────┘ └────────────────────┘
┌────────────────────┐
│ Upload Store │
│ Screenshots │
└────────────────────┘

See Upload Store Screenshots.

FamilyProfileUse for
iPhone 6.7”iphone-15-pro-maxRequired for App Store submissions
iPhone 6.5”iphone-15-proRequired for older devices
iPad 13”ipad-13Required if you target tablet
Pixelpixel-7Required for Play Store submissions
Android tabletnexus-tabletRequired if you target Android tablet

Marketing-quality screenshots usually need a separate, polished pipeline run with mocked data and explicit pumpAndSettle() calls. Don’t ship debug-mode screenshots to the App Store.

Captures missing on the dashboard Check the agent logs for screenstack/upload failures. The most common cause is an expired ScreenStack project token — re-authorize the integration in dashboard settings.

Random diffs from font rendering Lock the test font with --dart-define=FONT=NotoSans or use Flutter’s loadAppFonts() in your test harness — system fonts drift between CI agents.