---
name: pp-apptweak
description: "Every AppTweak endpoint in a local-first CLI — keyword rank fan-outs, competitor metadata diffs, and review mining that no MCP server can do. Trigger phrases: `check keyword rankings on AppTweak`, `pull AppTweak data`, `competitor ASO analysis`, `keyword rank history`, `use apptweak`, `app store rankings`."
author: "Ryan Kelley"
license: "Apache-2.0"
argument-hint: "<command> [args] | install cli|mcp"
allowed-tools: "Read Bash"
metadata:
  openclaw:
    requires:
      bins:
        - apptweak-pp-cli
    install:
      - kind: go
        bins: [apptweak-pp-cli]
        module: github.com/mvanhorn/printing-press-library/library/developer-tools/apptweak/cmd/apptweak-pp-cli
---
<!-- GENERATED FILE — DO NOT EDIT.
     This file is a verbatim mirror of library/developer-tools/apptweak/SKILL.md,
     regenerated post-merge by tools/generate-skills/. Hand-edits here are
     silently overwritten on the next regen. Edit the library/ source instead.
     See the repository agent guide, section "Generated artifacts: registry.json, cli-skills/". -->

# AppTweak — Printing Press CLI

## Prerequisites: Install the CLI

This skill drives the `apptweak-pp-cli` binary. **You must verify the CLI is installed before invoking any command from this skill.** If it is missing, install it first:

1. Install via the Printing Press installer. It defaults binaries to `$HOME/.local/bin` on macOS/Linux and `%LOCALAPPDATA%\Programs\PrintingPress\bin` on Windows:
   ```bash
   npx -y @mvanhorn/printing-press-library install apptweak --cli-only
   ```
2. Verify: `apptweak-pp-cli --version`
3. Ensure the reported install directory is on `$PATH` for the agent/runtime that will invoke this skill.

If the `npx` install fails (no Node, offline, etc.), fall back to a direct Go install (requires Go 1.26.10 or newer). This installs into `$GOPATH/bin` (default `$HOME/go/bin`), so add that directory to `$PATH` instead:

```bash
go install github.com/mvanhorn/printing-press-library/library/developer-tools/apptweak/cmd/apptweak-pp-cli@latest
```

If `--version` reports "command not found" after install, the runtime cannot see the binary directory on `$PATH`. Do not proceed with skill commands until verification succeeds.

The only CLI for AppTweak. Track keyword rankings across countries, diff competitor metadata changes, mine reviews by sentiment, and monitor paid vs organic keyword gaps — all stored in SQLite for offline analysis and CSV export. The AppTweak MCP servers cover individual queries; this CLI covers the workflows that require persistence, loops, and aggregation.

## When to Use This CLI

Use this CLI when an ASO team or agent needs to track keyword rankings over time, monitor competitor metadata changes, mine review sentiment, or audit paid keyword gaps across multiple countries. Best for workflows that require looping over countries/apps/keywords and persisting results for trend analysis.

## Anti-triggers

Do not use this CLI for:
- Real-time App Store Connect sales data — use ASC directly or the console endpoints which require integration setup
- Google Play Console data — requires account integration not available without setup
- Publishing or updating app listings — AppTweak is read-only intelligence

## Unique Capabilities

### Multi-country intelligence

- **`keywords rank-fanout`** — Check keyword rankings across many countries in one command — no MCP tool or competitor offers multi-country fan-out.

  _Use this when an ASO team needs a country-sweep ranking report without running the same query manually for each market._

  ```bash
  apptweak-pp-cli keywords rank-fanout --app 284882215 --keywords 'photo editor,camera' --countries us,gb,de,fr,jp --device iphone --json
  ```

### Competitor intelligence

- **`apps metadata-diff`** — Compare metadata between two app versions or two competitor apps to spot ASO experiments.

  _Use this to detect when a competitor changed their title, subtitle, or description — the primary signal of an ASO experiment._

  ```bash
  apptweak-pp-cli apps metadata-diff --app 284882215 --vs 389801252 --country us --device iphone --fields title,subtitle,description
  ```
