guides · fastlane

Publish to the stores with fastlane.

AppScreen does the design, fastlane does the upload. Your App Store Connect API key and Google Play service account stay on your own machine or CI runner. We never see them.

Why fastlane and not a SaaS uploader

Holding a customer's .p8 or service-account.json is a credential-custody business. If those keys leak, the attacker can edit your store listing. Fastlane keeps the keys with you (or your CI), runs locally, and signs uploads in-process. That is the right trust boundary for a screenshot tool.

1. Render and download the bundle

In the studio, pick the fastlane export and select every store size you target. Render. Download the ZIP.

fastlane/
├── screenshots/
│   ├── en-US/iPhone69/    01.png  02.png  …
│   ├── en-US/iPhone67/    …
│   └── en-US/iPhone65/    …
├── metadata/
│   └── android/en-US/images/phoneScreenshots/  01.png  02.png  …
├── README.txt
└── appscreen-manifest.json

Unzip into the root of your iOS / Android project. The folder tree merges with anything fastlane already uses there.

2. iOS — App Store Connect

One-time setup of an App Store Connect API key (recommended over login + 2FA prompts):

  1. App Store Connect → Users and Access IntegrationsApp Store Connect API Generate API Key. Role: Marketing (sufficient for screenshots; least privilege).
  2. Download the .p8 private key. Note the Key ID and Issuer ID shown in the table.
  3. Place the key somewhere fastlane can read it (~/.appstoreconnect/private_keys/AuthKey_KEYID.p8 is the convention).

Append to your fastlane/Fastfile:

lane :screenshots do
  app_store_connect_api_key(
    key_id: ENV["ASC_KEY_ID"],
    issuer_id: ENV["ASC_ISSUER_ID"],
    key_filepath: ENV["ASC_KEY_PATH"],
    in_house: false
  )

  deliver(
    skip_metadata: true,
    skip_binary_upload: true,
    skip_screenshots: false,
    overwrite_screenshots: true,
    force: true   # skip the manual confirm step
  )
end

Then run:

fastlane screenshots

All locales × every iPhone size in the bundle land in App Store Connect as a draft. You review and submit.

3. Android — Google Play

One-time service account setup:

  1. Google Cloud Console → create a service account in the project linked to your Play account. Grant role Service Account User.
  2. Generate a JSON key for that service account. Save as play-credentials.json (gitignore it).
  3. Play Console → Users and permissions → invite the service account email. Grant Manage store presence (covers screenshots and store-listing text). Apply to the apps you publish.

Append to your Fastfile:

lane :play_screenshots do
  supply(
    package_name: "com.example.app",
    json_key: "play-credentials.json",
    skip_upload_apk: true,
    skip_upload_aab: true,
    skip_upload_metadata: true,
    skip_upload_changelogs: true,
    skip_upload_images: true,
    skip_upload_screenshots: false,
    track: "production"
  )
end
fastlane play_screenshots

Lands as a pending draft in Play Console. Review and roll out yourself.

4. CI integration (optional)

The bundle is just files; any CI flow that already runs fastlane can pull it during a release build. Two common patterns:

  1. Manual checkout: download the ZIP from AppScreen, commit the fastlane/screenshots and fastlane/metadata folders, run fastlane in CI on tag push.
  2. Stored in CI artifact: upload the ZIP to the same CI artifact store you use for builds; expand into fastlane/ before the lane runs. Useful if you don't want generated PNGs in version control.

Example GitHub Actions step:

- name: Unzip AppScreen bundle
  run: |
    unzip -q appscreen-bundle.zip -d .
- name: Publish screenshots
  env:
    ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
    ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
    ASC_KEY_PATH: ${{ secrets.ASC_KEY_PATH }}
  run: bundle exec fastlane screenshots

5. Localization

Render every language you support inside one bundle (each maps to the correct en-US, es-ES, de-DE folder). Fastlane pushes them all in one run.

Common errors

  1. Asset failed validation on iOS: typically a non-RGB / alpha-channel PNG. AppScreen's fastlane export already alpha-flattens for iOS, so this only happens if you swapped a manual file in. Re-render the bundle.
  2. 401 INVALID_PROVIDER from supply: service account isn't invited in Play Console yet, or the role is too narrow. Add Manage store presence.
  3. Wrong device folder: deliver expects iPhone69 / iPhone67 / iPhone65. The export uses these exact names already.
Stuck on a step? The studio FAQ covers the most common questions, or open an issue and we'll help.
$ open studio →