Automation

Fastlane Screenshots: Capture, Localize, Design & Upload

Jul 29, 202610 min readYannickYannick
Fastlane screenshot automation pipeline from UI test capture through design and App Store upload
Fastlane screenshot automation pipeline from UI test capture through design and App Store upload

Fastlane can automate the repetitive parts of producing App Store screenshots: launching an app across simulator and language combinations, navigating to predictable UI states, capturing raw screens, and uploading approved files to App Store Connect.

It does not automatically solve the entire creative workflow. Capture, design, localization, validation, and upload are separate jobs. The reliable system is the one your team can rerun after an interface change without rebuilding hundreds of assets by hand.

Separation of concerns

Capture technically. Design deliberately. Upload reviewed assets.

01

Capture

Use deterministic UI tests and stable screenshot names.

02

Design

Turn raw UI into an editable, localized marketing story.

03

Deliver

Validate a complete approved directory before upload.

The Fastlane screenshot pipeline

Fastlane screenshot pipeline from deterministic app state through capture, design, validation, and upload
Keep raw capture, creative production, and upload as explicit stages. A failure in one stage should not silently leak stale or incomplete files into the next.
StageRecommended ownerOutput
Test data and app stateApp code plus UI-test fixturesPredictable, review-safe UI
Raw iOS captureFastlane snapshotScreens grouped by language and device
Raw Android captureFastlane screengrabScreens grouped by locale and device
Basic frame and text compositionFastlane frameitFramed or titled screenshots
Flexible design and localizationAppLaunchFlow or another visual workflowStore-ready creative variants
iOS uploadFastlane deliverAssets in App Store Connect

This guide concentrates on iOS because “Fastlane screenshots” usually refers to snapshot. Android uses screengrab with Espresso or UI Automator-based tests and different store requirements.

When screenshot automation is worth it

Five screenshots × three devices × eight languages × two visual variants creates 240 outputs before Product Page Optimization or custom product pages. The difficult part is not multiplication; it is keeping state, copy, order, and creative consistent.

Fastlane is usually worth maintaining when:

  • the app supports several languages;
  • UI changes ship regularly;
  • deterministic UI tests already exist;
  • more than one person must regenerate screenshots;
  • the team needs a reviewable capture artifact;
  • manual capture mistakes cost more than the test path.

Manual capture can still be reasonable for one device, one language, or a prototype whose UI is changing faster than the screenshot test can remain stable.

Prerequisites

  1. A Mac with a compatible Xcode installation and command-line tools.
  2. A working iOS project or workspace.
  3. A shared scheme containing an enabled UI-test target.
  4. A managed Ruby environment and pinned Fastlane installation.
  5. Predictable test data that does not depend on production accounts.
  6. A device and locale matrix aligned with the current store strategy.

Use Bundler so local and CI behavior share the same Fastlane version:

source "https://rubygems.org"

gem "fastlane"
bundle install
bundle exec fastlane --version

Record the tested Xcode, Ruby, Bundler, and Fastlane versions with the pipeline. The examples below have been syntax-checked and compared with the current action documentation, but project identifiers and installed simulator names must match your own environment.

Set up snapshot

  1. Create a UI-test target.
  2. Run the snapshot initializer from the iOS project directory.
  3. Add the generated SnapshotHelper.swift to the UI-test target.
  4. Use a shared scheme that builds the UI-test target.
  5. Call setupSnapshot before launching the app.
  6. Call snapshot at each stable state.
bundle exec fastlane snapshot init

Example UI test

import XCTest

final class StoreScreenshotTests: XCTestCase {
    private var app: XCUIApplication!

    override func setUpWithError() throws {
        continueAfterFailure = false
        app = XCUIApplication()
        setupSnapshot(app)
        app.launchArguments += ["-uiTesting", "-screenshotMode"]
        app.launch()
    }

    func testStoreStory() throws {
        XCTAssertTrue(
            app.staticTexts["dashboard-title"]
                .waitForExistence(timeout: 10)
        )
        snapshot("01-dashboard")

        app.buttons["create-project"].tap()
        XCTAssertTrue(
            app.staticTexts["project-editor-title"]
                .waitForExistence(timeout: 10)
        )
        snapshot("02-create-project")

        app.buttons["preview-result"].tap()
        XCTAssertTrue(
            app.staticTexts["preview-title"]
                .waitForExistence(timeout: 10)
        )
        snapshot("03-preview")
    }
}

This is an illustrative structure, not a drop-in test. Accessibility identifiers, navigation, launch arguments, and readiness conditions must match the real app.

Make screenshot data deterministic

A simulator should not depend on yesterday's backend data, a developer's account, or a request that may finish after capture. Add an explicit screenshot mode:

let isScreenshotMode =
    ProcessInfo.processInfo.arguments.contains("-screenshotMode")

