Formerly asc-client. Existing installations are migrated automatically on first run.
asc — A Swift CLI for App Store Connect. It covers the entire app release pipeline — from Xcode archive to App Review submission — plus provisioning, metadata management, in-app purchases, subscriptions, and everything in between. A single native binary, no runtime dependencies.
Full documentation: asccli.dev
Installation
Homebrew (recommended)
brew tap keremerkan/tap
brew install asc-cli
Pre-built binary for Apple Silicon. Installation is instant.
Download the binary
Download the latest release from GitHub Releases:
curl -L https://github.com/keremerkan/asc-cli/releases/latest/download/asc-macos-arm64.tar.gz -o asc.tar.gz
tar xzf asc.tar.gz
mv asc /usr/local/bin/
Since the binary isn’t notarized, remove the quarantine attribute:
xattr -d com.apple.quarantine /usr/local/bin/asc
Build from source
git clone https://github.com/keremerkan/asc-cli.git
cd asc-cli
swift build -c release
strip .build/release/asc
cp .build/release/asc /usr/local/bin/
Requires Swift 6.0+ and macOS 13+. The release build takes a few minutes because the asc-swift dependency includes ~2500 generated source files covering the entire API surface. strip reduces the binary from ~175 MB to ~64 MB.
Shell completions
Tab completion for all subcommands, options, and flags (zsh and bash):
asc install-completions
Restart your shell to activate. The tool detects outdated completions after updates and offers to reinstall.
Completions go beyond subcommand names — file arguments are filtered by type (e.g., only .json files for import commands, .ipa/.pkg/.xcarchive for uploads), and bundle ID arguments suggest your configured aliases.
AI coding skill
asc ships with a skill file that gives AI coding agents full knowledge of all commands, JSON formats, and workflows. Supported agents: Claude Code, Cursor, Windsurf, and GitHub Copilot.
Install via the binary (Claude Code):
asc install-skill
Install via npx (any supported agent):
npx asc-skill
The npx installer presents an interactive menu to select your agent and fetches the latest skill file from GitHub. The binary version checks for outdated skills on startup and offers to update.
Setup
1. Create an API Key
Go to App Store Connect > Users and Access > Integrations > App Store Connect API and generate a new key with the App Manager role. Download the .p8 private key file.
2. Configure
asc configure
This prompts for your Key ID, Issuer ID, and the path to your .p8 file. The private key is copied into ~/.asc/ with strict file permissions (owner-only access). Authentication uses ES256 JWT tokens, auto-renewed by the underlying library.
Aliases
Typing full bundle IDs gets old. Aliases map short names to bundle IDs:
asc alias add myapp
# Interactive picker shows your apps — select one
# Now use the alias everywhere
asc apps info myapp
asc apps versions myapp
asc builds list --bundle-id myapp
Any argument without a dot is treated as an alias. Real bundle IDs (which always contain dots) work unchanged, so there’s no ambiguity. Aliases are stored in ~/.asc/aliases.json.
List or remove aliases:
asc alias list
asc alias remove myapp
Workflow Files
The most powerful feature. Instead of running commands one by one, write a plain text file with one command per line:
# release.workflow — Ship MyApp v2.1.0
apps create-version com.example.MyApp 2.1.0
builds archive --scheme MyApp
builds upload --latest --bundle-id com.example.MyApp
builds await-processing com.example.MyApp
apps localizations import com.example.MyApp --file localizations.json
apps build attach-latest com.example.MyApp
apps review preflight com.example.MyApp
apps review submit com.example.MyApp
Run it:
asc run-workflow release.workflow
The workflow displays all steps, asks for confirmation, and runs them sequentially. If any step fails, it stops and tells you where.
Steps are aware of each other. When builds upload finishes, the uploaded build version is automatically passed to subsequent commands — no need to hardcode build numbers. The await-processing step polls until the build finishes processing on Apple’s servers.
Add --yes for CI/CD environments where there’s no one to confirm. Workflows can call other workflows (with circular reference detection). Both .workflow and .txt extensions work. Lines starting with # are comments, blank lines are ignored.
Version Management
Creating versions
asc apps create-version com.example.MyApp 2.1.0
asc apps create-version com.example.MyApp 2.1.0 --platform ios --release-type manual
The --release-type flag is optional — omitting it uses the previous version’s setting. The command is idempotent: re-running after a partial failure picks up where it left off.
Build management
# Interactively select and attach a build
asc apps build attach com.example.MyApp
# Attach the most recent build automatically
asc apps build attach-latest com.example.MyApp
# Remove the attached build
asc apps build detach com.example.MyApp
If the latest build is still processing, attach-latest prompts to wait. With --yes, it waits automatically.
Phased releases
# View phased release status
asc apps phased-release com.example.MyApp
# Enable, pause, resume, or complete
asc apps phased-release com.example.MyApp --enable
asc apps phased-release com.example.MyApp --pause
asc apps phased-release com.example.MyApp --resume
asc apps phased-release com.example.MyApp --complete
# Remove phased release entirely
asc apps phased-release com.example.MyApp --disable
Phased release starts inactive and activates automatically when the version goes live.
Localizations
App Store Connect has two layers of localizations: version-level (description, what’s new, keywords) and app-level (name, subtitle, privacy policy URL). asc handles both with the same export/import pattern.
Version localizations
# View all locales for the latest version
asc apps localizations view com.example.MyApp
# Export to JSON
asc apps localizations export com.example.MyApp
# Update a single locale via flags
asc apps localizations update com.example.MyApp --whats-new "Bug fixes" --locale en-US
# Bulk update from JSON
asc apps localizations import com.example.MyApp --file localizations.json
The JSON format:
{
"en-US": {
"description": "App description here.\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 get updated — omitted fields are left unchanged. This means you can have a whats-new.json that only contains whatsNew fields for each locale, and update just those without touching descriptions or keywords.
App info localizations
# View app info, categories, and per-locale metadata
asc apps app-info view com.example.MyApp
# Update fields for a single locale
asc apps app-info update com.example.MyApp --name "My App" --subtitle "Best app ever"
asc apps app-info update com.example.MyApp --locale de-DE --name "Meine App"
# Update categories
asc apps app-info update com.example.MyApp --primary-category UTILITIES
# Export/import in bulk
asc apps app-info export com.example.MyApp --output app-infos.json
asc apps app-info import com.example.MyApp --file app-infos.json
List all available category IDs with asc apps app-info view --list-categories.
Screenshots and App Previews
Managing screenshots across locales and device sizes is one of the most painful parts of App Store Connect. asc handles the entire flow with a folder-based approach.
Download and upload
# Download everything to a local folder
asc apps media download com.example.MyApp
# The folder structure mirrors the API
# media/en-US/APP_IPHONE_67/01_home.png
# media/en-US/APP_IPAD_PRO_3GEN_129/01_home.png
# media/de-DE/APP_IPHONE_67/01_home.png
# Edit locally, then re-upload
asc apps media upload com.example.MyApp --folder media/ --replace
# Upload from a zip file
asc apps media upload com.example.MyApp --folder screenshots.zip --replace
# Interactive mode: pick a folder or zip from the current directory
asc apps media upload com.example.MyApp
When --folder is omitted, the command lists subdirectories and .zip files in the current directory as a numbered picker. Zip files are extracted automatically before upload.
Folder structure
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 (
en-US,de-DE,ja, etc.) - Level 2: Display type folder name (see below)
- Level 3: Media files — images (
.png,.jpg,.jpeg) become screenshots, videos (.mp4,.mov) become app previews
Files are sorted alphabetically for ordering. Prefix them 01_, 02_, 03_ and they’ll appear in the right order on the App Store.
Required display types
App Store Connect requires APP_IPHONE_67 (iPhone 6.7″) and APP_IPAD_PRO_3GEN_129 (iPad Pro 12.9″ 3rd gen+) screenshots. All other display types are optional.
Additional display types include APP_IPHONE_61, APP_IPHONE_65, APP_IPHONE_55, APP_IPAD_PRO_3GEN_11, APP_DESKTOP, APP_APPLE_TV, APP_APPLE_VISION_PRO, various Watch sizes, and iMessage variants. Watch and iMessage types support screenshots only — video files in those folders are skipped.
Verify and retry stuck media
Screenshots and previews sometimes get stuck in “processing” after upload. media verify shows the status of every item and can retry stuck ones:
# Read-only status report
asc apps media verify com.example.MyApp
# Retry stuck items using local files
asc apps media verify com.example.MyApp --folder media/
Without --folder, sets where all items are complete show a one-liner; sets with stuck items expand to show each file and its state. With --folder, it prompts to retry stuck items by deleting and re-uploading from local files, preserving position order.
Using with asc-screenshots
asc-screenshots is a companion skill for AI coding agents that generates production-ready App Store screenshots. It scaffolds a Next.js project that renders ad-style screenshot layouts with Apple device bezels and exports a zip file in the exact folder structure asc expects:
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
Upload the exported zip directly:
asc apps media upload com.example.MyApp --folder screenshots.zip --replace
Pre-Submission Preflight
Before hitting submit, there’s a mental checklist: Is a build attached? Are all localizations filled in? Are descriptions long enough? Are screenshots uploaded for every locale?
The preflight command runs all of these checks automatically:
asc apps review preflight com.example.MyApp
It checks the version state, whether a build is attached, and then goes through every locale to verify localization fields (description, what’s new, keywords), app info fields (name, subtitle, privacy policy URL), and screenshots. The output is grouped by locale with 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
Exits with a non-zero status on failures, making it suitable for CI pipelines and workflow files.
Review Submission
# Submit for review
asc apps review submit com.example.MyApp
# Check submission status
asc apps review status com.example.MyApp
# After rejection: fix issues, reply in Resolution Center, then
asc apps review resolve-issues com.example.MyApp
# Cancel an active review
asc apps review cancel-submission com.example.MyApp
Builds
# List builds
asc builds list --bundle-id com.example.MyApp
asc builds list --bundle-id com.example.MyApp --version 2.1.0
# Archive an Xcode project
asc builds archive
asc builds archive --scheme MyApp --output ./archives
# Validate before uploading
asc builds validate MyApp.ipa
# Upload to App Store Connect
asc builds upload MyApp.ipa
# Wait for processing to finish
asc builds await-processing com.example.MyApp
The archive command auto-detects the .xcworkspace or .xcodeproj in the current directory. It accepts .ipa, .pkg, or .xcarchive files for upload and validate. When given an .xcarchive, it exports to .ipa automatically. Uploads use Apple’s xcrun altool under the hood — the same tool Xcode uses.
App Configuration
Age ratings
# View current age rating
asc apps app-info age-rating com.example.MyApp
# Update from a JSON file
asc apps app-info age-rating com.example.MyApp --file age-rating.json
The JSON uses the same field names as the API. Only fields present are updated:
{
"isAdvertising": false,
"violenceCartoonOrFantasy": "INFREQUENT_OR_MILD",
"alcoholTobaccoOrDrugUseOrReferences": "NONE"
}
Territory availability
# View available territories
asc apps availability com.example.MyApp
asc apps availability com.example.MyApp --verbose
# Add or remove territories
asc apps availability com.example.MyApp --add CHN,RUS
asc apps availability com.example.MyApp --remove CHN
Encryption declarations
# View existing declarations
asc apps encryption com.example.MyApp
# Create a declaration (stops the compliance popup on every submission)
asc apps encryption com.example.MyApp --create --description "Uses HTTPS for API communication"
Custom EULA
View the current EULA, set one from a text file, or revert to Apple’s standard EULA:
asc apps eula com.example.MyApp
asc apps eula com.example.MyApp --file eula.txt
asc apps eula com.example.MyApp --delete
Provisioning
asc covers the full Apple provisioning stack: devices, signing certificates, bundle identifiers, and provisioning profiles. Every command supports interactive mode — run without arguments for guided prompts, or pass all options explicitly for scripting.
Devices
# List registered devices
asc devices list
asc devices list --platform IOS --status ENABLED
# Register a new device
asc devices register
asc devices register --name "My iPhone" --udid 00008101-XXXXXXXXXXXX --platform IOS
# Update name or disable
asc devices update "My iPhone" --status DISABLED
Signing certificates
Creating certificates is usually a multi-step process: generate a CSR in Keychain Access, upload it to the Developer portal, download the certificate, import it back. asc does all of that in one command:
asc certs create --type DISTRIBUTION
This auto-generates an RSA key pair and CSR, sends it to the API, downloads the signed certificate, and imports both the private key and certificate into your login keychain. If you already have a CSR, pass it with --csr my-request.pem.
# List and inspect certificates
asc certs list --type DISTRIBUTION
asc certs info "Apple Distribution: My Team"
# Revoke a certificate (interactive picker if serial omitted)
asc certs revoke
Bundle identifiers
# List and register
asc bundle-ids list --platform IOS
asc bundle-ids register --name "My App" --identifier com.example.MyApp --platform IOS
# View details including capabilities
asc bundle-ids info com.example.MyApp
# Enable or disable capabilities
asc bundle-ids enable-capability com.example.MyApp --type PUSH_NOTIFICATIONS
asc bundle-ids disable-capability com.example.MyApp
After enabling or disabling a capability, asc detects existing provisioning profiles for that bundle ID and offers to regenerate them — a step that’s required for the capability change to take effect but easy to forget.
Provisioning profiles
# Create a profile (fully interactive if options omitted)
asc profiles create
asc profiles create --name "My Profile" --type IOS_APP_STORE \
--bundle-id com.example.MyApp --certificates all
# Download a profile
asc profiles download "My App Store Profile" --output ./profiles/
The --certificates all flag automatically selects every certificate of the matching family: distribution certs for App Store profiles, development certs for development profiles, Developer ID certs for Direct Distribution. This matches how Xcode’s automatic signing works.
Reissuing profiles
Provisioning profiles become invalid when a certificate expires or a capability changes. Instead of manually recreating each one:
# Reissue all invalid profiles
asc profiles reissue --all-invalid
# Reissue all profiles regardless of state
asc profiles reissue --all
# Use specific certificates instead of auto-detect
asc profiles reissue --all --to-certs ABC123,DEF456
# Include all enabled devices (for dev/adhoc profiles)
asc profiles reissue --all --all-devices
Each profile is deleted and recreated with the same name, bundle ID, devices, and profile type, but with fresh certificates. A summary table is shown before making changes.
In-App Purchases
Full lifecycle management for in-app purchases: create, update, delete, manage localizations, and submit for review.
# List and inspect
asc iap list com.example.MyApp
asc iap list com.example.MyApp --type consumable --state approved
asc iap info com.example.MyApp com.example.MyApp.coins100
asc iap promoted com.example.MyApp
# Create, update, and delete
asc iap create com.example.MyApp --name "100 Coins" --product-id com.example.MyApp.coins100 --type CONSUMABLE
asc iap update com.example.MyApp com.example.MyApp.coins100 --name "100 Gold Coins"
asc iap delete com.example.MyApp com.example.MyApp.coins100
# Submit for review (alongside an app version)
asc iap submit com.example.MyApp com.example.MyApp.coins100
IAP localizations
# View localizations
asc iap localizations view com.example.MyApp com.example.MyApp.coins100
# Export and import
asc iap localizations export com.example.MyApp com.example.MyApp.coins100
asc iap localizations import com.example.MyApp com.example.MyApp.coins100 --file iap-localizations.json
The import command creates missing locales automatically (with confirmation), so you can add new languages without visiting App Store Connect.
Subscriptions
Full management for auto-renewable subscriptions: CRUD operations for both subscriptions and subscription groups, localization management, and review submission.
# List and inspect
asc sub groups com.example.MyApp
asc sub list com.example.MyApp
asc sub info com.example.MyApp com.example.MyApp.monthly
# Create, update, and delete subscriptions
asc sub create com.example.MyApp --name "Monthly" --product-id com.example.MyApp.monthly --period ONE_MONTH --group-id GROUP_ID
asc sub update com.example.MyApp com.example.MyApp.monthly --name "Monthly Plan"
asc sub delete com.example.MyApp com.example.MyApp.monthly
# Manage subscription groups
asc sub create-group com.example.MyApp --name "Premium"
asc sub update-group com.example.MyApp --name "Premium Plus"
asc sub delete-group com.example.MyApp
# Submit for review
asc sub submit com.example.MyApp com.example.MyApp.monthly
Subscription localizations
# Subscription localizations
asc sub localizations view com.example.MyApp com.example.MyApp.monthly
asc sub localizations export com.example.MyApp com.example.MyApp.monthly
asc sub localizations import com.example.MyApp com.example.MyApp.monthly --file sub-localizations.json
# Subscription group localizations
asc sub group-localizations view com.example.MyApp
asc sub group-localizations export com.example.MyApp
asc sub group-localizations import com.example.MyApp --file group-localizations.json
When submitting an app version for review, apps review submit automatically detects in-app purchases, subscriptions, and subscription groups that may have pending changes and offers to submit them alongside the app version. This prevents the common mistake of forgetting to include updated IAPs or subscriptions in a submission.
Filter values are case-insensitive. IAP types: CONSUMABLE, NON_CONSUMABLE, NON_RENEWING_SUBSCRIPTION.
Automation
Most commands that prompt for confirmation support --yes / -y to skip prompts, making them suitable for CI/CD pipelines and scripts:
asc apps build attach-latest com.example.MyApp --yes
asc apps review submit com.example.MyApp --yes
asc profiles reissue --all-invalid --yes
When using --yes with provisioning commands, all required arguments must be provided explicitly — interactive mode is disabled.
Combined with workflow files and non-zero exit codes from preflight, you can build fully automated release pipelines that validate before submitting.
Rate limit
asc rate-limit
Hourly limit: 3600 requests (rolling window)
Used: 57
Remaining: 3543 (98%)
Terminal Output
All commands use color when connected to a terminal — green for success messages, red for errors, orange for cancellations. Colors are automatically disabled when piping output to files or other programs.
Locale codes are displayed with their language names (e.g. en-US (English (United States)) instead of bare en-US). Enum values and API states are formatted as readable titles (PREPARE_FOR_SUBMISSION becomes “Prepare for Submission”).
Under the Hood
asc is built in Swift 6.0 using swift-argument-parser for the CLI framework and Aaron Sky’s asc-swift for type-safe access to the App Store Connect API. Certificate generation uses swift-certificates for X.509 and CSR handling. Binary uploads go through Apple’s xcrun altool.
The result is a single ~64 MB native binary for Apple Silicon. Startup is instant, there’s no runtime to manage.
Developed with Claude Code.
Source & License
asc is open source under the MIT license.