· Workflow · 9 min read

How to Create App Store Screenshots for a React Native App (2026)

How to Create App Store Screenshots for a React Native App (2026)
TL;DR. React Native gives you no first-party screenshot pipeline. Your realistic options for capturing the raw frames are Fastlane (XCUITest on iOS, screengrab/Espresso on Android), Detox (which is built for RN and the easiest of the three), or just capturing manually from the simulator. Whichever you pick only produces bare app screenshots — turning those into a store-ready carousel with captions, device frames, and localized variants is a separate marketing step. For most teams shipping a few times a year, manual capture plus browser composition beats a day of Fastlane setup.

Here is the thing nobody tells you when you ship your first React Native app to the App Store: there is no built-in way to generate the screenshots the store wants. Native iOS developers reach for Xcode's UI test recorder; native Android developers have Espresso baked into the build. React Native sits on top of both, with your actual app logic running in JavaScript — and none of that tooling knows your JS exists. You are left to bridge the gap yourself.

This post walks through the approaches that actually work in the New Architecture era (RN 0.7x and up, 2026), with concrete commands. It is honest about the costs, because every one of these options has a real one. Then it covers the part that comes after capture — the marketing composition and localization — which is a genuinely separate problem regardless of how you grab the source frames.

The real problem: no first-party pipeline

App Store Connect wants screenshots at exact pixel dimensions, ideally one set per device class and one set per locale you support. Google Play wants its own sizes. A native iOS project can drive the simulator through XCUITest and dump frames; React Native technically can too, but the test you write runs against the native shell — the bundled binary — not against your JavaScript components directly. You are automating a black box that happens to be rendering your JS.

