TechnicalMarch 19, 202510 min read

Using App Store Connect API for Automated Localization

Technical guide to using the App Store Connect API for programmatic metadata localization. Automate your ASO workflow across all 40 locales.


Why Use the App Store Connect API?

Managing metadata for 40 locales through the App Store Connect web interface is tedious. Each locale requires individual editing, and a single update cycle could mean hours of copy-pasting.

The App Store Connect API changes this. You can programmatically update metadata across all locales in seconds.

API Overview

Authentication

App Store Connect uses JWT (JSON Web Token) authentication with ES256 signing.

You'll Need:

  • API Key (from App Store Connect → Users and Access → Keys)
  • Issuer ID
  • Key ID
  • Private Key (.p8 file)

JWT Structure:

`json

{

"alg": "ES256",

"kid": "YOUR_KEY_ID",

"typ": "JWT"

}

{

"iss": "YOUR_ISSUER_ID",

"iat": ,

"exp": ,

"aud": "appstoreconnect-v1"

}

`

JWT tokens expire after 20 minutes. Generate them as needed.

Base URL

All requests go to:

`

https://api.appstoreconnect.apple.com/v1

`

Key Endpoints for Localization

EndpointPurpose
`/apps`List your apps
`/apps/{id}/appStoreVersions`Get versions
`/appStoreVersions/{id}/appStoreVersionLocalizations`Get localizations
`/appStoreVersionLocalizations/{id}`Update localization
`/appInfoLocalizations/{id}`Update app-level info

Understanding the Data Model

App-Level vs. Version-Level

App-Level Fields (persist across versions):

  • App Name
  • Subtitle
  • Privacy Policy URL

Version-Level Fields (per release):

  • Description
  • Keywords
  • Promotional Text
  • What's New

You'll work with different endpoints depending on which fields you're updating.

Localization IDs

Each locale has a unique localization ID. When you fetch localizations, you'll get responses like:

`json

{

"data": [

{

"type": "appStoreVersionLocalizations",

"id": "abc123",

"attributes": {

"locale": "en-US",

"description": "...",

"keywords": "..."

}

},

{

"type": "appStoreVersionLocalizations",

"id": "def456",

"attributes": {

"locale": "de-DE",

"description": "...",

"keywords": "..."

}

}

]

}

`

Use these IDs for updates.

Common Workflows

Fetching Current Metadata

Step 1: Get Your App

`

GET /v1/apps?filter[bundleId]=com.yourcompany.yourapp

`

Step 2: Get Editable Version

`

GET /v1/apps/{appId}/appStoreVersions?filter[appStoreState]=PREPARE_FOR_SUBMISSION

`

Step 3: Get All Localizations

`

GET /v1/appStoreVersions/{versionId}/appStoreVersionLocalizations

`

Updating Metadata

Update a Single Locale:

`

PATCH /v1/appStoreVersionLocalizations/{localizationId}

Content-Type: application/json

{

"data": {

"type": "appStoreVersionLocalizations",

"id": "{localizationId}",

"attributes": {

"description": "Your new description...",

"keywords": "keyword1,keyword2,keyword3",

"promotionalText": "New promotional text",

"whatsNew": "What's new in this version"

}

}

}

`

Creating New Localizations

If a locale doesn't exist yet:

`

POST /v1/appStoreVersionLocalizations

Content-Type: application/json

{

"data": {

"type": "appStoreVersionLocalizations",

"attributes": {

"locale": "ja",

"description": "Japanese description...",

"keywords": "キーワード1,キーワード2"

},

"relationships": {

"appStoreVersion": {

"data": {

"type": "appStoreVersions",

"id": "{versionId}"

}

}

}

}

}

`

Building a Localization Script

Here's a practical workflow for automated localization:

Step 1: Prepare Your Data

Structure your localized content in a format like:

`json

{

"en-US": {

"description": "English description...",

"keywords": "keyword1,keyword2",

"promotionalText": "..."

},

"de-DE": {

"description": "German description...",

"keywords": "schlüsselwort1,schlüsselwort2",

"promotionalText": "..."

},

"ja": {

"description": "Japanese description...",

"keywords": "キーワード1,キーワード2",

"promotionalText": "..."

}

}

`

