Upload App Store screenshots with fastlane deliver
Dragging 100+ PNGs into App Store Connect by hand doesn't scale past your second
locale. fastlane deliver uploads a whole screenshot set — every language,
every device — in one command. Here's the exact folder layout it expects, the API key
setup, and the flags that keep it from touching anything else. Last verified: June 2026.
The folder layout deliver expects
deliver reads fastlane/screenshots/, one subfolder per
App Store Connect locale, with the image files flat inside (it does not
recurse). The device slot is auto-detected from each image's pixel resolution, so
a name prefix like iphone_01.png is for your own ordering, not for routing:
fastlane/
Appfile
Deliverfile
screenshots/
en-US/
iphone_01.png ← 1320×2868 → iPhone 6.9″ slot
iphone_02.png
ipad_01.png ← 2064×2752 → iPad 13″ slot
ko/
iphone_01.png
...
de-DE/
...
Two gotchas hide in that listing:
- Folder names are ASC locale codes, not bare ISO codes:
en-US,es-ES,fr-FR,de-DE— butko,jastay short. A folder namedenuploads nothing. - Resolutions must be exact per slot (see the size table) — a wrong-size image is skipped or rejected, it is never scaled.
Authentication: use an App Store Connect API key
Don't authenticate with your Apple ID — 2FA prompts break automation. Create an API
key instead: App Store Connect → Users and Access → Integrations →
App Store Connect API → generate a key, download the .p8 once,
and note the Key ID and Issuer ID. Then put all three in a JSON file
deliver can read:
{
"key_id": "YOUR_KEY_ID",
"issuer_id": "YOUR_ISSUER_ID",
"key": "-----BEGIN PRIVATE KEY-----\n…p8 contents…\n-----END PRIVATE KEY-----",
"duration": 1200,
"in_house": false
}
The key never leaves your machine — fastlane signs a short-lived token with it locally.
A minimal screenshots-only Deliverfile
By default deliver also wants to manage your store metadata. For a
screenshots-only pipeline, pin it down:
# fastlane/Deliverfile
overwrite_screenshots(true)
skip_binary_upload(true)
skip_metadata(true)
# fastlane/Appfile
app_identifier("com.yourcompany.app")
Then, from the folder containing fastlane/:
fastlane deliver --api_key_path ./asc_api_key.json
deliver shows an HTML preview of what it's about to upload and asks for
confirmation; pass --force to skip that in CI.
overwrite_screenshots(true) replaces the existing set per locale —
without it, deliver refuses to clobber screenshots that are already there.
screenshots/<asc-locale>/<device>_NN.png,
plus a ready Appfile, Deliverfile, API-key template and upload.sh.
Unzip, fill in two values, run. →
FAQ
Will deliver touch my app binary or metadata?
Not with the Deliverfile above — skip_binary_upload and skip_metadata
limit the run to screenshots. It's safe to run against a live app.
Do I need a new app version to update screenshots?
Yes — screenshots attach to a version, and you can only edit the set of a version that
isn't live yet (e.g. one in “Prepare for Submission”). The upload itself doesn't submit anything.
How does deliver know which device slot an image belongs to?
Purely from pixel dimensions. 1320×2868 lands in the iPhone 6.9″ slot, 2064×2752 in
iPad 13″ — which is also why exact export sizes matter.