guides

Integration guides.

AppScreen does the design; fastlane (or your own scripts) does the upload. Pick the export layout that matches your project, drop the rendered bundle into your repo, and submit.

Choose your project layout

The studio's export layout picker writes the rendered bundle in a tree that drops directly into your repo. One row below per supported project shape:

LayoutiOS pathAndroid path
fastlanefastlane/fastlane/
flutterios/fastlane/android/fastlane/
react-nativeios/fastlane/android/fastlane/
capacitorios/App/fastlane/android/fastlane/
kmmiosApp/fastlane/androidApp/fastlane/

The default (raw / flat) layout produces theme/size/lang/n.png and is intended for web pages, social, and decks rather than store submission.

Flutter

Flutter projects keep iOS and Android in subdirs, each with its own fastlane/.

cd /path/to/your_flutter_app
unzip ~/Downloads/appscreen-*.zip

Files land at:

ios/fastlane/screenshots/<locale>/iPhone69/01.png …
android/fastlane/metadata/android/<locale>/images/phoneScreenshots/01.png …

Append a screenshots lane to ios/fastlane/Fastfile and android/fastlane/Fastfile (snippets in the Fastfile lanes section), then run:

cd ios && bundle exec fastlane screenshots && cd ..
cd android && bundle exec fastlane screenshots && cd ..

React Native (incl. Expo bare)

Same layout as Flutter — separate ios/ + android/ subprojects each with their own fastlane folder. Expo bare-workflow projects follow the same shape after expo prebuild.

cd /path/to/your_rn_app
unzip ~/Downloads/appscreen-*.zip
cd ios && bundle exec fastlane screenshots && cd ..
cd android && bundle exec fastlane screenshots && cd ..

Capacitor / Ionic

Capacitor's iOS xcworkspace lives under ios/App/. Files land at ios/App/fastlane/ + android/fastlane/.

cd /path/to/your_capacitor_app
unzip ~/Downloads/appscreen-*.zip
cd ios/App && bundle exec fastlane screenshots && cd ../..
cd android  && bundle exec fastlane screenshots && cd ..

Kotlin Multiplatform

KMM projects use iosApp/ + androidApp/ modules.

cd /path/to/your_kmm_app
unzip ~/Downloads/appscreen-*.zip
cd iosApp     && bundle exec fastlane screenshots && cd ..
cd androidApp && bundle exec fastlane screenshots && cd ..

Bare iOS or Android (single fastlane root)

For a repo with fastlane initialised at the project root — either an Xcode-only iOS project or a Gradle-only Android project. The bundle's fastlane/ folder merges with the existing one.

cd /path/to/your_project
unzip ~/Downloads/appscreen-*.zip
# iOS
bundle exec fastlane screenshots

# Android
bundle exec fastlane screenshots

Fastlane authentication

One-time setup of an App Store Connect API key (recommended over login + 2FA prompts) and, for Play Store, a Google service account.

App Store Connect API key

  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.
  3. Save the key to ~/.appstore/AuthKey.p8 and create an ~/.appstore/api_key.json:
{
  "key_id": "ABC1234XYZ",
  "issuer_id": "00000000-0000-0000-0000-000000000000",
  "key_filepath": "~/.appstore/AuthKey.p8"
}

Google Play service account

  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 ~/.playstore/service-account.json (and gitignore it if committing fastlane config).
  3. Play Console → Users and permissions → invite the service-account email. Grant Manage store presence.

Fastfile lanes

Append these lanes to the appropriate Fastfile (see the layout table for the path).

iOS

# inside platform :ios do … end
desc "Upload screenshots only"
lane :screenshots do |options|
  project_root = File.expand_path("..", __dir__)
  api_key_path = options[:api_key_path] ||
                 ENV["APP_STORE_CONNECT_API_KEY_PATH"] ||
                 File.expand_path("~/.appstore/api_key.json")

  api_key = app_store_connect_api_key(
    key_id:       JSON.parse(File.read(api_key_path))["key_id"],
    issuer_id:    JSON.parse(File.read(api_key_path))["issuer_id"],
    key_filepath: JSON.parse(File.read(api_key_path))["key_filepath"],
    duration:     1200,
  )

  deliver(
    api_key:               api_key,
    skip_binary_upload:    true,
    skip_metadata:         true,
    skip_screenshots:      false,
    overwrite_screenshots: true,
    force:                 true,
    screenshots_path:      File.join(project_root, "fastlane", "screenshots"),
  )
end

Android

# inside platform :android do … end
desc "Upload screenshots only"
lane :screenshots do
  upload_to_play_store(
    skip_upload_apk:         true,
    skip_upload_aab:         true,
    skip_upload_metadata:    true,
    skip_upload_changelogs:  true,
    skip_upload_images:      false,
    skip_upload_screenshots: false,
    metadata_path:           File.expand_path("./metadata", __dir__),
  )
end

CI integration

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 fastlane/screenshots and fastlane/metadata, run fastlane in CI on tag push.
  2. Stored in CI artifact: upload the ZIP to your CI artifact store; 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

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, but each locale must already be added to the editable version in App Store Connect / Play Console — otherwise it gets silently skipped.

Common errors

  1. Asset failed validation on iOS: typically a non-RGB / alpha-channel PNG. AppScreen's fastlane export already alpha-flattens for store layouts, so this only happens if you swapped a manual file in. Re-render the bundle.
  2. 401 INVALID_PROVIDER from supply: the service account isn't invited in Play Console yet, or its role is too narrow. Add Manage store presence.
  3. Wrong device folder: deliver expects iPhone69 / iPhone67 / iPhone65. The export uses these names already.
  4. Empty Media Manager after a successful upload: you're probably viewing the inflight (locked) version. Open the version in Prepare for Submission; that's where deliver writes.

Stuck on a step? The studio FAQ covers the most common questions.

Open studio