appstore-tools
v1.0.13
Published
TypeScript App Store Connect API client and CLI.
Downloads
277
Maintainers
Readme
appstore-tools
TypeScript CLI and library for App Store Connect. Authenticate with JWT, list apps, generate IPAs, and upload builds — all from your terminal.
Installation
From npm
npx appstore-tools --helpOr install globally:
npm install -g appstore-tools
appstore-tools --helpFrom source
git clone https://github.com/alesanabriav7/appstore-tools.git
cd appstore-tools
pnpm install
npm link
appstore-tools --helpSetup
Requires Node.js 20+ and an App Store Connect API key.
Set these environment variables (via .env, shell, or CI secrets):
ASC_ISSUER_ID=your-issuer-id
ASC_KEY_ID=your-key-idASC_KEY_ID is auto-inferred when the key file name matches AuthKey_<KEY_ID>.p8 (for example via ASC_PRIVATE_KEY_PATH or ASC_KEY_PATH).
For API commands (apps list, App Store Connect requests in builds upload), provide JWT private key:
ASC_PRIVATE_KEY_PATH=./AuthKey_XXXXXX.p8Or pass the key inline:
ASC_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"Note: ASC_PRIVATE_KEY_PATH is recommended. For builds upload, inline ASC_PRIVATE_KEY is written to a temporary .p8 file for xcrun altool and deleted after the command completes.
For xcodebuild archive/generate signing (ipa generate and xcodebuild-backed generation):
ASC_KEY_PATH=./AuthKey_XXXXXX.p8
# or base64-encoded .p8 contents:
ASC_KEY_CONTENT=base64-encoded-p8Optional:
ASC_TEAM_ID=ABCDE12345ASC_BASE_URL is optional and defaults to https://api.appstoreconnect.apple.com/.
Note: creating certificates requires an App Store Connect API key with Admin permissions.
Usage
Run commands from your iOS app folder (the folder that contains your app files).
Example:
cd /path/to/YourAppIf you use Tuist and only have Project.swift, generate the workspace/project first:
tuist generateRecommended daily flow (inside the app folder):
npx appstore-tools ipa export-options --team-id ABCDE12345
npx appstore-tools ipa generate
npx appstore-tools builds upload --applyList apps
npx appstore-tools apps listJSON output:
npx appstore-tools apps list --jsonGenerate IPA
Default (no flags):
npx appstore-tools ipa generateThis works when the current folder has an iOS project context (.xcworkspace or .xcodeproj).
If ExportOptions.plist is not found, the CLI generates one automatically.
Optional override (only if needed):
npx appstore-tools ipa generate --output-ipa ./dist/MyApp.ipaIf auto-detection is ambiguous, use explicit xcodebuild flags:
npx appstore-tools ipa generate \
--output-ipa ./dist/MyApp.ipa \
--scheme MyApp \
--workspace-path ./MyApp.xcworkspaceIf your project uses a custom build script, use custom mode:
npx appstore-tools ipa generate \
--output-ipa ./dist/MyApp.ipa \
--build-command "make build-ipa" \
--generated-ipa-path ./build/MyApp.ipaAuto mode for ipa generate infers:
- workspace/project from local
.xcworkspace/.xcodeproj(including Tuist-generated projects) ExportOptions.plistfrom local files when available, otherwise generates one dynamically- scheme from
xcodebuild -list -json - output path as
./dist/<scheme>.ipawhen omitted
Generate ExportOptions.plist
Create a minimal production-ready template for TestFlight/App Store:
npx appstore-tools ipa export-options --team-id ABCDE12345Defaults:
- output path:
./ExportOptions.plist - method:
app-store - signing style:
automatic
Optional flags:
npx appstore-tools ipa export-options \
--output-plist ./config/ExportOptions.plist \
--signing-style manual \
--forceCreate ASC signing certificate
Create a certificate in App Store Connect and install it into your login keychain:
npx appstore-tools certificates createDefaults:
- certificate type:
IOS_DISTRIBUTION - common name:
CLI Certificate - output directory:
./dist/certificates - installation target:
~/Library/Keychains/login.keychain-db - keychain import access:
security import ... -Ato avoid interactive prompts in CI/CD
Optional flags:
npx appstore-tools certificates create \
--type IOS_DEVELOPMENT \
--common-name "CI Signing Certificate" \
--output-dir ./certs \
--keychain ~/Library/Keychains/login.keychain-db \
--skip-install \
--jsonRead metadata
Pull the current live metadata from App Store Connect and write it to a JSON file in the same format accepted by update-metadata.
npx appstore-tools apps read-metadata --app com.example.myappOutputs ./metadata.json by default. Use --output to change the path:
npx appstore-tools apps read-metadata \
--app com.example.myapp \
--output ./metadata/current.json \
--version 2.0.0 \
--platform IOS \
--json--output— output file path (default:./metadata.json)--version— target a specific version (defaults to the first version returned)--platform—IOS(default) orMAC_OS--json— print result summary as JSON instead of human-readable output
The output file uses the same manifest format as update-metadata, so you can read, edit, and push back in one round-trip.
Update metadata
Update App Store listing text and screenshots from a JSON manifest.
Dry-run by default (no mutations):
npx appstore-tools apps update-metadata --app com.example.myapp --metadata ./metadata.jsonApply changes:
npx appstore-tools apps update-metadata --app com.example.myapp --metadata ./metadata.json --applyOptional flags:
npx appstore-tools apps update-metadata \
--app com.example.myapp \
--metadata ./metadata.json \
--version 2.0.0 \
--platform IOS \
--text-only \
--json \
--apply--text-only— skip screenshot uploads, only update text fields--screenshots-only— skip text updates, only upload screenshots--version— target a specific version (defaults to the latest editable version)--platform—IOS(default) orMAC_OS
Manifest format
The manifest is a JSON object keyed by locale, with an optional _app key for app-level metadata.
Locale keys can contain text fields and/or a screenshots object:
| Field | Description |
|---|---|
| name | App name |
| description | App description |
| keywords | Comma-separated keywords |
| promotionalText | Promotional text |
| whatsNewText | What's new / release notes |
| supportUrl | Support URL |
| marketingUrl | Marketing URL |
| subtitle | App subtitle |
| privacyPolicyUrl | Privacy policy URL |
| screenshots | Map of display type → array of file paths |
_app key sets app-level metadata (not locale-specific):
| Field | Description |
|---|---|
| copyright | Copyright string |
| primaryCategory | Primary category ID (e.g., PRODUCTIVITY) |
| secondaryCategory | Secondary category ID (optional) |
| ageRating | Age rating declaration (see below) |
| reviewContact | Review contact information |
{
"_app": {
"copyright": "2025 Acme Inc.",
"primaryCategory": "PRODUCTIVITY",
"secondaryCategory": "FINANCE",
"ageRating": {
"gamblingAndContests": false,
"unrestrictedWebAccess": false,
"horrorOrFearThemes": "NONE",
"matureOrSuggestiveThemes": "NONE",
"violenceCartoonOrFantasy": "NONE",
"violenceRealistic": "NONE",
"medicalOrTreatmentInformation": "NONE"
},
"reviewContact": {
"contactFirstName": "Jane",
"contactLastName": "Doe",
"contactPhone": "+1 555 000 0000",
"contactEmail": "[email protected]"
}
},
"en-US": {
"name": "MyApp – Do Things Faster",
"description": "The best app for doing things.",
"keywords": "productivity, tools, utilities",
"promotionalText": "Now with dark mode!",
"whatsNewText": "Bug fixes and performance improvements.",
"supportUrl": "https://example.com/support",
"marketingUrl": "https://example.com",
"subtitle": "Do things faster",
"privacyPolicyUrl": "https://example.com/privacy",
"screenshots": {
"APP_IPHONE_67": [
"./screenshots/en-US/iphone67/01_home.png",
"./screenshots/en-US/iphone67/02_detail.png"
],
"APP_IPAD_PRO_129": [
"./screenshots/en-US/ipad/01_home.png"
]
}
},
"es-MX": {
"description": "La mejor app para hacer cosas.",
"keywords": "productividad, herramientas"
}
}All fields are optional. Screenshot keys are App Store Connect display types (e.g., APP_IPHONE_67, APP_IPAD_PRO_129). File paths are resolved relative to the manifest file location.
Upload build
Dry-run by default (no mutations):
npx appstore-tools builds uploadUpload (real apply):
npx appstore-tools builds upload --applyWait until processing finishes:
npx appstore-tools builds upload --apply --wait-processingAuto mode resolves:
- app from
CFBundleIdentifier - version from
CFBundleShortVersionString - build number from
CFBundleVersion - IPA source from newest local
.ipa, or from project build context (.xcworkspace/.xcodeproj+ scheme)
Optional overrides (only if needed):
npx appstore-tools builds upload \
--app com.example.myapp \
--version 1.2.3 \
--build-number 45 \
--ipa ./dist/MyApp.ipaExplicit xcodebuild mode (if auto-detection is ambiguous):
npx appstore-tools builds upload \
--app com.example.myapp \
--version 1.2.3 \
--build-number 45 \
--scheme MyApp \
--workspace-path ./MyApp.xcworkspace \
--applyPreflight checks
Every upload runs these checks before touching App Store Connect:
- File exists, is readable, has
.ipaextension - Archive contains
Payload/*.app/Info.plist - Bundle ID, version, and build number match expectations
- Code signing is valid (
codesign --verify --strict --deep) - SHA-256 and MD5 checksums computed
The CLI attempts upload with xcrun altool first. If altool is unavailable (missing Xcode tooling or credentials), it automatically falls back to the App Store Connect upload API flow (buildUploads + buildUploadFiles + checksum marking/polling). If altool reports a validation error (e.g. bundle ID mismatch, invalid entitlements), the error is surfaced immediately — no fallback is attempted.
Help
npx appstore-tools --helpLibrary usage
import { AppStoreConnectClient, listApps } from "appstore-tools";
const client = new AppStoreConnectClient({
issuerId: process.env.ASC_ISSUER_ID!,
keyId: process.env.ASC_KEY_ID!,
privateKey: process.env.ASC_PRIVATE_KEY!
});
const apps = await listApps(client);
console.log(apps);Development
pnpm install
pnpm verify # typecheck + test + build + helpIndividual commands:
pnpm typecheck # type check
pnpm test # run tests
pnpm build # compile to dist/
pnpm cli -- --help # run built CLI
pnpm cli:dev -- --help # run from source (no build needed)Project structure
src/
api/
client.ts # HTTP client with JWT auth
types.ts # Shared upload operation types
commands/
apps-list.ts # apps list command
apps-update-metadata.ts # apps update-metadata command
builds-upload.ts # builds upload command
certificates-create.ts # certificate create command
ipa-generate.ts # ipa generate command
ipa/
artifact.ts # IPA resolution (prebuilt/xcodebuild/custom)
preflight.ts # IPA verification
cli.ts # CLI entry point
index.ts # Public API exports