In that narrow mode the app can:

  • load local fixtures;
  • use a stable date and locale-safe sample content;
  • disable unpredictable notifications and nonessential animation;
  • avoid personal information;
  • reset to the same initial state for every run.

Avoid fixed sleeps. Wait for a meaningful state or expose a testable readiness signal:

let dashboard = app.staticTexts["dashboard-title"]
XCTAssertTrue(dashboard.waitForExistence(timeout: 10))
snapshot("01-dashboard")

Configure the Snapfile

scheme("StoreScreenshotUITests")
workspace("./ExampleApp.xcworkspace")

devices([
  "iPhone 16 Pro Max",
  "iPhone 16 Pro",
  "iPad Pro 13-inch (M4)"
])

languages([
  "en-US",
  "de-DE"
])

output_directory("./fastlane/raw_screenshots")
clear_previous_screenshots(true)
skip_open_summary(true)
stop_after_first_error(true)
override_status_bar(true)

launch_arguments([
  "-uiTesting -screenshotMode"
])

Simulator names depend on installed Xcode runtimes. Confirm available destinations on the local machine and CI runner. Use stop-after-first-error for release output, and clear or isolate each run so old files cannot make a partial capture look complete.

bundle exec fastlane snapshot

Review the generated HTML summary before moving any images into the design or upload stages.

Use screenshot names as a stable contract

Encode story order and meaning:

01-dashboard
02-create-project
03-preview
04-localize
05-export

Avoid names tied to temporary implementation details. A stable name lets the design stage replace the raw capture while preserving the intended story position.

Choose between frameit and a visual design workflow

frameit can add supported device frames, backgrounds, padding, and localized text. It works well when one repeatable configuration expresses the layout and the supported frames match the target devices.

Use a visual workflow when:

  • different screens need different compositions;
  • copy and hierarchy change by story position;
  • the team needs several creative directions or product-page variants;
  • marketing teammates should edit without changing Ruby configuration;
  • localization requires visual review and layout adjustment.

A practical hybrid workflow

  1. Capture current localized UI with snapshot.
  2. Review the Fastlane summary.
  3. Import selected raw screens into AppLaunchFlow.
  4. Apply one reusable visual system and benefit-first story.
  5. Localize the complete composition.
  6. Export exact store sizes.
  7. Validate file counts, dimensions, order, and locale.
  8. Place only approved exports in the upload directory.
  9. Upload with deliver.

Keep raw and approved assets separate

fastlane/
  raw_screenshots/
  screenshot_review/
  screenshots/
  • raw_screenshots: generated by snapshot;
  • screenshot_review: design exports waiting for review;
  • screenshots: approved, upload-ready assets only.

The upload lane should read only from the approved directory.

Upload screenshots with deliver

platform :ios do
  desc "Upload approved screenshots without metadata, binary, or review submission"
  lane :upload_store_screens do
    upload_to_app_store(
      screenshots_path: "./fastlane/screenshots",
      skip_binary_upload: true,
      skip_screenshots: false,
      skip_metadata: true,
      overwrite_screenshots: true,
      submit_for_review: false,
      force: false
    )
  end
end

Every option shown is present in Fastlane's current action documentation, and the Ruby sample passes syntax validation. Still inspect the installed action before a real run:

bundle exec fastlane action upload_to_app_store

Be deliberate with overwrite_screenshots

Fastlane documents overwrite mode as clearing previously uploaded screenshots before uploading the new set. Before enabling it:

  • verify all intended locales, devices, story positions, and dimensions;
  • reject unexpected or duplicate files;
  • save a review artifact;
  • confirm the exact app and editable version;
  • keep submit_for_review disabled unless that action is explicitly intended.

If authentication works but screenshot editing fails, inspect the version state and account role before assuming the lane is incorrect.

Authenticate safely

Prefer scoped, noninteractive App Store Connect credentials appropriate for this operation. Keep secrets out of the repository, screenshots, CI logs, shell history, and generated summaries. Separate capture from upload so contributors who regenerate images do not automatically receive production credentials.

Run the pipeline in CI

capture
  ├─ build and run UI tests
  ├─ generate raw screenshots
  └─ publish raw files and HTML summary

design/localization
  ├─ transform reviewed raw files
  └─ produce approved store assets

upload
  ├─ validate approved assets
  ├─ authenticate to App Store Connect
  └─ upload without automatic review submission

Pin the macOS runner, Xcode version, simulator runtimes, Ruby version, Bundler lockfile, Fastlane version, and app commit. Provenance makes unexpected visual changes explainable.

Validate before upload

  • expected locales, device classes, and story positions;
  • nonzero file size and allowed extensions;
  • required dimensions and consistent orientation;
  • no duplicates, alpha channels, or unexpected leftovers;
  • a complete target matrix and correct ordering.

