asc — App Store Connect CLI

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.

GitHub · Releases