Skip to main content
Manage app metadata with deterministic file workflows. Pull metadata from App Store Connect, edit locally, and push changes back.

Quick Start

asc metadata pull --app "APP_ID" --version "1.2.3" --dir "./metadata"
asc metadata push --app "APP_ID" --version "1.2.3" --dir "./metadata" --dry-run
asc metadata push --app "APP_ID" --version "1.2.3" --dir "./metadata"

Features

Phase 1 scope:
  • App-info localizations: name, subtitle, privacyPolicyUrl, privacyChoicesUrl, privacyPolicyText
  • Version localizations: description, keywords, marketingUrl, promotionalText, supportUrl, whatsNew
Not yet included:
  • Categories, copyright, review information, age ratings, screenshots

Subcommands

  • pull - Pull metadata from App Store Connect into canonical files
  • push - Push metadata changes from canonical files
  • validate - Validate metadata files for errors

Commands

metadata pull

Pull metadata from App Store Connect into canonical files:
asc metadata pull --app "APP_ID" --version "1.2.3" --dir "./metadata"
asc metadata pull --app "APP_ID" --version "1.2.3" --platform IOS --dir "./metadata"
asc metadata pull --app "APP_ID" --version "1.2.3" --dir "./metadata" --force
Flags:
  • --app - App Store Connect app ID (or ASC_APP_ID)
  • --version - App version string (e.g., 1.2.3) (required)
  • --platform - Optional platform: IOS, MAC_OS, TV_OS, or VISION_OS
  • --dir - Output root directory (required)
  • --force - Overwrite existing metadata files in --dir
  • --include - Included metadata scopes (default: localizations)
  • --output - Output format: json, table, markdown
  • --pretty - Pretty-print JSON output
Directory structure:
metadata/
├── app-info/
│   ├── en-US.json
│   ├── es-ES.json
│   └── default.json
└── versions/
    └── 1.2.3/
        ├── en-US.json
        ├── es-ES.json
        └── default.json

metadata push

Push metadata changes from canonical files:
asc metadata push --app "APP_ID" --version "1.2.3" --dir "./metadata" --dry-run
asc metadata push --app "APP_ID" --version "1.2.3" --platform IOS --dir "./metadata" --dry-run
asc metadata push --app "APP_ID" --app-info "APP_INFO_ID" --version "1.2.3" --dir "./metadata"
asc metadata push --app "APP_ID" --version "1.2.3" --dir "./metadata" --allow-deletes --confirm
Flags:
  • --app - App Store Connect app ID (or ASC_APP_ID)
  • --app-info - App Info ID (optional override)
  • --version - App version string (e.g., 1.2.3) (required)
  • --platform - Optional platform: IOS, MAC_OS, TV_OS, or VISION_OS
  • --dir - Metadata root directory (required)
  • --include - Included metadata scopes (default: localizations)
  • --dry-run - Preview changes without mutating App Store Connect
  • --allow-deletes - Allow destructive delete operations (disables default locale fallback)
  • --confirm - Confirm destructive operations (required with --allow-deletes)
  • --output - Output format: json, table, markdown
  • --pretty - Pretty-print JSON output
Notes:
  • default.json fallback is applied only when --allow-deletes is not set
  • With --allow-deletes, remote locales missing locally are planned as deletes
  • Omitted fields are treated as no-op; they do not imply deletion

metadata validate

Validate metadata files for errors:
asc metadata validate --dir "./metadata"
Flags:
  • --dir - Metadata root directory (required)
  • --output - Output format: json, table, markdown
  • --pretty - Pretty-print JSON output

File Format

App Info Localization

metadata/app-info/en-US.json:
{
  "name": "MyApp",
  "subtitle": "The best app ever",
  "privacyPolicyUrl": "https://example.com/privacy",
  "privacyChoicesUrl": "https://example.com/privacy-choices",
  "privacyPolicyText": "We respect your privacy..."
}
Supported fields:
  • name - App name (30 characters max)
  • subtitle - App subtitle (30 characters max)
  • privacyPolicyUrl - Privacy policy URL
  • privacyChoicesUrl - Privacy choices URL
  • privacyPolicyText - Privacy policy text

Version Localization