Apple's current screenshot specification allows one to ten screenshots and defines accepted formats and dimensions by device class. Use the dedicated App Store screenshot specifications guide instead of copying a device table that will age separately.

Product Page Optimization and custom product pages

Keep capture identity separate from creative destination. The same raw dashboard can feed a default page, a benefit-led PPO treatment, and several audience-specific custom product pages:

capture: 01-dashboard
creative: default-v1
creative: ppo-benefit-led-v1
creative: cpp-freelancers-v1
creative: cpp-agencies-v1

Do not make the UI test know about every campaign. Keep capture stable and let the creative layer map screens into variants. Read the App Store screenshot A/B testing guide and the custom product page guide for the strategy around those destinations.

Flutter apps and Fastlane screenshots

Fastlane operates around the built iOS app, Xcode project, simulator, and test path. A Flutter app can use Fastlane for capture and upload, but snapshot does not replace a working iOS UI-test target or another tested capture integration. Do not promise a one-command Flutter workflow unless that exact stack has been run and documented.

Troubleshooting Fastlane screenshots

SymptomLikely causeInspect
No screenshotsHelper or invocation is wrongsetupSnapshot, target membership, and command
One device or locale is missingUI test failed and the run continuedLogs and stop-after-first-error
Old screenshots reappearPrevious output was not clearedRun isolation and output directory
Loading state is capturedNetwork fixture or weak readiness conditionLocal fixtures and state-specific waits
Wrong languageLocale override or missing localizationArguments and bundled translations
Text clips in one localeLayout does not handle expansionPer-locale summary and design template
frameit output is rejectedFinal canvas is not a valid store sizeStore-sized composition and export
Upload replaces too muchOverwrite used with an incomplete directoryComplete approved target matrix

A safer Fastlane screenshot lane

platform :ios do
  desc "Capture raw localized screenshots"
  lane :capture_store_screens do
    capture_ios_screenshots(
      clean: true,
      clear_previous_screenshots: true,
      skip_open_summary: true,
      stop_after_first_error: true,
      output_directory: "./fastlane/raw_screenshots"
    )
  end

  desc "Upload already reviewed store assets"
  lane :upload_store_screens do
    # Run a project-specific validation action or script here.
    upload_to_app_store(
      screenshots_path: "./fastlane/screenshots",
      skip_binary_upload: true,
      skip_metadata: true,
      skip_screenshots: false,
      overwrite_screenshots: true,
      submit_for_review: false,
      force: false
    )
  end
end

Capture and upload are intentionally separate. The sample passes Ruby syntax validation, but a production team must run it against its recorded iOS environment and a safe editable App Store version before relying on the upload result.

Fastlane screenshot FAQ

What is the difference between snapshot, frameit, and deliver?

snapshot uses UI tests to capture localized app screens across simulator and language combinations. frameit applies device frames, backgrounds, and optional localized text. deliver, exposed through upload_to_app_store, uploads App Store metadata and screenshots.

Does Fastlane automatically design App Store screenshots?

frameit supports frames, backgrounds, padding, and title or keyword text. More flexible compositions, copy editing, creative variants, and visual localization may be easier in a dedicated design workflow.

Can Fastlane localize screenshots?

snapshot can capture the app in multiple configured languages, and frameit supports localized title and keyword strings. You still need to review the app content and marketing composition in each locale.

Can Fastlane upload screenshots without uploading a binary?

Yes. Fastlane documents metadata- and screenshot-only workflows. Configure the lane to skip the binary upload and test it against a noncritical editable version before depending on it.

Does Fastlane work with Flutter?

Fastlane can automate the iOS and Android release surfaces around a Flutter app. For snapshot, the team still needs a working iOS capture path, typically involving an Xcode UI-test target or a tested custom integration.

Can Fastlane generate custom product page screenshots?

Fastlane can help capture raw UI and automate App Store operations, but the team still needs an explicit asset and upload workflow for each product-page destination. Verify current Fastlane and App Store Connect API support for the intended operation.

Is Fastlane worth maintaining for a small app?

It is usually worthwhile when the app has several locales, devices, frequent UI changes, or an existing UI-test foundation. For a single-language early-stage app, manual capture and a repeatable design workflow may cost less.

Build a pipeline your team can rerun

Use snapshot to produce current, consistent raw screens. Keep fixtures and names stable. Design and localize the marketing story in a workflow the right teammates can edit. Validate the complete output, then let deliver upload only reviewed assets.

Next, import the captures into the AppLaunchFlow screenshot generator to build consistent layouts and localized variants while preserving the raw capture contract.

Sources and further reading

Related Articles

Generate App Store & Play Store screenshots with AI, then refine every detail.

Make store-ready screenshots in minutes