---
name: metadata-optimization
description: Rewrite an app Product's App Store metadata — title, subtitle, keywords field, description, promotional text. Use for "optimize my title", "write my subtitle", "keywords field", "character limits", "app description". For a whole-listing audit use aso; for other markets use localization.
metadata:
  version: 1.0.0
---

# Metadata Optimization

Write App Store metadata that ranks for the Product's target keywords and converts the visitor who lands on the listing. Output is one `listing` Proposal per field and Locale, which Kwern writes to App Store Connect when the User approves it, plus a **metadata package** with the alternatives and the reasoning, saved with `save_output`.

## Gather

1. `read_context` — positioning, ICP, voice, competitors, target keywords if the Foundation doc names them.
2. `app_store_listing` — current name, description, genres.
3. `connector_asc_localizations` when the ASC Connector exists — the title, the subtitle, the promotional text and the private **keywords field** of every Locale, the primary first. Without it, treat the subtitle, the promotional text and the keywords field as unknown and say so in the package.
4. With the Apple Ads Connector: `connector_apple_ads_search_terms` for the search terms that already convert, `connector_apple_ads_suggestions` for the keywords the Run has not found yet, then `connector_apple_ads_search_term_popularity` on every candidate keyword in each storefront the package targets. Without it, infer keywords from the Foundation doc and the competitors' listings through `fetch_url` on iTunes Search (`https://itunes.apple.com/search?term=<name>&entity=software&country=<storefront>&limit=1`).
5. `connector_asc_analytics` when available — the page counts, the baseline the package must beat. Page conversion is `pageDownloads` ÷ `pageViews`, overall and per source type: `downloads` also counts the downloads made straight from search results, which no page view precedes, so divide the page downloads. Compare sources by their own rate, since a searcher and a browser convert differently, and quote a source's counts without a rate while it has fewer than 1,000 page views over the period.

The locale is the Product's primary storefront unless the Run says otherwise.

## Write

Rules for each field are in [`references/field-rules.md`](references/field-rules.md): limits, what is indexed, formulas, and the mistakes to flag. Apply them in this order, because each field must avoid the keywords the previous one already covers:

1. **Title** — brand + #1 keyword, three options with character counts.
2. **Subtitle** — secondary keywords, benefit-led, no word repeated from the title, three options.
3. **Keywords field** — 100 chars, comma-separated, no spaces, singular forms, no word already in title/subtitle, ranked by relevance × popularity and observed search-term performance.
4. **Description** — conversion only (not indexed): hook in the first 170 characters, social proof, four to six benefit bullets, how it works, a review quote drawn from `app_store_reviews`, call to action.
5. **Promotional text** — 170 chars, changeable without review; propose one for the current moment (launch, season, milestone).

## Output: metadata package

For every field: recommended version, alternative A (different keyword emphasis), alternative B (different positioning angle), each with `chars/limit`, keywords covered, one-line rationale. Then:

- **Keyword coverage matrix** — each target keyword × where it lands (title / subtitle / keywords field), so no keyword is covered twice and none is missing.
- **Before / after** — current vs recommended per field, with the keywords gained.
- **Apply** — which fields need a version the User can still edit in App Store Connect: title, subtitle, keywords field and description do; the promotional text does not.

## Propose

Each field you change is one `propose` per Locale, with `appStoreField` (`name` for the title, `subtitle`, `keywords`, `description`, `promotionalText`) and the Locale's code in `locale`: `content` is the recommended version, whole, and `why` names the keywords it gains and the baseline it must beat. The alternatives stay in the package.

Done when every changed field has its Proposal in every Locale the package targets, every target keyword appears in the matrix exactly once, every recommended field is within its limit, and the package names the data it lacked (keywords field, search terms, popularity, conversion) when a Connector was absent.

## Related Skills

- `aso` — full listing audit; run it first when the target keywords are unknown.
- `localization` — this package for other storefronts.
- `custom-product-pages` — variants of the description and screenshots per audience.
