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

# Spec files

> Reference for appeeky.spec.yaml, listing files, every folder under appeeky/, releases, experiments and the playbook.

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
appeeky.spec.yaml                  # app, stores, targets, and everything Spec reads or watches
appeeky/
  store/
    app-store/<locale>.yaml        # one file per App Store locale (en-US, de-DE, ...)
    google-play/<language>.yaml    # one file per Play language (en-US, de-DE, ...)
  releases/<id>.yaml               # one file per push: what changed, why, and its checks
  experiments/<id>.yaml            # growth experiments outside the listing
  screenshots/app-store/<locale>/<display>/  # pulled App Store screenshots
  reviews/                         # reviews (JSONL per month), summary.md, replies/ to send
  competitors/                     # one file per competitor, changes.md
  visibility/                      # what AI assistants answer, per storefront
  seo/                             # Search Console and Google ranks for the website
  search-ads/                      # Apple Search Ads on your own key
  ads/<date>.yaml                  # saved by ads --save
  social/                          # social accounts, posts, drafts/ to send
  ugc/                             # creator personas, clips, briefs/ to make
  briefs/<date>.md                 # the weekly co-founder review
  category.csv                     # rank in the category chart, one row a day
  loops.md                         # every change being measured (written by status)
  playbook.md                      # what worked and what did not
  data/                            # only with data.commit: true
.appeeky/                          # cache, private data and rendered media, keep out of git
```

## appeeky.spec.yaml

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
version: 1
app:
  name: Sleep Sounds
  primaryLocale: en-US
stores:
  appStore:
    appId: "1234567890"        # numeric id or bundle id
    via: auto                  # auto | local | hosted
    account: my-team           # optional: saved appstore CLI account
    searchAds:                 # optional: Apple Search Ads on your own key
      orgId: "1234567"
      campaigns: ["987654"]
  googlePlay:
    packageName: com.example.sleep
    via: auto
    account: my-co             # optional: saved gps CLI account
targets:
  us: [sleep sounds, white noise, rain sounds, brown noise]
  de: [einschlafgeräusche, weißes rauschen]
storefronts:                   # optional
  us: [en-US, es-MX]
```

| Key | Meaning |
| - | - |
| `app.name` | Display name, used in reports and as the brand when checking for repeated words |
| `app.primaryLocale` | Default locale for `suggest` and new files |
| `stores.appStore.appId` | App Store app id. A numeric id also enables rank checks |
| `stores.appStore.platform` | `IOS` (default), `MAC_OS`, `TV_OS` or `VISION_OS` |
| `stores.googlePlay.packageName` | Google Play package name |
| `stores.*.via` | How to reach the store: `local` (your CLI and keys), `hosted` (Appeeky gateway), `auto` |
| `stores.*.account` | Named account saved with `appstore accounts add` or `gps accounts add`; default: the CLI's default account |
| `stores.appStore.searchAds.orgId` | Apple Search Ads organization, when the key reaches more than one |
| `stores.appStore.searchAds.campaigns` | Only these campaign ids; default: every campaign for this app |
| `targets` | Searches the app should be found for, per storefront (two-letter country code) |
| `storefronts` | Which App Store listing locales a storefront indexes. Leave it out to use Appeeky's defaults (for example, the US also reads `es-MX`) |

### Everything else in the spec

All optional. Each block is explained on the page that uses it.

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
competitors:
  - name: Calm Night
    appStore: "1234567891"
    googlePlay: com.calmnight.app
ads:
  meta:
    adAccount: act_1234567890      # optional: defaults to the account picked in Appeeky
    campaigns: ["120210000000001"]
  tiktok:
    advertiser: "7000000000000"    # optional
    campaigns: ["1790000000000"]
category:
  googlePlay: HEALTH_AND_FITNESS   # appStore: "6013" to override the genre
  chart: top-free                  # top-free | top-paid | top-grossing
  countries: [us, gb]
aiVisibility:
  store: app-store                 # which app to watch when it is on both stores
  countries: [us]
  models: [chatgpt, claude]        # --local: only these assistants
  aliases: [Sleep Sounds app]
  intents:
    us:
      - label: fall asleep to rain sounds
        prompts:
          - what app plays rain sounds to help me sleep
web:
  url: https://sleepsounds.app/
  searchConsole: sc-domain:sleepsounds.app
  keywords:
    us: [rain sounds, white noise app]
  countries: [us]
  device: mobile                   # mobile | desktop
attribution:
  via: self                        # self | hosted
  url: https://analytics.sleepsounds.workers.dev
  app: sleep-sounds                # or { app-store: …, google-play: … }
data:
  commit: false
personas:
  - id: sleepless-parent
    name: Sleepless parent
    description: Up at night with a newborn
    searches: [baby sleep sounds, white noise for baby]
