Expo App Store Screenshots: What EAS Submit Skips
.ipa/.aab to App Store
Connect and Play Console — and that is all it does for your listing. It does not generate,
upload, or manage your store screenshots. So Expo devs need a separate screenshot pipeline:
capture frames from a dev/preview build (simulator, emulator, or Maestro/Detox), then compose
and localize the marketing panels. This post covers the capture commands honestly, then where a
composition tool fits — it does not capture anything for you.
If you ship an Expo app, your release path probably ends in one line: eas submit.
It takes the build EAS produced and hands it to Apple or Google. Clean, boring, reliable. Then
you open App Store Connect to flip the build live and — the screenshot slots are empty. Every
time.
This trips up a lot of people because EAS feels like it does everything. It builds, it signs, it submits. Surely it handles screenshots too? It does not, and the docs say so plainly. This is not a bug or a missing feature you can flag on — it is simply outside what EAS Submit is for.
What EAS Submit actually does (and does not)
EAS Submit is a binary-delivery service. It uploads exactly one thing: your compiled app
archive — an .ipa for iOS, an .aab for Android — into the store's
processing pipeline. The Expo documentation is explicit about the boundary:
"EAS Submit uploads your binary but does not manage store listing metadata, screenshots, or release notes."
There is a sibling tool, EAS Metadata, that can automate parts of your App Store listing — app name, subtitle, localized descriptions, keywords, support URLs — from a config file. It is genuinely useful and worth setting up. But read its scope carefully: screenshots are not in it. EAS Metadata pushes text, not images. Your screenshots, on both stores, are still yours to produce and upload.
So the Expo screenshot problem splits into two distinct jobs, and it helps to keep them separate in your head:
- Capture — get raw frames of your app's real screens out of a build.
- Compose & localize — turn those raw frames into the framed, captioned, multi-language marketing panels the stores actually display.
EAS does neither. Expo's own store-assets guidance points you to capture frames yourself and design the panels in a tool like Figma. Let's walk both jobs with concrete commands.
Job 1: Capturing frames from a dev or preview build
You want screenshots of the actual app, so you need the app running somewhere you can capture it. For Expo that means a dev client or a preview build — not Expo Go, since Expo Go shows the Expo wrapper UI and your native config may differ. Build and run locally with the standard Expo commands:
npx expo run:ios— prebuilds native iOS, compiles, and boots your app in the iOS Simulator.npx expo run:android— the same for an Android emulator (or a connected device).
With the app on screen in the iOS Simulator, capture is a single command from your Mac terminal:
xcrun simctl io booted screenshot home.png
booted targets the currently running simulator and writes a pixel-exact PNG to your
working directory. Two flags matter for store work: --type=png (the default, and
what the stores want) and --mask=ignored versus --mask=black — the
mask controls whether the notch and rounded corners get rendered into the image. For App Store
uploads you generally want the flat rectangular pixels, then add the device frame later in
composition, so the unmasked capture is usually the right starting point.
On Android, capture straight off the emulator (or device) with adb:
adb exec-out screencap -p > home.png
Use exec-out, not shell screencap. The plain shell path pipes the PNG
through a pseudo-terminal that mangles the binary on some setups (you get a corrupt file with
stray carriage returns); exec-out streams the bytes straight through and is the
reliable form. If you run several emulators, target one with adb -s <serial> from
adb devices.
That is the whole manual-capture toolkit: two commands, one per platform, no dependencies beyond Xcode and the Android SDK you already have for an Expo native build.
Job 1, automated: Maestro or Detox
Tapping through to the right screen and running those commands by hand is fine for a handful of shots. Once you have eight screens across two device classes, or you want screenshots regenerated on every release so they never drift from the real UI, you automate the capture with an end-to-end testing tool that can drive the app and snap frames.
Maestro is the one Expo itself reaches for in its documented EAS Workflows examples. Flows are plain YAML, which keeps the barrier low. A flow that drives to a screen and captures it looks like this:
appId: com.you.yourapp --- - launchApp - tapOn: "Get started" - assertVisible: "Your dashboard" - takeScreenshot: dashboard
Run it with maestro test flows/home.yaml. The takeScreenshot command
writes a PNG to the test output directory (point MAESTRO_TESTS_DIR wherever you
want the assets to land). The same flows run in
CI on EAS Workflows — Expo's documented example builds an
.apk with an e2e-test build profile and then runs a
.maestro/ flow against it — so you can wire screenshot capture into the same job
that runs your e2e suite.
Detox is the other established option, with a tighter, more programmatic JavaScript API:
const path = await device.takeScreenshot('dashboard');
Be honest with yourself about the Detox-with-Expo setup, though. Detox does not officially
support Expo. In practice it works if you npx expo prebuild to generate the native
projects and build a release-style client (not a dev client) so the JS bundle is embedded —
then point Detox at that binary. It is more moving parts than Maestro's YAML, and the payoff is
Detox's stricter synchronization and assertion API. If you already run Detox, reuse it for
capture; if you are choosing fresh and your goal is store screenshots, Maestro is the lighter
path.
Job 1, manual: the right call for infrequent releases
Automation earns its keep when you ship often. If you cut one to three releases a year — which is most indie Expo apps — wiring up Maestro flows or a Detox config for screenshot capture is work you pay for once and barely amortize. For that cadence, just:
- Boot the build with
npx expo run:ios/run:android, seed it with realistic demo data. - Navigate to each hero screen by hand.
- Snap each one with the
simctl/adbcommand above.
Twenty minutes of clicking beats a half-day of test harness you will have forgotten how to maintain by the next release. There is no shame in manual capture — the stores cannot tell how the PNG was made.
Job 2: Composition and 50-language localization
Here is the part the capture tools deliberately do not touch, and it is the part the stores
actually grade you on. A raw simctl PNG is your app's UI on a white background.
What ranks in search and converts on the product page is the marketing panel: the
screenshot inside a device frame, on a branded background, with a one-line caption that says why
the screen matters — usually as a multi-panel carousel that reads left to right. And on the App
Store, screenshots are localized per device size and per language, so a serious
launch is dozens of variants, not five.
This is the bounded spot where Mokbi fits, and it is worth being precise about the boundary. Mokbi does not capture your app — you still produce the source frames with the Expo commands above. What it does is take those frames and let you, in the browser: drop them into real device frames, add captions and gradient backgrounds, lay out multi-panel carousels, one-click translate the caption text into 50 languages, and batch-export every App Store and Play Store dimension at once. You design for free with a watermarked preview; export is a one-time purchase (Single €9.99 / Pro €29.99) with no subscription. It replaces the Figma-template step Expo's guide hand-waves at — nothing more, nothing less.
The realistic combined workflow
- Build a dev/preview client.
npx expo run:iosandnpx expo run:android, seeded with good demo data. - Capture source frames. Manually via
xcrun simctl io booted screenshotandadb exec-out screencap -p, or automated via MaestrotakeScreenshot/ Detoxdevice.takeScreenshot— ideally on EAS Workflows so they regenerate each release. - Compose the marketing panels. Frame, caption, and arrange the carousel from those raw frames.
- Localize and batch-export. Translate captions across your target languages, export every required dimension for both stores.
- Upload listing assets. Screenshots into App Store Connect and Play Console; pair with EAS Metadata for the text fields if you use it.
- Submit the binary.
eas submit— the one step EAS does own. - Next release: re-capture changed screens, re-open the saved composition project, swap the frames, re-export. The captions and translations stay put.
When you can skip the automation
Reach for Maestro or Detox capture when screenshot drift is a real cost: you ship weekly, your UI changes constantly, or you maintain many apps and cannot afford stale store images. In those cases CI-regenerated frames pay for themselves and the React Native screenshot tooling story (which Expo inherits) is worth the investment.
For everyone else — the once-a-quarter shipper — skip it. Manual capture with two terminal commands, then browser-based composition and localization, gets you to a polished, multi-language listing in an afternoon with nothing to maintain between releases. Match the tooling to your cadence, not to what looks impressive on a CI dashboard.
Either way, the binary half is solved: eas submit handles it. Make sure you check
your screenshots against the
current store requirements before you
upload — Apple rejects a listing over a single off-by-one pixel — and the rest of the launch is
just design.