That distinction matters more than it sounds. It means your screenshot automation breaks for reasons that have nothing to do with your React code (a Metro bundler that wasn't running, a simulator stuck on a permission dialog, a native build that drifted from your JS) and it means the learning curve is the curve of two native test frameworks, not your familiar RN stack. There are three serious ways through this. Pick based on how often you ship.

Option 1 — Fastlane snapshot (iOS) and screengrab (Android)

Fastlane is the canonical open-source mobile automation framework, and its screenshot modules are the most battle-tested option. They are also the most work to set up for React Native, because they were built for native projects and only tolerate RN.

iOS, via snapshot. You add a UI testing target in Xcode and write XCUITest cases in Swift that drive the app to each screen you want to capture. fastlane snapshot init drops a Snapfile and a SnapshotHelper.swift into your fastlane/ folder. In your test you call setupSnapshot(app), launch, and then snapshot("01_home") at each state. You run it from the terminal with fastlane snapshot — not from inside Xcode, which won't produce correct output. It loops over every simulator and locale in your Snapfile and writes PNGs to fastlane/screenshots/.

The React Native wrinkle: snapshot launches the compiled app, which in debug needs the Metro bundler already running. So your Fastfile (or a wrapper script) has to start Metro first — the common trick is launching npx react-native start in a background tmux session before calling snapshot, then tearing it down after. Release builds with the JS bundle embedded avoid this but cost you a full release build per run.

Android, via screengrab. Different framework entirely: screengrab uses Espresso. You add Screengrab.screenshot("name") calls inside JUnit instrumented tests, declare permissions (DISABLE_KEYGUARD, WAKE_LOCK, CHANGE_CONFIGURATION, and storage perms), build a debug APK and a test APK with ./gradlew assembleDebug assembleAndroidTest, and run fastlane screengrab. Output lands in fastlane/metadata/android/. As with iOS, Metro and the emulator must already be up — screengrab does not start them for you.

Strengths:

  • CI-integrated and drift-proof. Wire it into your pipeline and screenshots regenerate on every release build, always matching the shipped app.
  • True per-locale rendering. Each locale runs in the simulator/emulator with its real locale settings, so dates, numbers, and currency render natively — not faked in a design tool.
  • Free, open source, mature. No subscription, huge community, well-trodden failure modes.

Weaknesses (be honest with yourself here):

  • You maintain two native test suites. XCUITest in Swift for iOS, Espresso/JUnit in Kotlin/Java for Android — as an RN developer, that may be two unfamiliar stacks.
  • It tests the native shell, not your JS logic. The tests assert on rendered native views; they are not aware of your component tree.
  • Setup is a day or two the first time, and the Metro-bundler dance is a recurring source of flaky CI runs.
  • Output is raw frames. No captions, no device frames, no gradients, no carousel — just the bare app UI at simulator resolution.
  • Mac required for iOS. The simulator needs Xcode.

For a deeper side-by-side on the composition question specifically, see Fastlane snapshot vs no-code App Store screenshots and the Mokbi vs Fastlane comparison.

Option 2 — Detox screenshots (built for React Native)

Detox is a gray-box end-to-end testing framework made specifically for React Native, by the team at Wix. If you already run Detox for e2e tests, screenshots are nearly free, and the learning curve is the one you'd want to climb anyway — it's a JavaScript API, not Swift or Kotlin.

The capture call is a one-liner inside any test:

// full screen
const path = await device.takeScreenshot('01_home');

// a single element
await element(by.id('paywallRoot')).takeScreenshot('paywall');

Whether those images are kept as artifacts is governed by the --take-screenshots flag (none, failing, manual, or all) and configured in .detoxrc.js. In manual or all mode, passing tests write to <artifacts-location>/✓ [test name]/[name].png. You drive the app to each state with the same Detox matchers you'd use for assertions, then snapshot.

Strengths:

  • It's a JS API. You write tests in the language your app is written in — no second-language native test suite to own.
  • Gray-box, so it understands RN. Detox synchronizes with the app's bridge/JSI and waits for it to be idle, which makes screenshots far less flaky than blindly timed XCUITest waits.
  • One framework, both platforms. The same test file captures iOS and Android.
  • You probably already have it if you do e2e testing, in which case the marginal cost of screenshots is tiny.

Weaknesses:

  • Standing Detox up from scratch is non-trivial — native build config, a dedicated test build, and emulator/simulator setup. If you don't already run it, this is a real investment.
  • Locale handling is on you. Detox won't sweep every App Store locale automatically the way snapshot's Snapfile does; you script the locale changes or relaunch with different settings.
  • Output is still raw frames. Same as Fastlane — bare app UI, no marketing layer.
  • Screenshots can differ across host machines (a known Detox issue), which matters if you compare them in CI but is harmless for store assets.

Option 3 — Manual capture (simplest, and underrated)

Open the iOS Simulator or an Android emulator, drive your own app to each screen by hand, and grab the frame. On iOS, Cmd-S in the Simulator saves a correctly sized PNG to the desktop; xcrun simctl io booted screenshot home.png does the same from the terminal and is easy to script loosely. On Android, the emulator's camera button or adb exec-out screencap -p > home.png captures the screen. A physical device works too — capture, then AirDrop or transfer the files.

This is dismissed too quickly. It has zero setup, never breaks in CI because there is no CI, and for an app that ships a handful of times a year it is genuinely the fastest path to a set of source frames. The downside is obvious and real: it is manual, so it does not regenerate on its own, and if you change a screen your captures go stale until you redo them. For a five-screen carousel that's ten minutes of work per release — cheaper than maintaining test automation you run twice a year.

The part everyone forgets: composition and localization

Here is what unites all three options: every one of them produces raw app screenshots, and raw app screenshots are not what converts in the store. The App Store carousel that actually moves installs has a device frame around the screen, a one-line caption above it explaining the benefit, a background that isn't your app's white, and continuity across the five panels. None of the capture tools above produce any of that — they stop at the bare frame. That's not a flaw in them; it's a different job.

This is the step where Mokbi fits, and it's worth being precise about the boundary: it does not capture your source screenshots — that's the simulator, the device, or Fastlane/Detox above. What it does is the marketing-composition and localization layer that comes next. You drop your raw frames into a browser editor, wrap them in real device frames, add captions, lay out multi-panel carousels, then one-click translate the captions into 50 languages and batch-export at every store dimension. It's free to design with a watermarked preview; you pay once to export (Single €9.99, Pro €29.99 — no subscription). The reason it slots in cleanly is that it solves the problem your capture pipeline doesn't even attempt: turning a folder of PNGs into a localized, store-ready carousel without opening Photoshop or hand-resizing for 50 languages.

The realistic combined workflow

  1. Capture source frames. Pick one: Fastlane (snapshot + screengrab) on CI for frequent releases, Detox if you already run e2e tests, or manual simulator capture for infrequent ones. Output: a folder of raw PNGs per screen, per device.
  2. Compose, caption, and frame. Drop the raw frames into a browser editor. Add device frames, write the benefit captions, build the five-panel carousel, pick a background.
  3. Translate. One-click batch-translate the captions across 50 languages, then spot-check the languages that matter most to you by hand.
  4. Batch export. Export every locale at every required dimension for both App Store Connect and Google Play in one pass.
  5. Re-swap on the next release. Recapture the changed frames (rerun Fastlane/Detox, or grab them by hand), reopen the saved project, swap the screenshots, re-export. The caption and translation work is already done.

When you can skip the automation

If you ship one to three releases a year — which describes most indie React Native apps — the Fastlane or Detox setup cost almost never pays back. You'd spend a day wiring up XCUITest and the Metro-bundler dance to save ten minutes of manual capture twice a year. That math doesn't close. Capture by hand from the simulator, compose and localize in the browser, and you're done in less total time than the automation would take to configure once.

The automation earns its keep when you ship weekly or daily, when screenshot drift becomes a recurring bug, or when you run a portfolio of apps and the per-app capture cost multiplies. At that scale, Fastlane on CI (or Detox if it's already in your stack) is the right call for the capture step — and you still pair it with a browser composition tool for the marketing layer, because no capture pipeline produces a finished carousel.

Before you export anything, it's worth confirming the targets: the App Store screenshot sizes you actually need to upload, and the App Store screenshot requirements that get submissions rejected. Getting those right once saves a round-trip with App Review.

What to read next

Open the editor →