```

| Key | Meaning | See |
| - | - | - |
| `competitors` | Apps you compete with: `name`, numeric `appStore` id and/or `googlePlay` package. `competitors discover --add <n>` fills it | [Commands](https://docs.appeeky.com/docs/spec-commands.md#competitors-pull) |
| `ads.meta`, `ads.tiktok` | The Meta and TikTok campaigns that promote this app; the ad account or advertiser defaults to the one picked in Appeeky. Apple Search Ads needs nothing here | [Experiments](https://docs.appeeky.com/docs/spec-experiments.md#paid-channels) |
| `category.appStore` | App Store genre id; read from the app when left out | [Commands](https://docs.appeeky.com/docs/spec-commands.md#category-pull) |
| `category.googlePlay` | Google Play category, needed for the Play chart | |
| `category.chart` | `top-free`, `top-paid` or `top-grossing`; default `top-paid` for a paid App Store app, `top-free` otherwise | |
| `category.countries` | Storefronts to record; default: the storefronts under `targets` | |
| `aiVisibility.store` | `app-store` or `google-play`, when the app is on both; default App Store | [AI answers](https://docs.appeeky.com/docs/spec-ai-visibility.md) |
| `aiVisibility.countries` | Storefronts to watch; default: the first under `targets` | |
| `aiVisibility.intents` | Per storefront: `label` (what people want, 8+ characters), optional `description`, and `prompts` (how they ask, 15+ characters each) | |
| `aiVisibility.models` | Which of `chatgpt`, `claude`, `gemini`, `perplexity` a `--local` scan asks; default: every one with a key set | |
| `aiVisibility.aliases` | Other names the assistants use for the app | |
| `web.url` | The app's website | [Website](https://docs.appeeky.com/docs/spec-website.md) |
| `web.searchConsole` | Search Console property (`sc-domain:example.com` or `https://example.com/`); default: the url's domain | |
| `web.keywords` | Google searches to watch with `seo ranks` and `seo keywords`, per storefront; default: the store targets. Only the storefronts in `web.countries` are watched | |
| `web.countries` | Storefronts to watch; default: the first under `keywords` or `targets` | |
| `web.device` | `mobile` (default) or `desktop` results page | |
| `attribution` | Appeeky Analytics: `via: self` with your server's `url` and `ATTRIBUTION_TOKEN`, or `via: hosted` with `APPEEKY_API_KEY`; `app` is one id, or one per store | [Commands](https://docs.appeeky.com/docs/spec-commands.md#attribution-init) |
| `data.commit` | `true` writes `data pull` output to `appeeky/data/` instead of the gitignored `.appeeky/data/` | |
| `personas` | Who the app is for: `id`, `name`, `description`, `searches`. Experiments, screenshots and UGC refer to them by `id` | [Experiments](https://docs.appeeky.com/docs/spec-experiments.md#personas) |

## Listing files

App Store, `appeeky/store/app-store/en-US.yaml`:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
name: "Sleep Sounds: Rain & Ocean"
subtitle: White noise, fan, lullaby
keywords: insomnia,relax,meditation,storm,thunder,baby,nap,calm,brown,pink
promotionalText: New: brown noise mixes.
description: |
  Fall asleep faster with ...
whatsNew: Bug fixes.
supportUrl: https://example.com/support
marketingUrl: https://example.com
```

Google Play, `appeeky/store/google-play/en-US.yaml`:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
title: Sleep Sounds - Rain & Ocean
shortDescription: White noise, rain and ocean sounds to fall asleep faster.
fullDescription: |
  ...
video: https://youtube.com/watch?v=...
```

Rules for every listing file:

* **A field you leave out is not managed.** It is never diffed or pushed. You can adopt the spec one field or one locale at a time.
* **`""` clears a field** on the store.
* **Values are compared the way the stores store them:** trailing spaces and line endings do not count as changes.

### Limits

| Store | Field | Limit |
| - | - | - |
| App Store | `name`, `subtitle` | 30 characters |
| App Store | `keywords` | 100 characters |
| App Store | `promotionalText` | 170 characters |
| App Store | `description`, `whatsNew` | 4000 characters |
| Google Play | `title` | 30 characters |
| Google Play | `shortDescription` | 80 characters |
| Google Play | `fullDescription` | 4000 characters |

All limits are in characters, the way App Store Connect and Play Console count them. A Cyrillic or Japanese letter is one character.

## Folders under appeeky/

| Path | Written by | What is in it |
| - | - | - |
| `releases/<id>.yaml` | `push`, `verify` | See [Releases](#releases) below |
| `experiments/<id>.yaml` | `experiment add`, `close`, `verify` | Hypothesis, one metric, baseline, target, check date, result |
| `screenshots/app-store/<locale>/<display>/` | `screenshots pull` | Live App Store screenshots |
| `reviews/<store>/<YYYY-MM>.jsonl` | `reviews pull` | One review per line: id, rating, title, body, territory or language, version, date, reply |
| `reviews/summary.md` | `reviews pull` | Last 30 days against the 30 before, stars per version, low ratings without a reply, words users use that no listing has |
| `reviews/replies/` | `reviews reply` | Drafted replies; `reviews push` sends them |
| `competitors/<name>.yaml` | `competitors pull` | Listing, version and notes, the 25 searches it ranks best for, where it ranks for your targets, recent low ratings |
| `competitors/changes.md` | `competitors pull` | New titles, versions, rewritten descriptions, climbs into the top 10 for your targets |
| `visibility/<country>.yaml` | `visibility pull`, `visibility scan --local` | Each intent `winning`, `weak` or `missing`, share of answers that name you per assistant, who is named instead, cited pages, fixes |
| `visibility/changes.md` | `visibility pull`, `scan --local` | What moved since the last pull |
| `visibility/history.csv`, `visibility/answers/<country>.jsonl` | `visibility scan --local` | One row per scan, intent and assistant; every answer |
| `seo/daily.csv`, `queries.csv`, `pages.csv`, `summary.md` | `seo pull` | Search Console clicks and impressions per day, top queries and pages |
| `seo/ranks.csv`, `ranks.md`, `changes.md` | `seo ranks` | Google positions of the site and the store page, AI Overview citations |
| `seo/keywords.csv` | `seo keywords` | Volume, difficulty, CPC, intent, related ideas |
| `seo/domain.md`, `ranked-keywords.csv` | `seo domain` | What the site ranks for, competing sites |
| `search-ads/daily.csv`, `keywords.csv`, `search-terms.csv`, `summary.md` | `search-ads pull` | Spend, installs, taps and impressions per day; keywords; search terms that installed and are not targets |
| `ads/<date>.yaml` | `ads --save` | Spend, installs and cost per install per channel |
| `social/accounts.yaml`, `posts.jsonl`, `summary.md` | `social pull` | Connected accounts, recent posts and their results |
| `social/drafts/<name>.yaml` | you, or the co-founder review | Posts to send after the merge; see [Social posts](https://docs.appeeky.com/docs/spec-social.md) |
| `ugc/personas.yaml`, `clips.jsonl` | `ugc pull` | Appeeky creator personas and their clips |
| `ugc/briefs/<name>.yaml` | you, or the co-founder review | Videos to make after the merge |
| `ugc/personas/<name>.yaml` | you | A persona kept in the repo with its look images, for `ugc generate --local` |
| `briefs/<YYYY-MM-DD>.md` | the co-founder review | What each specialist found, the change, what is for a person |
| `category.csv` | `category pull` | Category chart rank, one row a day per storefront and store |
| `loops.md` | `status`, `push`, `verify`, `experiment` | Every release and experiment being measured |
| `playbook.md` | `verify --playbook`, `experiment close --playbook`, you | What worked and what did not |
| `data/` | `data pull` with `data.commit: true` | Analytics, ads and revenue CSVs |

`.appeeky/` holds the keyword cache (`cache/`, 7 days), `data/` (private business numbers from `data pull`), `media/` (clips rendered with `ugc generate --local`) and `proposal.md` (the weekly review's pull request text). Keep it out of git.

## Releases

`push` writes one file per store per push to `appeeky/releases/`:

```yaml theme={"theme":{"light":"github-light","dark":"github-dark"}}
id: 2026-11-02T09-14-00Z-app-store
pushedAt: 2026-11-02T09:14:00.000Z
store: app-store
target: version 2.5.0 (prepare for submission)
via: local
note: Add brown noise to the US keyword field
changes:
  - locale: en-US
    field: keywords
    before: insomnia,relax,meditation,storm
    after: insomnia,relax,meditation,storm,brown
baseline:
  at: 2026-11-02T09:13:40.000Z
  source: Appeeky API
  ranks:
    us: { brown noise: 48, white noise: 12 }
checks:
  - day: 7
    verdict: won
    improved: [{ country: us, keyword: brown noise, before: 48, after: 21 }]
    dropped: []
    regressions: []
```

`verify` adds the `checks`. Edit the `note` freely; leave the rest to the CLI.

## Experiments

`experiment add` writes `appeeky/experiments/<id>.yaml` with a hypothesis, one metric, a baseline, a target and a check date. `experiment close` records the measured value and the result. See [Experiments and screenshots](https://docs.appeeky.com/docs/spec-experiments.md).

## Playbook

`appeeky/playbook.md` is plain Markdown. `verify --playbook` and `experiment close --playbook` append one line per result; you can write in it too. Agents read it before proposing a change, so failed ideas are not repeated.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.