ascelerate — A Swift CLI for App Store Connect
A command-line tool for building, archiving, and publishing apps to the App Store — from Xcode archive to App Review submission. Built with Swift on the App Store Connect API.
Note: Covers the core app release workflow: archiving, uploading builds, managing versions and localizations, screenshots, review submission, provisioning (devices, certificates, bundle IDs, profiles), and full management of in-app purchases and subscriptions. Also handles customer reviews and developer responses, in-app events, custom product pages, and Sales/Finance/Analytics report downloads. Most provisioning commands support interactive mode — run without arguments to get guided prompts.
Full documentation: ascelerate.dev
Requirements
- macOS 13+
- Swift 6.0+ (only for building from source)
Installation
Homebrew
brew tap keremerkan/tap
brew trust keremerkan/tap
brew install ascelerate
Since Homebrew 6.0, third-party taps must be explicitly trusted before their code runs. The brew trust step above approves the tap; alternatively, a fully-qualified install (brew install keremerkan/tap/ascelerate) prompts you to trust it interactively.
The tap provides a pre-built binary for Apple Silicon Macs, so installation is instant.
Install script
curl -sSL https://raw.githubusercontent.com/keremerkan/ascelerate/main/install.sh | bash
Downloads the latest release, installs to /usr/local/bin, and removes the quarantine attribute automatically. Apple Silicon only.
Download manually
Download the latest release from GitHub Releases:
curl -L https://github.com/keremerkan/ascelerate/releases/latest/download/ascelerate-macos-arm64.tar.gz -o ascelerate.tar.gz
tar xzf ascelerate.tar.gz
mv ascelerate /usr/local/bin/
Since the binary is not signed or notarized, macOS will quarantine it on first download. Remove the quarantine attribute:
xattr -d com.apple.quarantine /usr/local/bin/ascelerate
Note: Pre-built binaries are provided for Apple Silicon (arm64) only. Intel Mac users should build from source.
Build from source
git clone https://github.com/keremerkan/ascelerate.git
cd ascelerate
swift build -c release
strip .build/release/ascelerate
cp .build/release/ascelerate /usr/local/bin/
Note: The release build takes several minutes because it compiles the App Store Connect client that ascelerate generates from Apple's OpenAPI specification. strip removes debug symbols, reducing the binary from ~156 MB to ~41 MB.
Shell completions
Set up tab completion for subcommands, options, and flags (supports zsh and bash):
ascelerate install-completions
This detects your shell and configures everything automatically. Restart your shell or open a new tab to activate.
AI coding skill
ascelerate ships with a skill file that gives AI coding agents (Claude Code, Grok Build, Cursor, Windsurf, GitHub Copilot) full knowledge of all commands, JSON formats, and workflows.
Via the binary (detects your installed agents):
ascelerate install-skill # install/update for every detected agent
ascelerate install-skill --all # include all supported agents (e.g. Copilot)
It auto-detects Claude Code, Grok Build (which reads the Claude Code skill path natively), Cursor, and Windsurf (and GitHub Copilot with --all), installs/updates the skill for each, and checks for outdated skills on each run to prompt you after upgrades.
Via npx (any AI coding agent):
npx ascelerate-skill
This presents an interactive menu to select your agent and installs the skill to the appropriate directory. The skill file is fetched from GitHub, so it's always up to date. Use npx ascelerate-skill --uninstall to remove it.
Setup
1. Create an API Key
Go to App Store Connect > Users and Access > Integrations > App Store Connect API and generate a new key. Download the .p8 private key file.
2. Configure
ascelerate configure
This will prompt for your Key ID, Issuer ID, and the path to your .p8 file, plus an optional vendor number (only needed for reports sales/reports finance). The private key is copied into ~/.ascelerate/ with strict file permissions (owner-only access).
Usage
Aliases
Instead of typing full bundle IDs every time, you can create short aliases:
# Add an alias (interactive app picker)
ascelerate alias add myapp
Now use the alias anywhere you'd use a bundle ID
ascelerate apps info myapp
ascelerate apps versions myapp
ascelerate apps localizations view myapp
List all aliases
ascelerate alias list
Remove an alias
ascelerate alias remove myapp
Aliases are stored in ~/.ascelerate/aliases.json. Any argument that doesn't contain a dot is looked up as an alias — real bundle IDs (which always contain dots) work unchanged.
JSON output
Read commands support --json for machine-readable output, ready for jq, scripts, and AI agents:
ascelerate apps list --json
ascelerate apps info <bundle-id> --json
ascelerate apps versions <bundle-id> --json
ascelerate apps review preflight <bundle-id> --json
ascelerate apps review status <bundle-id> --json
ascelerate builds list --bundle-id <bundle-id> --json
ascelerate testflight builds <bundle-id> --json
ascelerate testflight status <bundle-id> --json
ascelerate reviews list <bundle-id> --json
ascelerate reviews info <review-id> --json
ascelerate iap list <bundle-id> --json
ascelerate iap info <bundle-id> <product-id> --json
ascelerate iap pricing show <bundle-id> <product-id> --json
ascelerate sub groups <bundle-id> --json
ascelerate sub list <bundle-id> --json
ascelerate sub info <bundle-id> <product-id> --json
ascelerate sub pricing show <bundle-id> <product-id> --json
ascelerate rate-limit --json
List commands emit a top-level JSON array, detail commands a single object. Enum values are raw API constants (WAITING_FOR_REVIEW, IOS), dates are ISO 8601, every resource carries its id, null fields are omitted, and empty results emit [] — never prose. Warnings become booleans (iap info/sub info report "hasPricing": false). --json implies non-interactive mode, and errors go to stderr so stdout is always valid JSON.
Apps
# List all apps
ascelerate apps list
Show app details
ascelerate apps info <bundle-id>
List App Store versions
ascelerate apps versions <bundle-id>
Create a new version
ascelerate apps create-version <bundle-id> <version-string>
ascelerate apps create-version <bundle-id> 2.1.0 --platform ios --release-type manual
View or update the copyright notice
ascelerate apps copyright <bundle-id>
ascelerate apps copyright <bundle-id> --set "2026 Your Name" --version 2.1.0 --platform macos
Check review submission status
ascelerate apps review status <bundle-id>
ascelerate apps review status <bundle-id> --version 2.1.0
Submit for review
ascelerate apps review submit <bundle-id>
ascelerate apps review submit <bundle-id> --version 2.1.0
ascelerate apps review submit <bundle-id> --platform macos
Resolve rejected review items (after fixing issues and replying in Resolution Center)
ascelerate apps review resolve-issues <bundle-id>
Cancel an active review submission
ascelerate apps review cancel-submission <bundle-id>
View or update App Review Information (contact, demo account, notes)
ascelerate apps review info <bundle-id>
ascelerate apps review info <bundle-id> --contact-email [email protected] --demo-account-name reviewer --demo-account-password "hunter2" --demo-account-required true --notes "Steps to test…"
App Review attachment files (demo videos, docs, etc.)
ascelerate apps review attachment list <bundle-id>
ascelerate apps review attachment upload <bundle-id> demo.mp4
ascelerate apps review attachment delete <attachment-id>
For universal-purchase apps (one App Store record spanning iOS, macOS, tvOS, and/or visionOS), the same version string can exist once per platform. create-version and review submit default to iOS — pass --platform macos (or tvos, visionos) to target another platform. All other version-scoped commands (localizations, media, build attach, review preflight/info/attachments/resolve-issues/cancel-submission, phased release, release, routing coverage) accept an optional --platform as well; without it they prompt whenever a version (or active review submission) matches more than one platform — and refuse with a hint instead of prompting under --yes.
Pre-submission preflight checks
Before submitting for review, run preflight to verify that all required fields are filled in across every locale:
# Check the latest editable version
ascelerate apps review preflight <bundle-id>
Check a specific version
ascelerate apps review preflight <bundle-id> --version 2.1.0
The command checks version state, build attachment, and then goes through each locale to verify localization fields (description, what's new, keywords, support URL), app info fields (name, subtitle, privacy policy URL), and screenshots. Results are grouped by locale with colored pass/fail indicators:
Preflight checks for MyApp v2.1.0 (Prepare for Submission)
Check Status
──────────────────────────────────────────────────────────────────
Version state ✓ Prepare for Submission
Build attached ✓ Build 42
en-US (English (United States))
App info ✓ All fields filled
Localizations ✓ All fields filled
Screenshots ✓ 2 sets, 10 screenshots
de-DE (German (Germany))
App info ✗ Missing: Privacy Policy URL
Localizations ✗ Missing: What's New
Screenshots ✗ No screenshots
──────────────────────────────────────────────────────────────────
Result: 5 passed, 3 failed
The What's New check is skipped when the app has no previously released version — that field only exists for updates, not for a first release.
Exits with a non-zero status when any check fails, making it suitable for CI pipelines and workflow files. With --json, it emits a structured report — a passed boolean plus one entry per check — while keeping the same exit-code behavior.
Build Management
# Interactively select and attach a build to a version
ascelerate apps build attach <bundle-id>
ascelerate apps build attach <bundle-id> --version 2.1.0
Attach the most recent build automatically
ascelerate apps build attach-latest <bundle-id>
ascelerate apps build attach-latest <bundle-id> --platform macos
Remove the attached build from a version
ascelerate apps build detach <bundle-id>
Build lookups are platform-aware: on universal-purchase apps, iOS and macOS builds can share build numbers, so the attach commands only consider builds matching the target version's platform.
Phased Release
# View phased release status
ascelerate apps phased-release <bundle-id>
Enable phased release (starts inactive, activates when version goes live)
ascelerate apps phased-release <bundle-id> --enable
Pause, resume, or complete a phased release
ascelerate apps phased-release <bundle-id> --pause
ascelerate apps phased-release <bundle-id> --resume
ascelerate apps phased-release <bundle-id> --complete
Remove phased release entirely
ascelerate apps phased-release <bundle-id> --disable
Manual Release
When a version's release option is set to manual, the approved version sits in Pending Developer Release until you release it:
# Release the version that is pending developer release
ascelerate apps release <bundle-id>
Target a specific version or platform
ascelerate apps release <bundle-id> --version 2.1.0 --platform macos
Age Rating
# View age rating declaration
ascelerate apps app-info age-rating <bundle-id>
Export age rating to JSON
ascelerate apps app-info age-rating export <bundle-id>
Update age ratings from a JSON file
ascelerate apps app-info age-rating import <bundle-id> --file age-rating.json
The JSON file uses the same field names as the API. Only fields present in the file are updated:
{
"isAdvertising": false,
"isUserGeneratedContent": true,
"violenceCartoonOrFantasy": "INFREQUENT_OR_MILD",
"alcoholTobaccoOrDrugUseOrReferences": "NONE"
}
Intensity fields accept: NONE, INFREQUENT_OR_MILD, FREQUENT_OR_INTENSE. Boolean fields accept true/false.
Routing App Coverage
# View current routing coverage status
ascelerate apps routing-coverage <bundle-id>
Upload a .geojson file
ascelerate apps routing-coverage <bundle-id> --file coverage.geojson
Localizations
# View localizations (latest version by default)
ascelerate apps localizations view <bundle-id>
ascelerate apps localizations view <bundle-id> --version 2.1.0 --locale en-US
Export localizations to JSON
ascelerate apps localizations export <bundle-id>
ascelerate apps localizations export <bundle-id> --version 2.1.0 --output my-localizations.json
Update a single locale
ascelerate apps localizations update <bundle-id> --whats-new "Bug fixes" --locale en-US
Bulk update from JSON file
ascelerate apps localizations import <bundle-id> --file localizations.json
The JSON format for export and bulk update:
{
"en-US": {
"description": "My app description.\n\nSecond paragraph.",
"whatsNew": "- Bug fixes\n- New dark mode",
"keywords": "productivity,tools,utility",
"promotionalText": "Try our new features!",
"marketingURL": "https://example.com",
"supportURL": "https://example.com/support"
},
"de-DE": {
"whatsNew": "- Fehlerbehebungen\n- Neuer Dunkelmodus"
}
}
Only fields present in the JSON are updated -- omitted fields are left unchanged.
Screenshots & App Previews
# Download all screenshots and preview videos
ascelerate apps media download <bundle-id>
ascelerate apps media download <bundle-id> --folder my-media/ --version 2.1.0
ascelerate apps media download <bundle-id> --locale en-US,tr
Upload screenshots and preview videos from a folder
ascelerate apps media upload <bundle-id> media/
Upload from an archive (zip, tar, tar.gz supported)
ascelerate apps media upload <bundle-id> screenshots.zip
Upload to a specific version
ascelerate apps media upload <bundle-id> media/ --version 2.1.0
Replace existing media in matching sets before uploading
ascelerate apps media upload <bundle-id> media/ --replace
Interactive mode: pick a folder or archive from the current directory
ascelerate apps media upload <bundle-id>
When the folder argument is omitted, the command lists all subdirectories and archive files in the current directory as a numbered picker. Archives (zip, tar, tar.gz) are extracted automatically before upload.
Organize your media folder with locale and display type subfolders:
media/
├── en-US/
│ ├── APP_IPHONE_67/
│ │ ├── 01_home.png
│ │ ├── 02_settings.png
│ │ └── preview.mp4
│ └── APP_IPAD_PRO_3GEN_129/
│ └── 01_home.png
└── de-DE/
└── APP_IPHONE_67/
├── 01_home.png
└── 02_settings.png
- Level 1: Locale (e.g.
en-US,de-DE,ja) - Level 2: Display type folder name (see table below)
- Level 3: Media files -- images (
.png,.jpg,.jpeg) become screenshots, videos (.mp4,.mov) become app previews - Files are uploaded in alphabetical order by filename
- Unsupported files are skipped with a warning
Display types
App Store Connect requires APP_IPHONE_67 screenshots for iPhone apps and APP_IPAD_PRO_3GEN_129 screenshots for iPad apps. All other display types are optional.
| Folder name | Device | Screenshots | Previews |
|---|---|---|---|
| APP_IPHONE_67 | iPhone 6.7" (iPhone 17 Pro Max, 16 Pro Max, 15 Pro Max) | Required | Yes |
| APP_IPAD_PRO_3GEN_129 | iPad Pro 12.9" (3rd gen+) | Required | Yes |
All optional display types
| Folder name | Device | Screenshots | Previews |
|---|---|---|---|
| APP_IPHONE_61 | iPhone 6.1" (iPhone 17 Pro, 16 Pro, 15 Pro) | Yes | Yes |
| APP_IPHONE_65 | iPhone 6.5" (iPhone 11 Pro Max, XS Max) | Yes | Yes |
| APP_IPHONE_58 | iPhone 5.8" (iPhone 11 Pro, X, XS) | Yes | Yes |
| APP_IPHONE_55 | iPhone 5.5" (iPhone 8 Plus, 7 Plus, 6s Plus) | Yes | Yes |
| APP_IPHONE_47 | iPhone 4.7" (iPhone SE 3rd gen, 8, 7, 6s) | Yes | Yes |
| APP_IPHONE_40 | iPhone 4" (iPhone SE 1st gen, 5s, 5c) | Yes | Yes |
| APP_IPHONE_35 | iPhone 3.5" (iPhone 4s and earlier) | Yes | Yes |
| APP_IPHONE_DUO | iPhone Duo (uploaded through the asset library, see below) | Yes | No |
| PRODUCT_PAGE_HEADER | Product page header image (asset library, see below) | Yes | No |
| APP_STORE_SEARCH_RESULTS | App Store search results image (asset library, see below) | Yes | No |
| APP_IPAD_PRO_3GEN_11 | iPad Pro 11" | Yes | Yes |
| APP_IPAD_PRO_129 | iPad Pro 12.9" (1st/2nd gen) | Yes | Yes |
| APP_IPAD_105 | iPad 10.5" (iPad Air 3rd gen, iPad Pro 10.5") | Yes | Yes |
| APP_IPAD_97 | iPad 9.7" (iPad 6th gen and earlier) | Yes | Yes |
| APP_DESKTOP | Mac | Yes | Yes |
| APP_APPLE_TV | Apple TV | Yes | Yes |
| APP_APPLE_VISION_PRO | Apple Vision Pro | Yes | Yes |
| APP_WATCH_ULTRA | Apple Watch Ultra | Yes | No |
| APP_WATCH_SERIES_10 | Apple Watch Series 10 | Yes | No |
| APP_WATCH_SERIES_7 | Apple Watch Series 7 | Yes | No |
| APP_WATCH_SERIES_4 | Apple Watch Series 4 | Yes | No |
| APP_WATCH_SERIES_3 | Apple Watch Series 3 | Yes | No |
| IMESSAGE_APP_IPHONE_67 | iMessage iPhone 6.7" | Yes | No |
| IMESSAGE_APP_IPHONE_61 | iMessage iPhone 6.1" | Yes | No |
| IMESSAGE_APP_IPHONE_65 | iMessage iPhone 6.5" | Yes | No |
| IMESSAGE_APP_IPHONE_58 | iMessage iPhone 5.8" | Yes | No |
| IMESSAGE_APP_IPHONE_55 | iMessage iPhone 5.5" | Yes | No |
| IMESSAGE_APP_IPHONE_47 | iMessage iPhone 4.7" | Yes | No |
| IMESSAGE_APP_IPHONE_40 | iMessage iPhone 4" | Yes | No |
| IMESSAGE_APP_IPAD_PRO_3GEN_129 | iMessage iPad Pro 12.9" (3rd gen+) | Yes | No |
| IMESSAGE_APP_IPAD_PRO_3GEN_11 | iMessage iPad Pro 11" | Yes | No |
| IMESSAGE_APP_IPAD_PRO_129 | iMessage iPad Pro 12.9" (1st/2nd gen) | Yes | No |
| IMESSAGE_APP_IPAD_105 | iMessage iPad 10.5" | Yes | No |
| IMESSAGE_APP_IPAD_97 | iMessage iPad 9.7" | Yes | No |
Note: Watch and iMessage display types support screenshots only -- video files in those folders are skipped with a warning. The --replace flag deletes all existing assets in each matching set before uploading new ones.
> App Store Connect has no screenshot set for iPhone Duo: files in anAPP_IPHONE_DUOfolder go to the app's asset library and are placed on the version localization in file order. Accepted sizes are 2853×2007 / 2007×2853 (inner display, unfolded) and 2034×1398 / 1398×2034 (cover display); other sizes are rejected before upload. A file that still fails after retries makesmedia uploadplace that locale's iPhone Duo screenshots again at the end of the run, in file order.media verifylists them with file names and states and, given the folder, flags locales whose iPhone Duo files or order differ;media downloaddoesn't include them yet, andmedia prunenever deletes them.
>PRODUCT_PAGE_HEADERandAPP_STORE_SEARCH_RESULTSfolders also go through the asset library, one image per locale each that isn't tied to a device class (the version shows it on iPhone, iPad and iPhone Duo alike), on every platform's versions: the product page header takes a PNG at 3840×1646 or 5244×2950, and the search results image a 3:2 JPG/PNG from 1920×1280 to 3840×2560 or a 5244×2950 PNG. Each slot also takes a video instead (header: 3840×1646; search results: 3:2 in the same size range; 5–30 s at 30 or 60 fps). Uploading replaces the locale's current image or video (the old one is removed after the new one is uploaded). AnAPP_IPHONE_DUOfolder can hold app previews too (1920×886 or 886×1920, 15–30 s at 23–30 fps, with audio). Custom product pages take all three throughproduct-pages media upload --display-type PRODUCT_PAGE_HEADER(orAPP_STORE_SEARCH_RESULTS,APP_IPHONE_DUO).media downloadsaves the library images; App Store Connect gives no download link for library videos.
>media downloadsaves files in this same folder structure (defaults to), so you can download, edit, and re-upload.-media/
Using with app-store-screenshots
app-store-screenshots is a companion skill for AI coding agents that generates production-ready App Store screenshots. It creates a Next.js page that renders ad-style marketing layouts using framed device screenshots from ascelerate screenshot frame and exports them as a zip file ready for upload via ascelerate apps media upload:
en-US/APP_IPHONE_67/01_hero.png
en-US/APP_IPAD_PRO_3GEN_129/01_hero.png
de-DE/APP_IPHONE_67/01_hero.png
Install the skill for your AI coding agent:
npx skills add keremerkan/ascelerate
Upload the exported zip directly:
ascelerate apps media upload <bundle-id> screenshots.zip --replace
Verify and retry stuck media
Sometimes screenshots or previews get stuck in "processing" after upload. Use media verify to check the status of all media at once and optionally retry stuck items:
# Check status of all screenshots and previews
ascelerate apps media verify <bundle-id>
Check a specific version
ascelerate apps media verify <bundle-id> --version 2.1.0
Retry stuck items using local files from the media folder
ascelerate apps media verify <bundle-id> media/
Without --folder, the command shows a read-only status report. Sets where all items are complete show a compact one-liner; sets with stuck items expand to show each file and its state. With --folder, it prompts to retry stuck items by deleting them and re-uploading from the matching local files, preserving the original position order.
A screenshot also counts as stuck when it reads complete but its asset library placement is still processing; App Review refuses a version in that state ("Asset is being processed"), and retrying with the folder uploads it again.
Prune stale sets
--replace on upload only clears sets that match a local folder — server sets for screen sizes you no longer ship (say, an old 5.8-inch set) keep their outdated screenshots. media prune deletes the sets that have no matching local locale/display-type folder, after listing them with asset counts and confirming:
ascelerate apps media prune <bundle-id> media/
ascelerate apps media prune <bundle-id> media/ --version 2.1.0 --platform ios
Locales that have no local folder at all are skipped entirely — the command only prunes within locales the folder actually manages.
Remove asset library images
media remove takes one kind of asset library item off a version (the PRODUCT_PAGE_HEADER or APP_STORE_SEARCH_RESULTS image or video, or APP_IPHONE_DUO screenshots; --previews for Duo app previews), for the locales given with --locale or all of them, after listing what it found and asking:
ascelerate apps media remove <bundle-id> PRODUCT_PAGE_HEADER --locale en-US
ascelerate apps media remove <bundle-id> APP_IPHONE_DUO --locale en-US,tr --version 2.1.0
Clean up the asset library
Versions share the app's asset library images (a new version's screenshots are the previous version's images, and old versions keep theirs), so an image stays in use as long as any version, custom product page or event places it. When ascelerate removes a placement (media remove, media upload --replace, or replacing a header or search results image), it also deletes the image if nothing uses it any more and it never went through App Review. Earlier uploads can still have left unused images; media library counts the images and lists the unused ones, and --delete-unused deletes them after asking:
ascelerate apps media library <bundle-id>
ascelerate apps media library <bundle-id> --delete-unused
ascelerate apps media library <bundle-id> --only APP_IPHONE_DUO --delete-unused
--only narrows it to images that fit the given kinds, by asset category and pixel size: PRODUCT_PAGE_HEADER, APP_STORE_SEARCH_RESULTS, APP_IPHONE_DUO, a screenshot display type such as APP_IPHONE_67, or UNFINISHED_UPLOADS for uploads whose file never arrived, so the library can be cleaned one device type at a time. Images less than an hour old are always kept (an upload running at the same time may be about to place them), and a run that hits App Store Connect's hourly API limit stops and says how many are left.
Images that went through App Review are never deleted, and each one is checked again right before it is deleted.
Capturing Screenshots
Capture App Store screenshots directly from iOS/iPadOS simulators using UI tests. Replaces fastlane snapshot.
# Generate config and helper files
ascelerate screenshot init # Creates ascelerate/screenshot.yml and ascelerate/ScreenshotHelper.swift
Capture screenshots
ascelerate screenshot run
ascelerate screenshot run -l en-US,tr-TR # Only capture a subset of configured languages
ascelerate screenshot frame # Frame screenshots with device bezels
ascelerate screenshot doctor # Check config and environment for problems
Add ScreenshotHelper.swift to your UITest target, then call setupScreenshots(app) in setUp() and screenshot("name") to capture:
override func setUp() {
setupScreenshots(app)
app.launch()
}
func testScreenshots() {
screenshot("01-home")
app.buttons["Settings"].tap()
screenshot("02-settings")
}
On the iPhone Duo simulator (Xcode 27.1+), setHinge(.open) / setHinge(.closed) unfold and fold the device mid-test (it always boots folded). deviceBezel also takes a list of bezels; each screenshot is framed with the one whose screen fits its size, so folded and unfolded shots each get the right frame.
Configure via ascelerate/screenshot.yml:
# workspace: MyApp.xcworkspace
project: MyApp.xcodeproj
scheme: AppUITests
devices:
- simulator: iPhone 17 Pro Max
# frameDevice: true
# deviceBezel: ./bezels/iPhone 17 Pro Max.png
- simulator: iPad Pro 13-inch (M5)
# frameDevice: true
# deviceBezel: ./bezels/iPad Pro 13-inch (M5).png
languages:
- en-US
- de-DE
outputDirectory: ./screenshots
framedOutputDirectory: ./screenshots/framed
clearPreviousScreenshots: true
localizeSimulator: true
overrideStatusBar: true
darkMode: false
disableAnimations: false
waitAfterBoot: 0
configuration: Debug
testplan: MyTestPlan
numberOfRetries: 0 # Retry failed languages (erase + reboot simulator)
stopAfterFirstError: false
reinstallApp: false
disableAssetDownloads: false # Disable mobileassetd (no Siri/keyboard/ML asset downloads; also blocks on-device ML assets)
xcargs: -maximum-parallel-testing-workers 2
Features:
- Builds once, then runs tests across all languages
- iPhone and iPad run concurrently per language
- Status bar override (9:41, full bars, no carrier)
- Simulator localization per language
- Dark mode support
- Animation disabling for reliable captures
- Automatic retries for failed languages (erases simulator, re-localizes, reboots, and reruns)
- Errors skip and continue, with summary table and error logs saved to output
- Helper version tracking with update warnings
- Device bezel framing with Apple Product Bezels (download required)
- Config validation via
doctorsubcommand create-helperavailable separately but also run automatically byinit
screenshots/
├── en-US/
│ ├── iPhone-01-home.png
│ └── iPad-01-home.png
└── de-DE/
└── ...
With frameDevice enabled, framed screenshots are saved to {outputDirectory}/framed/ (or framedOutputDirectory if set).
App Info & Categories
# View app info, categories, and per-locale metadata
ascelerate apps app-info view <bundle-id>
List all available category IDs (no bundle ID needed)
ascelerate apps app-info view --list-categories
Update localization fields for a single locale
ascelerate apps app-info update <bundle-id> --name "My App" --subtitle "Best app ever"
ascelerate apps app-info update <bundle-id> --locale de-DE --name "Meine App"
Update categories (can combine with localization flags)
ascelerate apps app-info update <bundle-id> --primary-category UTILITIES
ascelerate apps app-info update <bundle-id> --primary-category GAMES_ACTION --secondary-category ENTERTAINMENT
Export all app info localizations to JSON
ascelerate apps app-info export <bundle-id>
ascelerate apps app-info export <bundle-id> --output app-infos.json
Bulk update localizations from a JSON file
ascelerate apps app-info import <bundle-id> --file app-infos.json
Territory Availability
# View which territories the app is available in
ascelerate apps availability <bundle-id>
Show full country names
ascelerate apps availability <bundle-id> --verbose
Make territories available or unavailable
ascelerate apps availability <bundle-id> --add CHN,RUS
ascelerate apps availability <bundle-id> --remove CHN
Encryption Declarations
# View existing encryption declarations
ascelerate apps encryption <bundle-id>
Create a new encryption declaration
ascelerate apps encryption <bundle-id> --create --description "Uses HTTPS for API communication"
ascelerate apps encryption <bundle-id> --create --description "Uses AES encryption" --proprietary-crypto --third-party-crypto
EULA
# View the current EULA (or see that the standard Apple EULA applies)
ascelerate apps eula <bundle-id>
Set a custom EULA from a text file
ascelerate apps eula <bundle-id> --file eula.txt
Remove the custom EULA (reverts to standard Apple EULA)
ascelerate apps eula <bundle-id> --delete
Subscription Grace Period
The grace period lets subscribers keep access for a short window after a failed renewal payment while Apple retries billing. Settings apply to the whole app.
# View current grace period configuration
ascelerate apps subscription-grace-period <bundle-id>
Enable for production with a 16-day window, applies to all renewals
ascelerate apps subscription-grace-period <bundle-id> --opt-in true --duration SIXTEEN_DAYS --renewal-type ALL_RENEWALS
Enable for sandbox testing too
ascelerate apps subscription-grace-period <bundle-id> --sandbox-opt-in true
Valid --duration values: THREE_DAYS, SIXTEEN_DAYS, TWENTY_EIGHT_DAYS. Valid --renewal-type values: ALL_RENEWALS, PAID_TO_PAID_ONLY.
Devices
# List registered devices
ascelerate devices list
ascelerate devices list --platform IOS --status ENABLED
Show device details (interactive picker if name/UDID omitted)
ascelerate devices info
ascelerate devices info "My iPhone"
Register a new device (interactive prompts if options omitted)
ascelerate devices register
ascelerate devices register --name "My iPhone" --udid 00008101-XXXXXXXXXXXX --platform IOS
Update a device (interactive picker and update prompts if omitted)
ascelerate devices update
ascelerate devices update "My iPhone" --name "Work iPhone"
ascelerate devices update "My iPhone" --status DISABLED
Certificates
# List signing certificates
ascelerate certs list
ascelerate certs list --type DISTRIBUTION
Show certificate details (interactive picker if omitted)
ascelerate certs info
ascelerate certs info "Apple Distribution: Example Inc"
Create a certificate (interactive type picker if --type omitted)
Auto-generates RSA key pair and CSR, imports into login keychain
ascelerate certs create
ascelerate certs create --type DISTRIBUTION
ascelerate certs create --type DEVELOPMENT --csr my-request.pem
Revoke a certificate (interactive picker if omitted)
ascelerate certs revoke
ascelerate certs revoke ABC123DEF456
Bundle Identifiers
# List bundle identifiers
ascelerate bundle-ids list
ascelerate bundle-ids list --platform IOS
Show details and capabilities (interactive picker if omitted)
ascelerate bundle-ids info
ascelerate bundle-ids info com.example.MyApp
Register a new bundle ID (interactive prompts if options omitted)
ascelerate bundle-ids register
ascelerate bundle-ids register --name "My App" --identifier com.example.MyApp --platform IOS
Rename a bundle ID (identifier itself is immutable)
ascelerate bundle-ids update
ascelerate bundle-ids update com.example.MyApp --name "My Renamed App"
Delete a bundle ID (interactive picker if omitted)
ascelerate bundle-ids delete
ascelerate bundle-ids delete com.example.MyApp
Enable a capability (interactive pickers if omitted)
Shows only capabilities not already enabled
ascelerate bundle-ids enable-capability
ascelerate bundle-ids enable-capability com.example.MyApp --type PUSH_NOTIFICATIONS
Disable a capability (picks from currently enabled capabilities)
ascelerate bundle-ids disable-capability
ascelerate bundle-ids disable-capability com.example.MyApp
After enabling or disabling a capability, if provisioning profiles exist for that bundle ID, the command offers to regenerate them (required for changes to take effect).
Note: Some capabilities (e.g. App Groups, iCloud, Associated Domains) require additional configuration in the Apple Developer portal after enabling.
Provisioning Profiles
# List provisioning profiles
ascelerate profiles list
ascelerate profiles list --type IOS_APP_STORE --state ACTIVE
Show profile details (interactive picker if omitted)
ascelerate profiles info
ascelerate profiles info "My App Store Profile"
Download a profile (interactive picker if omitted)
ascelerate profiles download
ascelerate profiles download "My App Store Profile" --output ./profiles/
Create a profile (fully interactive if options omitted)
Prompts for name, type, bundle ID, certificates, and devices
ascelerate profiles create
ascelerate profiles create --name "My Profile" --type IOS_APP_STORE --bundle-id com.example.MyApp --certificates all
--certificates all uses all certs of the matching family (distribution, development, or Developer ID)
You can also specify serial numbers: --certificates ABC123,DEF456
Delete a profile (interactive picker if omitted)
ascelerate profiles delete
ascelerate profiles delete "My App Store Profile"
Reissue profiles (delete + recreate with latest certs of matching family)
ascelerate profiles reissue # Interactive: pick from all profiles (shows status)
ascelerate profiles reissue "My Profile" # Reissue a specific profile by name
ascelerate profiles reissue --all-invalid # Reissue all invalid profiles
ascelerate profiles reissue --all # Reissue all profiles regardless of state
ascelerate profiles reissue --all --all-devices # Reissue all, using all enabled devices for dev/adhoc
ascelerate profiles reissue --all --to-certs ABC123,DEF456 # Use specific certificates instead of auto-detect
Builds
# List all builds (shows app version, platform, and build number)
ascelerate builds list
ascelerate builds list --bundle-id <bundle-id>
ascelerate builds list --bundle-id <bundle-id> --version 2.1.0
ascelerate builds list --bundle-id <bundle-id> --platform macos
Archive an Xcode project
ascelerate builds archive
ascelerate builds archive --scheme MyApp --output ./archives
Validate a build before uploading
ascelerate builds validate MyApp.ipa
Upload a build to App Store Connect
ascelerate builds upload MyApp.ipa
Wait for a build to finish processing
ascelerate builds await-processing <bundle-id>
ascelerate builds await-processing <bundle-id> --build-version 903
ascelerate builds await-processing <bundle-id> --build-version 903 --platform macos
The archive command auto-detects the .xcworkspace or .xcodeproj in the current directory and resolves the scheme if only one exists. It accepts .ipa, .pkg, or .xcarchive files for upload and validate. When given an .xcarchive, it detects the archive's platform and automatically exports to .ipa (iOS-family) or .pkg (macOS) before uploading, passing the matching platform to altool.
TestFlight
# Beta groups
ascelerate testflight groups list <bundle-id>
ascelerate testflight groups info <bundle-id> "External Testers"
ascelerate testflight groups create <bundle-id> --name "Friends" --public-link --public-link-limit 100
ascelerate testflight groups update <bundle-id> "Friends" --public-link false
ascelerate testflight groups delete <bundle-id> "Friends"
Give a group access to a build (defaults to the latest)
ascelerate testflight groups add-build <bundle-id> "Friends"
ascelerate testflight groups add-build <bundle-id> "Friends" --build 123
ascelerate testflight groups remove-build <bundle-id> "Friends" --build 123
Public-link recruitment criteria (device/OS filters)
ascelerate testflight groups criteria view <bundle-id> "Friends" --options
ascelerate testflight groups criteria set <bundle-id> "Friends" --filter IPHONE:18.0 --filter IPAD:17.0:26
ascelerate testflight groups criteria clear <bundle-id> "Friends"
Testers
ascelerate testflight testers list <bundle-id> --group "Friends"
ascelerate testflight testers add <bundle-id> --email [email protected] --group "Friends"
ascelerate testflight testers remove <bundle-id> [email protected] --group "Friends"
ascelerate testflight testers remove <bundle-id> [email protected] # remove from the whole app
ascelerate testflight testers invite <bundle-id> [email protected] # re-send the invitation email
ascelerate testflight testers import <bundle-id> --file testers.csv --group "Friends"
Builds & distribution
ascelerate testflight builds <bundle-id> # TestFlight states per build
ascelerate testflight versions <bundle-id> # pre-release version trains
ascelerate testflight status <bundle-id> --build 123 # processing, testing, and beta review states
ascelerate testflight expire <bundle-id> --build 123
ascelerate testflight notify <bundle-id> # notify testers about the latest build
ascelerate testflight auto-notify <bundle-id> --enabled true
What to Test (per build, per locale)
ascelerate testflight whats-new view <bundle-id>
ascelerate testflight whats-new set <bundle-id> --text "Bug fixes" --locale en-US
ascelerate testflight whats-new set <bundle-id> --text "Bug fixes" # all existing locales
ascelerate testflight whats-new export <bundle-id> --output notes.json
ascelerate testflight whats-new import <bundle-id> --file notes.json
Beta review (required for external testing)
ascelerate testflight submit <bundle-id>
ascelerate testflight app-info view <bundle-id>
ascelerate testflight app-info update <bundle-id> --locale en-US --feedback-email [email protected]
ascelerate testflight review-info <bundle-id> # contact + demo account; pass flags to update
ascelerate testflight eula <bundle-id> --file eula.txt # custom beta license agreement
Tester feedback
ascelerate testflight feedback crashes list <bundle-id>
ascelerate testflight feedback crashes log <submission-id> --output crash.log
ascelerate testflight feedback screenshots list <bundle-id>
ascelerate testflight feedback screenshots download <bundle-id> # picker; zips screenshots + comment
Build-scoped commands default to the latest non-expired build; pass --build (and --platform for universal-purchase apps) to target a specific one. testers import reads one tester per line (email[,first name[,last name]]), skipping blank lines, # comments, and a leading header row.
In-App Purchases
# List and inspect
ascelerate iap list <bundle-id>
ascelerate iap list <bundle-id> --type consumable --state approved
ascelerate iap info <bundle-id> <product-id>
Promoted purchases (shown on the App Store product page)
ascelerate iap promoted list <bundle-id>
ascelerate iap promoted add <bundle-id> <product-id>
ascelerate iap promoted reorder <bundle-id> com.example.a,com.example.b
ascelerate iap promoted toggle <bundle-id> <product-id> --enabled false
ascelerate iap promoted remove <bundle-id> <product-id>
Create, update, and delete
ascelerate iap create <bundle-id> --name "100 Coins" --product-id <product-id> --type CONSUMABLE
ascelerate iap update <bundle-id> <product-id> --name "100 Gold Coins"
ascelerate iap delete <bundle-id> <product-id>
Submit for review
ascelerate iap submit <bundle-id> <product-id>
Manage localizations
ascelerate iap localizations view <bundle-id> <product-id>
ascelerate iap localizations export <bundle-id> <product-id>
ascelerate iap localizations import <bundle-id> <product-id> --file iap-de.json
Pricing — set the base region price (auto-equalizes to all other territories)
ascelerate iap pricing show <bundle-id> <product-id>
ascelerate iap pricing tiers <bundle-id> <product-id> --territory USA
ascelerate iap pricing set <bundle-id> <product-id> --price 4.99
ascelerate iap pricing set <bundle-id> <product-id> --price 4.99 --base-territory GBR
Pricing — manage per-territory manual overrides
ascelerate iap pricing override <bundle-id> <product-id> --price 5.99 --territory FRA
ascelerate iap pricing remove <bundle-id> <product-id> --territory FRA
Pricing — copy the schedule between products (same app or another one)
ascelerate iap pricing export <bundle-id> <product-id> --output prices.json
ascelerate iap pricing import <other-bundle-id> <other-product-id> --file prices.json
Per-IAP territory availability (independent of the app's territories)
ascelerate iap availability <bundle-id> <product-id>
ascelerate iap availability <bundle-id> <product-id> --add CHN,RUS --remove ITA --available-in-new-territories true
Offer codes (campaigns + redeem codes)
ascelerate iap offer-code list <bundle-id> <product-id>
ascelerate iap offer-code create <bundle-id> <product-id> --name "Launch Promo" --eligibility NON_SPENDER,ACTIVE_SPENDER --price 0.99 --territory USA --equalize-all-territories
ascelerate iap offer-code toggle <bundle-id> <product-id> <offer-code-id> --active true
ascelerate iap offer-code gen-codes <bundle-id> <product-id> <offer-code-id> --count 100 --expires 2026-12-31
ascelerate iap offer-code add-custom-codes <bundle-id> <product-id> <offer-code-id> --code PROMO2026 --count 1000 --expires 2026-12-31
ascelerate iap offer-code view-codes <one-time-use-batch-id> --output codes.txt
Promotional images + App Review screenshot
ascelerate iap images list <bundle-id> <product-id>
ascelerate iap images upload <bundle-id> <product-id> ./hero.png
ascelerate iap images delete <bundle-id> <product-id> <image-id>
ascelerate iap review-screenshot view <bundle-id> <product-id>
ascelerate iap review-screenshot upload <bundle-id> <product-id> ./review.png
ascelerate iap review-screenshot delete <bundle-id> <product-id>
Filter values are case-insensitive. Types: CONSUMABLE, NON_CONSUMABLE, NON_RENEWING_SUBSCRIPTION. States: APPROVED, MISSING_METADATA, READY_TO_SUBMIT, WAITING_FOR_REVIEW, IN_REVIEW, etc.
iap info and iap pricing show warn when an IAP has no price schedule — the same condition surfaced in apps review preflight (which skips products you removed from sale instead of failing them). When set changes the base territory price, existing per-territory manual overrides are preserved by default. If overrides exist, an interactive menu offers to revert any of them; pass --remove-all-overrides for a non-interactive wipe.
iap pricing export writes the base territory and every manual price to a JSON file keyed by territory code; iap pricing import applies such a file to any IAP — prices are matched to the target product's own tiers by customer price, so the file works across products and apps. Import replaces the schedule wholesale: territories not listed in the file revert to auto-equalize. If the current schedule already matches the file, import is a no-op.
Offer code one-time-use codes are generated asynchronously. After gen-codes, run view-codes to fetch the actual code values. If the response is empty, retry in a few seconds. Custom codes (add-custom-codes) are developer-supplied strings that don't need separate generation.
Images and review screenshots use Apple's 3-step file upload flow (reserve → PUT chunks → commit with MD5). The CLI handles all three steps in upload.
Subscriptions
```bash
List and inspect
ascelerate sub groupsCreate, update, and delete subscriptions
ascelerate sub createManage subscription groups
ascelerate sub create-groupSubmit for review
ascelerate sub submitSubscription localizations
ascelerate sub localizations viewSubscription group localizations
ascelerate sub group-localizations viewPricing — single territory or fan-out across all territories
ascelerate sub pricing showStandard global price raise: grandfather existing subscribers at the old price
ascelerate sub pricing setPricing — copy per-territory prices between subscriptions (same app or another one)
ascelerate sub pricing exportPer-subscription territory availability (independent of the app's territories)
ascelerate sub availabilityIntroductory offers (free trials and intro discounts for new subscribers)
ascelerate sub intro-offer listPromotional offers (server-signed offers for existing subscribers)
ascelerate sub promo-offer listOffer codes (redeemable codes — one-time-use batches and custom codes)
ascelerate sub offer-code list... (README truncated for length)