- **`keywords paid-organic-gap`** — Find keywords a competitor bids on where your app doesn't rank organically — ASA opportunity map.

  _Use this to find Apple Search Ads opportunities where competitors are spending but your organic rank is absent._

  ```bash
  apptweak-pp-cli keywords paid-organic-gap --competitor 389801252 --app 284882215 --country us --device iphone --agent
  ```

### Local state that compounds

- **`keywords track`** — Sync and alert on ranking changes for a saved keyword basket across apps and countries.

  _Use this to monitor ranking changes for your core keyword set without re-querying or manually comparing runs._

  ```bash
  apptweak-pp-cli keywords track --app 284882215 --keywords 'photo,camera,selfie' --country us --device iphone --since 7d
  ```
- **`reviews sentiment`** — Aggregate review ratings by keyword term — find what topics drive 1-star vs 5-star reviews.

  _Use this to surface the specific complaint terms driving low ratings — faster than reading individual reviews._

  ```bash
  apptweak-pp-cli reviews sentiment --app 284882215 --country us --device iphone --word 'crash' --json
  ```

### Agent-native plumbing

- **`credits status`** — Check remaining API credits and burn rate before running expensive bulk queries.

  _Use this before bulk syncs to avoid hitting credit limits mid-run._

  ```bash
  apptweak-pp-cli credits status --json
  ```

`--ca-cert`, `APPTWEAK_CA_CERT`, or `ca_cert` adds a PEM CA bundle to the system trust roots. `--tls-server-name`, `APPTWEAK_TLS_SERVER_NAME`, or `tls_server_name` is the name checked against the certificate. Precedence is flag, then environment, then the config file. A config file other users can change does not supply these settings. `doctor` reports the trust in use and names the setting that fixes a chain or hostname failure.

## Command Reference

**apps** — Manage apps

- `apptweak-pp-cli apps get-category-ranking-current` — Current free, paid, or grossing chart position for one or more apps.
- `apptweak-pp-cli apps get-category-ranking-history` — Track category chart position over time.
- `apptweak-pp-cli apps get-keyword-rankings-current` — Rank position for a list of keywords across a country and device.
- `apptweak-pp-cli apps get-keyword-rankings-history` — Track keyword rank positions over time — core ASO monitoring endpoint.
- `apptweak-pp-cli apps get-metadata` — Title, subtitle, description, screenshots, ratings, developer info, languages, in-app purchases, and more.
- `apptweak-pp-cli apps get-metadata-history` — Track title, subtitle, description changes over a date range.
- `apptweak-pp-cli apps get-metrics-current` — Estimated downloads, revenues, and App Power score.
- `apptweak-pp-cli apps get-metrics-history` — Downloads, revenues, and App Power score over a date range.
- `apptweak-pp-cli apps get-paid-keywords` — Keywords an app bids on in Apple Search Ads — competitor paid strategy intelligence.
- `apptweak-pp-cli apps get-review-stats` — Rating distribution, average rating, review count over a date range.
- `apptweak-pp-cli apps get-reviews-displayed` — Reviews currently displayed in the App Store or Google Play for an app.
- `apptweak-pp-cli apps get-twin` — Find the Android equivalent of an iOS app or vice versa.
- `apptweak-pp-cli apps search-reviews` — Search through review text, filter by rating or date range. Requires tracked app.

**apptweak** — Manage apptweak

- `apptweak-pp-cli apptweak get-dna-list` — AppTweak's proprietary DNA sub-genre taxonomy identifiers.
- `apptweak-pp-cli apptweak get-supported-countries` — List all countries supported for a given store.
- `apptweak-pp-cli apptweak get-supported-languages` — List all supported language codes.

**categories** — Manage categories

