Skip to main content

metadata

Manage app metadata with deterministic file workflows
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.