Step 2: Fetch Existing Localizations

Map locale codes to localization IDs:

`javascript

const localizationMap = {};

const localizations = await fetchLocalizations(versionId);

for (const loc of localizations) {

localizationMap[loc.attributes.locale] = loc.id;

}

`

Step 3: Update or Create

For each locale in your data:

`javascript

for (const [locale, content] of Object.entries(localizedContent)) {

if (localizationMap[locale]) {

// Update existing

await updateLocalization(localizationMap[locale], content);

} else {

// Create new

await createLocalization(versionId, locale, content);

}

}

`

Step 4: Verify

After updates, fetch localizations again and verify content matches what you sent.

Error Handling

Common Errors

StatusMeaningSolution
401Authentication failedCheck JWT token
403Permission deniedVerify API key permissions
404Resource not foundCheck IDs are correct
409ConflictVersion not editable or locale exists
422Validation failedCheck field lengths and format
429Rate limitedSlow down requests

Rate Limits

Apple enforces rate limits. Best practices:

  • Add delays between requests (200-500ms)
  • Use exponential backoff on 429 errors
  • Batch operations where possible

Working with App-Level Fields

App Name and Subtitle are app-level, not version-level.

Get App Info Localizations:

`

GET /v1/apps/{appId}/appInfos

GET /v1/appInfos/{appInfoId}/appInfoLocalizations

`

Update App Info:

`

PATCH /v1/appInfoLocalizations/{localizationId}

{

"data": {

"type": "appInfoLocalizations",

"id": "{localizationId}",

"attributes": {

"name": "Your App Name",

"subtitle": "Your Subtitle"

}

}

}

`

Screenshot Upload via API

Screenshot upload is more complex:

Step 1: Create Screenshot Set (if needed)

`

POST /v1/appScreenshotSets

`

Step 2: Reserve Screenshot Asset

`

POST /v1/appScreenshots

{

"data": {

"type": "appScreenshots",

"attributes": {

"fileName": "screenshot.png",

"fileSize": 1234567

},

"relationships": {

"appScreenshotSet": {...}

}

}

}

`

Step 3: Upload Binary

The response includes upload operations with URLs and headers. Upload your file in chunks.

Step 4: Commit Upload

`

PATCH /v1/appScreenshots/{id}

{

"data": {

"type": "appScreenshots",

"id": "{id}",

"attributes": {

"uploaded": true

}

}

}

`

This process requires handling multipart uploads and checksums.

Tools and Libraries

Official Resources

  • [App Store Connect API Documentation](https://developer.apple.com/documentation/appstoreconnectapi)
  • [Apple's Sample Code](https://developer.apple.com/sample-code/)

Community Libraries

Various open-source libraries wrap the API:

  • **Node.js:** app-store-connect-api
  • **Python:** app-store-connect-api
  • **Ruby:** spaceship (via fastlane)

Fastlane Alternative

Fastlane's deliver action abstracts much of this complexity:

`

fastlane deliver --metadata_path ./metadata

`

Great for CI/CD pipelines, but requires local setup.

When to Build vs. Buy

Build Your Own Integration When:

  • You need custom workflow automation
  • You're integrating with existing systems
  • You want complete control

Use Existing Tools When:

  • You need to move fast
  • API complexity is a barrier
  • Maintenance overhead matters

Many developers find that dedicated localization tools save more time than they cost.

Security Best Practices

Protect Your Credentials

  • Never commit .p8 files to git
  • Use environment variables for keys
  • Rotate API keys periodically

Use Minimal Permissions

Create API keys with only the permissions needed:

  • App Manager for metadata updates
  • Developer for read-only access

Audit Access

Review who has API access regularly. Remove keys that aren't in use.

Summary

The App Store Connect API enables powerful automation for localization workflows. Key takeaways:

  • **Authentication uses JWT** with ES256 signing
  • **App-level and version-level fields** use different endpoints
  • **Each locale has a unique ID** you'll use for updates
  • **Rate limiting exists**—build in delays
  • **Screenshot upload is complex**—consider tools for this

For developers managing multiple apps across many locales, API automation is transformative. Start with metadata updates, then expand to screenshots as you get comfortable.

Ready to localize your app?

Start reaching international markets today with AI-powered localization.

Get Started Free