- `apptweak-pp-cli categories get-category-metrics` — Aggregate downloads, revenue, and top performers for an App Store category.
- `apptweak-pp-cli categories get-conversion-rate-benchmarks` — Industry average conversion rates by category — benchmark your app's store listing performance.

**charts** — Manage charts

- `apptweak-pp-cli charts get-dna-current` — AppTweak's proprietary DNA sub-genre taxonomy charts — more granular than official categories.
- `apptweak-pp-cli charts get-top-current` — Current free, paid, or grossing chart for a category and country.
- `apptweak-pp-cli charts get-top-history` — How the free/paid/grossing chart changed over a date range.

**featured-content** — Manage featured content

- `apptweak-pp-cli featured-content` — When and in which editorial lists an app was featured (iOS only).

**keywords** — Manage keywords

- `apptweak-pp-cli keywords get-live-search-ads-current` — Apps running Apple Search Ads for a keyword right now.
- `apptweak-pp-cli keywords get-live-search-current` — Apps appearing in search results right now for a given keyword.
- `apptweak-pp-cli keywords get-metrics-current` — Search volume, difficulty score, and brand score for keywords.
- `apptweak-pp-cli keywords get-metrics-history` — Search volume and difficulty score trends over time.
- `apptweak-pp-cli keywords get-search-history` — How search results for a keyword changed over time.
- `apptweak-pp-cli keywords get-share-of-voice` — Ad impression share across all bidders for a keyword — identify dominant advertisers.
- `apptweak-pp-cli keywords get-suggestions-by-app` — Keyword ideas based on an app's install patterns — top installs, trending, or volume change.
- `apptweak-pp-cli keywords get-suggestions-by-category` — Highest-volume and trending keywords for an App Store category.


**apps**


- `apptweak-pp-cli apps metadata-diff` — Compare metadata between two app versions or two competitor apps to spot ASO experiments.


**credits**


- `apptweak-pp-cli credits status` — Check remaining API credits and burn rate before running expensive bulk queries.


**keywords**


- `apptweak-pp-cli keywords rank-fanout` — Check keyword rankings across many countries in one command — no MCP tool or competitor offers multi-country fan-out.

- `apptweak-pp-cli keywords track` — Sync and alert on ranking changes for a saved keyword basket across apps and countries.

- `apptweak-pp-cli keywords paid-organic-gap` — Find keywords a competitor bids on where your app doesn't rank organically — ASA opportunity map.


**reviews**


- `apptweak-pp-cli reviews sentiment` — Aggregate review ratings by keyword term — find what topics drive 1-star vs 5-star reviews.




### Finding the right command

When you know what you want to do but not which command does it, ask the CLI directly:

```bash
apptweak-pp-cli which "<capability in your own words>"
```

`which` resolves a natural-language capability query to the best matching command from this CLI's curated feature index. Exit code `0` means at least one match; exit code `2` means no confident match — fall back to `--help` or use a narrower query. `--json` (and other machine formats) keep that exit-2 contract and write `{"matches":[]}` on stdout so agents can inspect the envelope without treating a miss as success.

## Recipes


### Multi-country keyword rank sweep

```bash
apptweak-pp-cli keywords rank-fanout --app 284882215 --keywords 'photo editor,camera filter' --countries us,gb,de,fr,jp,kr --device iphone --json --select results.country,results.keyword,results.rank
```

Fan out keyword rank checks across 6 countries and extract just country/keyword/rank fields.

### Competitor metadata change detection

```bash
apptweak-pp-cli apps metadata-diff --app 284882215 --vs 389801252 --country us --device iphone --fields title,subtitle
```

Compare title and subtitle between two apps to spot competitor ASO experiments.

### Review sentiment for a complaint term

```bash
apptweak-pp-cli reviews sentiment --app 284882215 --country us --device iphone --word 'crash' --json --agent
```

Aggregate rating distribution for reviews mentioning 'crash' — identify if a term drives negative sentiment.

