GitHub Actions
Render screenshots on a tagged release, store the API key in repository secrets, and upload or commit the reviewed output.
CI / CD
Wire appscreenshotapi into the pipeline you already run. Captures go in from a build, fresh localized store assets come out, and upload stays an explicit release step.
Render screenshots on a tagged release, store the API key in repository secrets, and upload or commit the reviewed output.
Call appscreenshotapi from a lane, download the Fastlane-compatible ZIP, and point deliver at the extracted folder.
Hit the same API from a local shell, build script, or coding agent that can read the docs and operate a release checklist.
Large locale and store matrices return a render id immediately with async: true, so runners can poll status until the set is ready.
Store your live key (asa_live_…) as the APPSCREENSHOTAPI_KEY repository secret. On a version tag, this workflow posts your render request, asks for a fastlane_zip archive, downloads it, and uploads the set as a build artifact for review.
# .github/workflows/screenshots.yml
# Regenerate store screenshots on every tagged release.
name: Store screenshots
on:
push:
tags: ["v*"]
jobs:
render:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# 1. Render the set and request a Fastlane-ready archive.
# output.format=fastlane_zip adds archive.url to the response.
- name: Render screenshots
env:
APPSCREENSHOTAPI_KEY: ${{ secrets.APPSCREENSHOTAPI_KEY }}
run: |
curl -fsS -X POST https://api.appscreenshotapi.com/v1/renders \
-H "Authorization: Bearer $APPSCREENSHOTAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: ${{ github.ref_name }}" \
-d @screenshots/render.json > render.json
# 2. Pull archive.url out of the response and download the ZIP.
- name: Download Fastlane archive
run: |
ARCHIVE_URL=$(jq -r '.archive.url' render.json)
curl -fsSL "$ARCHIVE_URL" -o screenshots.zip
unzip -o screenshots.zip -d fastlane/screenshots
# 3. Upload the set as a build artifact for human review.
- name: Upload for review
uses: actions/upload-artifact@v4
with:
name: store-screenshots
path: fastlane/screenshotsThe request body is a plain POST /v1/renders payload checked into the repo, so screenshot changes show up in diffs and code review.
// screenshots/render.json - the POST /v1/renders request body.
{
"preset": "aurora-midnight",
"canvas": { "preset": "appstore.iphone_6_9" },
"theme": {
"accentColor": "#5EEAD4",
"device": { "frame": { "style": "clay" }, "shadow": { "elevation": "medium" } }
},
"output": {
"locales": ["en-US", "de-DE"],
"format": "fastlane_zip"
},
"slides": [
{
"role": "hook",
"headline": { "lines": ["Track every habit", "in one tap"], "accent": "one tap" },
"screenshot": { "url": "https://acme.app/shots/home.png" }
},
{
"role": "feature",
"headline": { "lines": ["See your streaks build"] },
"subtitle": "Daily, weekly, and monthly views.",
"screenshot": { "url": "https://acme.app/shots/streaks.png" }
}
]
}The Fastlane-compatible ZIP is live today. Set output.format to fastlane_zip, read archive.url from the response, and extract it into the folder structure deliver expects. The lane below renders the set; a separate, reviewed lane runs the upload.
# fastlane/Fastfile
# A lane that renders the set, then hands the folder to deliver.
lane :screenshots do
# 1. Render and download the Fastlane-ready archive.
sh("curl -fsS -X POST https://api.appscreenshotapi.com/v1/renders " \
"-H 'Authorization: Bearer #{ENV['APPSCREENSHOTAPI_KEY']}' " \
"-H 'Content-Type: application/json' " \
"-d @../screenshots/render.json > ../render.json")
archive_url = sh("jq -r '.archive.url' ../render.json").strip
sh("curl -fsSL '#{archive_url}' -o ../screenshots.zip")
sh("unzip -o ../screenshots.zip -d screenshots")
end
# deliver uploads the screenshots directory to App Store Connect.
# Keep store upload an explicit, reviewed step - never auto-publish.
lane :upload_screenshots do
deliver(
screenshots_path: "fastlane/screenshots",
skip_binary_upload: true,
skip_metadata: true,
overwrite_screenshots: true,
submit_for_review: false
)
endThe API produces the deliver-ready folder and fastlane deliver owns the upload, so the store submission stays an explicit human step. See Fastlane-compatible ZIPs for the exact folder layout.
Build real app captures, render the set with an Idempotency-Key, check the lint report, download the outputs, and send the assets through human review before store upload.
POST /v1/renders # sync, or "async": true
GET /v1/renders/{id} # poll async renders
output.format=fastlane_zip # deliver-ready archive.urlFor big locale and store matrices, send "async": true. The API returns 202 with a render id; the runner polls GET /v1/renders/{id} until the status is succeeded.
CI can poll the render id or use a signed callback endpoint to continue the pipeline when the assets are ready.
Render the same set from a script with the Node.js or Python quickstarts, or read the full API reference. The docs publish API discovery files for humans and agents.