> ## Documentation Index
> Fetch the complete documentation index at: https://docs.asccli.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Metadata

# 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

```bash theme={null} theme={null}
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:

```bash theme={null} theme={null}
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:

```bash theme={null} theme={null}
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:

```bash theme={null} theme={null}
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:**

```json theme={null} theme={null}
{
  "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:**

```json theme={null} theme={null}
{
  "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:**

```json theme={null} theme={null}
{
  "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:

```bash theme={null} theme={null}
asc metadata pull \
  --app "123456789" \
  --version "1.2.3" \
  --dir "./metadata"
```

### 2. Edit Locally

Edit the JSON files in your preferred editor:

```bash theme={null} theme={null}
vim metadata/versions/1.2.3/en-US.json
```

### 3. Preview Changes

Preview changes with `--dry-run`:

```bash theme={null} theme={null}
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:

```bash theme={null} theme={null}
asc metadata push \
  --app "123456789" \
  --version "1.2.3" \
  --dir "./metadata"
```

## Examples

### Add New Locale

1. Create locale file:
   ```bash theme={null} theme={null}
   cp metadata/app-info/en-US.json metadata/app-info/ja-JP.json
   vim metadata/app-info/ja-JP.json
   ```

2. Edit content:
   ```json theme={null} theme={null}
   {
     "name": "私のアプリ",
     "subtitle": "最高のアプリ"
   }
   ```

3. Push changes:
   ```bash theme={null} theme={null}
   asc metadata push --app "APP_ID" --version "1.2.3" --dir "./metadata"
   ```

### Update What's New

1. Edit release notes:
   ```bash theme={null} theme={null}
   vim metadata/versions/1.2.3/en-US.json
   ```

2. Update `whatsNew` field:
   ```json theme={null} theme={null}
   {
     "whatsNew": "Version 1.2.3 includes:\n- New features\n- Bug fixes\n- Performance improvements"
   }
   ```

3. Preview and apply:
   ```bash theme={null} theme={null}
   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:

```bash theme={null} theme={null}
# 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:

```bash theme={null} theme={null}
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

```yaml theme={null} theme={null}
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:

```bash theme={null} theme={null}
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.