### Paid vs organic gap report

```bash
apptweak-pp-cli keywords paid-organic-gap --competitor 389801252 --app 284882215 --country us --device iphone --agent --select gap_keywords
```

Find keywords where the competitor bids but your app has no organic ranking — prime Apple Search Ads targets.

## Auth Setup

Set APPTWEAK_API_KEY to your AppTweak API token. The key is sent as the x-apptweak-key header on every request. Get your key at https://developers.apptweak.com.

Run `apptweak-pp-cli doctor` to verify setup.

## Agent Mode

Add `--agent` to any command. Expands to: `--json --compact --no-input --no-color`.

Global format flags share one contract on promoted, novel, sync, and `--deliver` paths:

- `--json` — one JSON document on stdout (sync progress events go to stderr)
- `--compact` — keep identity/status/timestamp fields; does not change the document vs stream shape
- `--csv` / `--plain` — tabular rows (collection envelopes unwrap to the row array). `--csv` prefixes `'` on a cell or header key that starts with `=`, `+`, `-`, `@`, tab, CR, or LF (fullwidth `＝＋－＠` too) so a spreadsheet does not run it as a formula; a plain signed number such as `-5` or `+2.5e3` is unchanged.
- `--quiet` — one identity value per row, no envelope

- **Pipeable** — JSON on stdout, errors on stderr
- **Filterable** — `--select` keeps a subset of fields. Dotted paths descend into nested structures; arrays traverse element-wise. Critical for keeping context small on verbose APIs:

  ```bash
  apptweak-pp-cli apps get-category-ranking-current --apps 324684580 --country us --device iphone --agent
  ```
- **Previewable** — `--dry-run` shows the request without sending
- **Offline-friendly** — sync/search commands can use the local SQLite store when available
- **Non-interactive** — never prompts, every input is a flag
- **Read-only** — do not use this CLI for create, update, delete, publish, comment, upvote, invite, order, send, or other mutating requests

### Response envelope

Commands that read from the local store or the API wrap output in a provenance envelope:

```json
{
  "meta": {"source": "live" | "local", "synced_at": "...", "reason": "..."},
  "results": <data>
}
```

Parse `.results` for data and `.meta.source` to know whether it's live or local. A human-readable `N results (live)` summary is printed to stderr only when stdout is a terminal AND no machine-format flag (`--json`, `--csv`, `--compact`, `--quiet`, `--plain`, `--select`) is set — piped/agent consumers and explicit-format runs get pure JSON on stdout.

## Paths and state

Agents should treat the CLI's path resolver as part of the runtime contract:

- Use `--home <dir>` for one invocation, or set `APPTWEAK_HOME=<dir>` to relocate all four path kinds under one root.
- Use per-kind env vars only when a specific kind must diverge: `APPTWEAK_CONFIG_DIR`, `APPTWEAK_DATA_DIR`, `APPTWEAK_STATE_DIR`, `APPTWEAK_CACHE_DIR`.
- Resolution order is per-kind env var, `--home`, `APPTWEAK_HOME`, XDG (`XDG_CONFIG_HOME`, `XDG_DATA_HOME`, `XDG_STATE_HOME`, `XDG_CACHE_HOME`), then platform defaults.
- `config` contains settings like `config.toml` and profiles. `data` contains `credentials.toml`, `data.db`, cookies, and auth sidecars. `state` contains persisted queries, jobs, and `teach.log`. `cache` contains regenerable HTTP/cache files.
- Stored secrets live in `credentials.toml` under the data dir. Existing legacy `config.toml` secrets are read for compatibility and leave `config.toml` on the first auth write.
- Run `apptweak-pp-cli doctor --fail-on warn` to surface path and credential-location warnings. `agent-context` exposes a schema v4 `paths` block for agents that need the resolved dirs.
- For MCP, pass relocation through the MCP host config. The MCP binary does not inherit CLI flags:

  ```json
  {
    "mcpServers": {
      "apptweak": {
        "command": "apptweak-pp-mcp",
        "env": {
          "APPTWEAK_HOME": "/srv/apptweak"
        }
      }
    }
  }
  ```

