App Store Metadata
Manage App Store metadata and optimize for ASO using EAS Metadata.
What is EAS Metadata?
EAS Metadata automates App Store presence management from the command line using a store.config.json file instead of manually filling forms in App Store Connect. It includes built-in validation to catch common rejection pitfalls.
Current Status: Preview, Apple App Store only.
Getting Started
Pull Existing Metadata
If your app is already published, pull current metadata:
eas metadata:pullThis creates store.config.json with your current App Store configuration.
Push Metadata Updates
After editing your config, push changes:
eas metadata:pushImportant: You must submit a binary via eas submit before pushing metadata for new apps.
Configuration File
Create store.config.json at your project root:
{
"configVersion": 0,
"apple": {
"copyright": "2025 Your Company",
"categories": ["UTILITIES", "PRODUCTIVITY"],
"info": {
"en-US": {
"title": "App Name",
"subtitle": "Your compelling tagline",
"description": "Full app description...",
"keywords": ["keyword1", "keyword2", "keyword3"],
"releaseNotes": "What's new in this version...",
"promoText": "Limited time offer!",
"privacyPolicyUrl": "https://example.com/privacy",
"supportUrl": "https://example.com/support",
"marketingUrl": "https://example.com"
}
},
"advisory": {
"alcoholTobaccoOrDrugUseOrReferences": "NONE",
"gamblingSimulated": "NONE",
"medicalOrTreatmentInformation": "NONE",
"profanityOrCrudeHumor": "NONE",
"sexualContentGraphicAndNudity": "NONE",
"sexualContentOrNudity": "NONE",
"horrorOrFearThemes": "NONE",
"matureOrSuggestiveThemes": "NONE",
"violenceCartoonOrFantasy": "NONE",
"violenceRealistic": "NONE",
"violenceRealisticProlongedGraphicOrSadistic": "NONE",
"contests": "NONE",
"gambling": false,
"unrestrictedWebAccess": false,
"seventeenPlus": false
},
"release": {
"automaticRelease": true,
"phasedRelease": true
},
"review": {
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]",
"phone": "+1 555-123-4567",
"notes": "Demo account: [email protected] / password123"
}
}
}App Store Optimization (ASO)
Title Optimization (30 characters max)
The title is the most important ranking factor. Include your brand name and 1-2 strongest keywords.
{
"title": "Budgetly - Money Tracker"
}Best Practices:
- Brand name first for recognition
- Include highest-volume keyword
- Avoid generic words like "app" or "the"
- Title keywords boost rankings by ~10%
Subtitle Optimization (30 characters max)
The subtitle appears below your title in search results. Use it for your unique value proposition.
{
"subtitle": "Smart Expense & Budget Planner"
}Best Practices:
- Don't duplicate keywords from title (Apple counts each word once)
- Highlight your main differentiator
- Include secondary high-value keywords
- Focus on benefits, not features
Keywords Field (100 characters max)
Hidden from users but crucial for discoverability. Use comma-separated keywords without spaces after commas.
{
"keywords": [
"finance,budget,expense,money,tracker,savings,bills,income,spending,wallet,personal,weekly,monthly"
]
}Best Practices:
- Use all 100 characters
- Separate with commas only (no spaces)
- No duplicates from title/subtitle
- Include singular forms (Apple handles plurals)
- Add synonyms and alternate spellings
- Include competitor brand names (carefully)
- Use digits instead of spelled numbers ("5" not "five")
- Skip articles and prepositions
Description Optimization
The iOS description is NOT indexed for search but critical for conversion. Focus on convincing users to download.
{
"description": "Take control of your finances with Budgetly, the intuitive money management app trusted by over 1 million users.\n\nKEY FEATURES:\n• Smart budget tracking - Set limits and watch your progress\n• Expense categorization - Know exactly where your money goes\n• Bill reminders - Never miss a payment\n• Beautiful charts - Visualize your financial health\n• Bank sync - Connect 10,000+ institutions\n• Cloud backup - Your data, always safe\n\nWHY BUDGETLY?\nUnlike complex spreadsheets or basic calculators, Budgetly learns your spending habits and provides personalized insights. Our users save an average of $300/month within 3 months.\n\nPRIVACY FIRST\nYour financial data is encrypted end-to-end. We never sell your information.\n\nDownload Budgetly today and start your journey to financial freedom!"
}Best Practices:
- Front-load the first 3 lines (visible before "more")
- Use bullet points for features
- Include social proof (user counts, ratings, awards)
- Add a clear call-to-action
- Mention privacy/security for sensitive apps
- Update with each release
Release Notes
Shown to existing users deciding whether to update.
{
"releaseNotes": "Version 2.5 brings exciting improvements:\n\n• NEW: Dark mode support\n• NEW: Widget for home screen\n• IMPROVED: 50% faster sync\n• FIXED: Notification timing issues\n\nLove Budgetly? Please leave a review!"
}Promo Text (170 characters max)
Appears above description; can be updated without new binary. Great for time-sensitive promotions.
{
"promoText": "🎉 New Year Special: Premium features free for 30 days! Start 2025 with better finances."
}Categories
Primary category is most important for browsing and rankings.
{
"categories": ["FINANCE", "PRODUCTIVITY"]
}Available Categories:
- BOOKS, BUSINESS, DEVELOPER_TOOLS, EDUCATION
- ENTERTAINMENT, FINANCE, FOODANDDRINK
- GAMES (with subcategories), GRAPHICSANDDESIGN
- HEALTHANDFITNESS, KIDS (age-gated)
- LIFESTYLE, MAGAZINESANDNEWSPAPERS
- MEDICAL, MUSIC, NAVIGATION, NEWS
- PHOTOANDVIDEO, PRODUCTIVITY, REFERENCE
- SHOPPING, SOCIAL_NETWORKING, SPORTS
- STICKERS (with subcategories), TRAVEL
- UTILITIES, WEATHER
Localization
Localize metadata for each target market. Keywords should be researched per locale—direct translations often miss regional search terms.
{
"info": {
"en-US": {
"title": "Budgetly - Money Tracker",
"subtitle": "Smart Expense Planner",
"keywords": ["budget,finance,money,expense,tracker"]
},
"es-ES": {
"title": "Budgetly - Control de Gastos",
"subtitle": "Planificador de Presupuesto",
"keywords": ["presupuesto,finanzas,dinero,gastos,ahorro"]
},
"ja": {
"title": "Budgetly - 家計簿アプリ",
"subtitle": "簡単支出管理",
"keywords": ["家計簿,支出,予算,節約,お金"]
},
"de-DE": {
"title": "Budgetly - Haushaltsbuch",
"subtitle": "Ausgaben Verwalten",
"keywords": ["budget,finanzen,geld,ausgaben,sparen"]
}
}
}Supported Locales: ar-SA, ca, cs, da, de-DE, el, en-AU, en-CA, en-GB, en-US, es-ES, es-MX, fi, fr-CA, fr-FR, he, hi, hr, hu, id, it, ja, ko, ms, nl-NL, no, pl, pt-BR, pt-PT, ro, ru, sk, sv, th, tr, uk, vi, zh-Hans, zh-Hant
Dynamic Configuration
Use JavaScript for dynamic values like copyright year or fetched translations.
Basic Dynamic Config
// store.config.js
const baseConfig = require("./store.config.json");
const year = new Date().getFullYear();
module.exports = {
...baseConfig,
apple: {
...baseConfig.apple,
copyright: `${year} Your Company, Inc.`,
},
};Async Configuration (External Localization)
// store.config.js
module.exports = async () => {
const baseConfig = require("./store.config.json");
// Fetch translations from CMS/localization service
const translations = await fetch(
"https://api.example.com/app-store-copy"
).then((r) => r.json());
return {
...baseConfig,
apple: {
...baseConfig.apple,
info: translations,
},
};
};Environment-Based Config
// store.config.js
const baseConfig = require("./store.config.json");
const isProduction = process.env.EAS_BUILD_PROFILE === "production";
module.exports = {
...baseConfig,
apple: {
...baseConfig.apple,
info: {
"en-US": {
...baseConfig.apple.info["en-US"],
promoText: isProduction
? "Download now and get started!"
: "[BETA] Help us test new features!",
},
},
},
};Update eas.json to use JS config:
{
"cli": {
"metadataPath": "./store.config.js"
}
}Age Rating (Advisory)
Answer content questions honestly to get an appropriate age rating.
Content Descriptors:
NONE- Content not presentINFREQUENT_OR_MILD- Occasional mild contentFREQUENT_OR_INTENSE- Regular or strong content
{
"advisory": {
"alcoholTobaccoOrDrugUseOrReferences": "NONE",
"contests": "NONE",
"gambling": false,
"gamblingSimulated": "NONE",
"horrorOrFearThemes": "NONE",
"matureOrSuggestiveThemes": "NONE",
"medicalOrTreatmentInformation": "NONE",
"profanityOrCrudeHumor": "NONE",
"sexualContentGraphicAndNudity": "NONE",
"sexualContentOrNudity": "NONE",
"unrestrictedWebAccess": false,
"violenceCartoonOrFantasy": "NONE",
"violenceRealistic": "NONE",
"violenceRealisticProlongedGraphicOrSadistic": "NONE",
"seventeenPlus": false,
"kidsAgeBand": "NINE_TO_ELEVEN"
}
}Kids Age Bands: FIVE_AND_UNDER, SIX_TO_EIGHT, NINE_TO_ELEVEN
Release Strategy
Control how your app rolls out to users.
{
"release": {
"automaticRelease": true,
"phasedRelease": true
}
}Options:
automaticRelease: true- Release immediately upon approvalautomaticRelease: false- Manual release after approvalautomaticRelease: "2025-02-01T10:00:00Z"- Schedule release (RFC 3339)phasedRelease: true- 7-day gradual rollout (1%, 2%, 5%, 10%, 20%, 50%, 100%)
Review Information
Provide contact info and test credentials for the App Review team.
{
"review": {
"firstName": "Jane",
"lastName": "Smith",
"email": "[email protected]",
"phone": "+1 (555) 123-4567",
"demoUsername": "[email protected]",
"demoPassword": "ReviewDemo2025!",
"notes": "To test premium features:\n1. Log in with demo credentials\n2. Navigate to Settings > Subscription\n3. Tap 'Restore Purchase' - sandbox purchase will be restored\n\nFor location features, allow location access when prompted."
}
}ASO Checklist
Before Each Release
- [ ] Update keywords based on performance data
- [ ] Refresh description with new features
- [ ] Write compelling release notes
- [ ] Update promo text if running campaigns
- [ ] Verify all URLs are valid
Monthly ASO Tasks
- [ ] Analyze keyword rankings
- [ ] Research competitor keywords
- [ ] Check conversion rates in App Analytics
- [ ] Review user feedback for keyword ideas
- [ ] A/B test screenshots in App Store Connect
Keyword Research Tips
- Brainstorm features - List all app capabilities
- Mine reviews - Find words users actually use
- Analyze competitors - Check their titles/subtitles
- Use long-tail keywords - Less competition, higher intent
- Consider misspellings - Common typos can drive traffic
- Track seasonality - Some keywords peak at certain times
Metrics to Monitor
- Impressions - How often your app appears in search
- Product Page Views - Users who tap to learn more
- Conversion Rate - Views → Downloads
- Keyword Rankings - Position for target keywords
- Category Ranking - Position in your categories
VS Code Integration
Install the Expo Tools extension for:
- Auto-complete for all schema properties
- Inline validation and warnings
- Quick fixes for common issues
Common Issues
"Binary not found"
Push a binary with eas submit before pushing metadata.
"Invalid keywords"
- Check total length is ≤100 characters
- Remove spaces after commas
- Remove duplicate words
"Description too long"
Description maximum is 4000 characters.
Pull doesn't update JS config
eas metadata:pull creates a JSON file; import it into your JS config.
CI/CD Integration
Automate metadata updates in your deployment pipeline:
# .eas/workflows/release.yml
jobs:
submit-and-metadata:
steps:
- name: Submit to App Store
run: eas submit -p ios --latest
- name: Push Metadata
run: eas metadata:pushTips
- Update metadata every 4-6 weeks for optimal ASO
- 70% of App Store visitors use search to find apps
- Apps with 4+ star ratings get featured more often
- Localized apps see 128% more downloads per country
- First 3 lines of description are most critical (shown before "more")
- Use all 100 keyword characters—every character counts