asc-client – App Store Connect CLI

asc-client is a command-line tool for the App Store Connect API, built in Swift. It covers the entire app release pipeline — from Xcode archive to App Review submission — plus provisioning, metadata management, and everything in between. A single native binary, no runtime dependencies.

Installation

Homebrew (recommended)

brew tap keremerkan/tap
brew install asc-client

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-client/releases/latest/download/asc-client-macos-arm64.tar.gz -o asc-client.tar.gz
tar xzf asc-client.tar.gz
mv asc-client /usr/local/bin/

Since the binary isn’t notarized, remove the quarantine attribute:

xattr -d com.apple.quarantine /usr/local/bin/asc-client

Build from source

git clone https://github.com/keremerkan/asc-client.git
cd asc-client
swift build -c release
strip .build/release/asc-client
cp .build/release/asc-client /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-client install-completions

Restart your shell to activate. The tool detects outdated completions after updates and reminds you to reinstall.

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-client configure

This prompts for your Key ID, Issuer ID, and the path to your .p8 file. The private key is copied into ~/.asc-client/ 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-client alias add myapp
# Interactive picker shows your apps — select one

# Now use the alias everywhere
asc-client apps info myapp
asc-client apps versions myapp
asc-client 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-client/aliases.json.

List or remove aliases:

asc-client alias list
asc-client 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-client 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-client apps create-version com.example.MyApp 2.1.0
asc-client 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-client apps build attach com.example.MyApp

# Attach the most recent build automatically
asc-client apps build attach-latest com.example.MyApp

# Remove the attached build
asc-client 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-client apps phased-release com.example.MyApp

# Enable, pause, resume, or complete
asc-client apps phased-release com.example.MyApp --enable
asc-client apps phased-release com.example.MyApp --pause
asc-client apps phased-release com.example.MyApp --resume
asc-client apps phased-release com.example.MyApp --complete

# Remove phased release entirely
asc-client 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-client handles both with the same export/import pattern.

Version localizations

# View all locales for the latest version
asc-client apps localizations view com.example.MyApp

# Export to JSON
asc-client apps localizations export com.example.MyApp

# Update a single locale via flags
asc-client apps localizations update com.example.MyApp --whats-new "Bug fixes" --locale en-US

# Bulk update from JSON
asc-client 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-client apps app-info view com.example.MyApp

# Update fields for a single locale
asc-client apps app-info update com.example.MyApp --name "My App" --subtitle "Best app ever"
asc-client apps app-info update com.example.MyApp --locale de-DE --name "Meine App"

# Update categories
asc-client apps app-info update com.example.MyApp --primary-category UTILITIES

# Export/import in bulk
asc-client apps app-info export com.example.MyApp --output app-infos.json
asc-client apps app-info import com.example.MyApp --file app-infos.json

List all available category IDs with asc-client 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-client handles the entire flow with a folder-based approach.

Download and upload

# Download everything to a local folder
asc-client 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-client apps media upload com.example.MyApp --folder media/ --replace

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-client apps media verify com.example.MyApp

# Retry stuck items using local files
asc-client 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.

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? Missing any of these means a rejection or a wasted review cycle.

The preflight command runs all of these checks automatically:

asc-client 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-client apps review submit com.example.MyApp

# Check submission status
asc-client apps review status com.example.MyApp

# After rejection: fix issues, reply in Resolution Center, then
asc-client apps review resolve-issues com.example.MyApp

# Cancel an active review
asc-client apps review cancel-submission com.example.MyApp

Builds

# List builds
asc-client builds list --bundle-id com.example.MyApp
asc-client builds list --bundle-id com.example.MyApp --version 2.1.0

# Archive an Xcode project
asc-client builds archive
asc-client builds archive --scheme MyApp --output ./archives

# Validate before uploading
asc-client builds validate MyApp.ipa

# Upload to App Store Connect
asc-client builds upload MyApp.ipa

# Wait for processing to finish
asc-client 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-client apps age-rating com.example.MyApp

# Update from a JSON file
asc-client apps 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-client apps availability com.example.MyApp
asc-client apps availability com.example.MyApp --verbose

# Add or remove territories
asc-client apps availability com.example.MyApp --add CHN,RUS
asc-client apps availability com.example.MyApp --remove CHN

Encryption declarations

# View existing declarations
asc-client apps encryption com.example.MyApp

# Create a declaration (stops the compliance popup on every submission)
asc-client 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-client apps eula com.example.MyApp
asc-client apps eula com.example.MyApp --file eula.txt
asc-client apps eula com.example.MyApp --delete

Provisioning

asc-client 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-client devices list
asc-client devices list --platform IOS --status ENABLED

# Register a new device
asc-client devices register
asc-client devices register --name "My iPhone" --udid 00008101-XXXXXXXXXXXX --platform IOS

# Update name or disable
asc-client 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-client does all of that in one command:

asc-client 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-client certs list --type DISTRIBUTION
asc-client certs info "Apple Distribution: My Team"

# Revoke a certificate (interactive picker if serial omitted)
asc-client certs revoke

Bundle identifiers

# List and register
asc-client bundle-ids list --platform IOS
asc-client bundle-ids register --name "My App" --identifier com.example.MyApp --platform IOS

# View details including capabilities
asc-client bundle-ids info com.example.MyApp

# Enable or disable capabilities
asc-client bundle-ids enable-capability com.example.MyApp --type PUSH_NOTIFICATIONS
asc-client bundle-ids disable-capability com.example.MyApp

After enabling or disabling a capability, asc-client 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-client profiles create
asc-client profiles create --name "My Profile" --type IOS_APP_STORE \
  --bundle-id com.example.MyApp --certificates all

# Download a profile
asc-client 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-client profiles reissue --all-invalid

# Reissue all profiles regardless of state
asc-client profiles reissue --all

# Use specific certificates instead of auto-detect
asc-client profiles reissue --all --to-certs ABC123,DEF456

# Include all enabled devices (for dev/adhoc profiles)
asc-client 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 and Subscriptions

Read-only views for now:

# In-app purchases
asc-client iap list com.example.MyApp
asc-client iap list com.example.MyApp --type consumable --state approved
asc-client iap info com.example.MyApp com.example.MyApp.coins100
asc-client iap promoted com.example.MyApp

# Subscriptions
asc-client sub groups com.example.MyApp
asc-client sub list com.example.MyApp
asc-client sub info com.example.MyApp com.example.MyApp.monthly

Filter values are case-insensitive. 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-client apps build attach-latest com.example.MyApp --yes
asc-client apps review submit com.example.MyApp --yes
asc-client 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-client 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-client 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-client is open source under the MIT license.

GitHub · Releases