Fleet precedence: an inherited per-kind env var overrides an explicit `--home` for that kind. Use `APPTWEAK_HOME` or per-kind vars as durable fleet levers, and use `--home` only for a single invocation. Relocation is not reversible by unsetting env vars; move files manually before clearing `APPTWEAK_HOME`, or `doctor` will not find credentials left under the former root.

Local data is unencrypted and relies on OS account permissions plus disk encryption. Reads in the default `--data-source auto` mode are written to the SQLite store; GET responses are cached for five minutes under the cache dir. `local-data purge` previews what it would erase (store files, response cache, learn journal) and deletes only with `--yes`; it is not exposed over MCP. `APPTWEAK_NO_LOCAL_DATA=1` disables the response cache and store writes, turns `auto` reads into live reads, and blocks `sync` and `workflow archive`; `--data-source local` still reads an existing store, and `APPTWEAK_DATA_SOURCE` sets the `--data-source` default.

## Automatic learning

This CLI ships a self-capturing learning loop. The CLI does its own bookkeeping: every invocation is journaled locally, a failed flag followed by a corrected retry auto-derives a `flag_alias` candidate, and a `teach` on a query family without a playbook auto-synthesizes a `playbook_candidate` from the session's journal. Your job is judgment only: `recall` first, act on surfaced candidates, `teach` the final answer, `playbook amend` when you observe a correction. You never record failures by hand.

### Step 1: `recall` before any discovery

Before list/search/drill commands on a new user question, pass the question as an argv or MCP tool argument to `recall --agent`. Do not interpolate user-controlled text into a shell command line.

Quoted `recall "<question>"` breaks on an apostrophe, which is ordinary English. A quoted heredoc breaks when a body line equals the delimiter, and that delimiter is published in these docs. Write the question with a non-shell file-writing tool, then read it back as data:

```bash
# Write the question verbatim with your file-writing tool (no shell involved).
# Command substitution on a file only ever yields data — the shell never
# parses the file's bytes as syntax.
QUERY=$(cat /path/to/question.txt)
apptweak-pp-cli recall "$QUERY" --agent
```

Prefer MCP: pass the question as the tool's query argument. `"$QUERY"` after a file read is argv-safe; putting the question itself in the command text is not.

The response envelope:

```json
{
  "query": "...",
  "normalized": "<normalized form>",
  "query_entities": ["..."],
  "found": true | false,
  "match_score": 0.0,
  "results": [
    { "resource_id": "...", "resource_type": "...", "venue": "...",
      "confidence": 2, "entity_match": "exact|partial|unknown",
      "source": "taught|preseed|pattern", "warnings": ["..."] }
  ],
  "mismatches": [ /* only when --debug-mismatches */ ],
  "warnings": [ /* top-level */ ],
  "candidates": [
    { "id": 12, "class": "flag_alias | playbook_candidate",
      "summary": "...", "sightings": 3, "last_seen": "...",
      "rationale": "...",
      "next_action": ["<trial command>", "apptweak-pp-cli learnings confirm 12"] }
  ],
  "playbook": {
    "query_family": "...",
    "playbook": {
      "steps": [ { "cmd": "<command with {slot} substitution>", "purpose": "..." } ],
      "entity_slots": ["$ENTITY"],
      "expected_tool_calls": 3
    },
    "slots_resolved": { "$ENTITY": { "token": "<live token>", "canonical": "<canonical>" } },
    "notes": "<workarounds + gotchas for this query family>"
  },
  "notes": "<duplicate surface for non-playbook callers>"
}
```

Empty-store short-circuit: if the store has no learnings, playbooks, or candidates yet (recall finds nothing and `learnings list` and `learnings candidates` are both empty), skip recall for the re