metadata/versions/1.2.3/en-US.json:
{
  "description": "MyApp is the best app for...",
  "keywords": "productivity,tools,business",
  "marketingUrl": "https://example.com",
  "promotionalText": "Try it free for 30 days!",
  "supportUrl": "https://example.com/support",
  "whatsNew": "Bug fixes and performance improvements"
}
Supported fields:
  • description - App description (4000 characters max)
  • keywords - Keywords (100 characters max)
  • marketingUrl - Marketing URL
  • promotionalText - Promotional text (170 characters max)
  • supportUrl - Support URL
  • whatsNew - What’s new / release notes (4000 characters max)

Default Locale

metadata/app-info/default.json:
{
  "name": "MyApp",
  "subtitle": "The best app"
}
The default.json file provides fallback values for locales not explicitly defined. It is only applied when --allow-deletes is not set.

Workflow

1. Pull Current Metadata

Pull metadata from App Store Connect:
asc metadata pull \
  --app "123456789" \
  --version "1.2.3" \
  --dir "./metadata"

2. Edit Locally

Edit the JSON files in your preferred editor:
vim metadata/versions/1.2.3/en-US.json

3. Preview Changes

Preview changes with --dry-run:
asc metadata push \
  --app "123456789" \
  --version "1.2.3" \
  --dir "./metadata" \
  --dry-run
Output:
App ID: 123456789
Version: 1.2.3
Dir: ./metadata
Dry Run: true

change   key                              scope    locale  version  field           reason                              from                           to
add      versions:1.2.3:es-ES:whatsNew   versions es-ES   1.2.3    whatsNew        field exists locally but not remotely                              Correcciones de errores
update   versions:1.2.3:en-US:whatsNew   versions en-US   1.2.3    whatsNew        field value differs                 Bug fixes                      Bug fixes and improvements

operation              scope     count
create_localization    versions  1
update_localization    versions  1

4. Apply Changes

Apply changes to App Store Connect:
asc metadata push \
  --app "123456789" \
  --version "1.2.3" \
  --dir "./metadata"

Examples

Add New Locale

  1. Create locale file:
    cp metadata/app-info/en-US.json metadata/app-info/ja-JP.json
    vim metadata/app-info/ja-JP.json
    
  2. Edit content:
    {
      "name": "私のアプリ",
      "subtitle": "最高のアプリ"
    }
    
  3. Push changes:
    asc metadata push --app "APP_ID" --version "1.2.3" --dir "./metadata"
    

Update What’s New

  1. Edit release notes:
    vim metadata/versions/1.2.3/en-US.json
    
  2. Update whatsNew field:
    {
      "whatsNew": "Version 1.2.3 includes:\n- New features\n- Bug fixes\n- Performance improvements"
    }
    
  3. Preview and apply:
    asc metadata push --app "APP_ID" --version "1.2.3" --dir "./metadata" --dry-run
    asc metadata push --app "APP_ID" --version "1.2.3" --dir "./metadata"
    

Delete Locale

With --allow-deletes, remove a locale by deleting its file:
# Remove locale file
rm metadata/app-info/ja-JP.json
rm metadata/versions/1.2.3/ja-JP.json

# Push with delete confirmation
asc metadata push \
  --app "APP_ID" \
  --version "1.2.3" \
  --dir "./metadata" \
  --allow-deletes \
  --confirm

Version Control

Commit metadata files to version control:
git add metadata/
git commit -m "Update app metadata for v1.2.3"
git push
Benefits:
  • Track changes over time
  • Review metadata changes in pull requests
  • Revert to previous versions
  • Collaborate on metadata updates

CI/CD Integration

name: Update Metadata
on:
  push:
    paths:
      - 'metadata/**'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Push metadata
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_PRIVATE_KEY: ${{ secrets.ASC_PRIVATE_KEY }}
        run: |
          asc metadata push \
            --app "${{ secrets.APP_ID }}" \
            --version "1.2.3" \
            --dir "./metadata"

Multiple App Info IDs

If you have multiple app infos (e.g., different platforms), specify the app info ID:
asc metadata push \
  --app "APP_ID" \
  --app-info "APP_INFO_ID" \
  --version "1.2.3" \
  --dir "./metadata"
The CLI will auto-resolve the correct app info in most cases, but you can override it when needed.