Fetches low-star App Store and Google Play reviews, clusters them into broken-promise patterns, and generates a ranked copy brief with positioning opportunities.
How this skill is triggered — by the user, by Claude, or both
Slash command
/opendirectory-gtm-skills:app-store-review-arbitrageThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Convert a competitor's App Store or Google Play URL into a one-session GTM brief: ranked complaint clusters, a broken promise map, landing page headlines, and ad copy directions — all sourced from verbatim reviews.
Convert a competitor's App Store or Google Play URL into a one-session GTM brief: ranked complaint clusters, a broken promise map, landing page headlines, and ad copy directions — all sourced from verbatim reviews.
These rules apply throughout all steps. Violating any of them fails Self-QA (Step 6).
[cluster: "cluster-name"].Accept a natural language prompt containing one app URL. Extract the URL.
Platform detection:
apps.apple.com → App Storeplay.google.com/store/apps/details?id= → Google PlayID extraction (do this before calling the script):
| Platform | What to extract | How |
|---|---|---|
| App Store | Numeric app_id | Digits after /id in the URL |
| App Store | country | 2-letter code after apps.apple.com/ (e.g., us, gb) |
| Google Play | package_name | Value of id= query parameter |
Persist the extracted values — you will need them for the output filename in Step 7.
If product_context was provided in the user's prompt (what their own product does), store it — used to personalise copy in Step 5.
Run the full fetch script:
python3 scripts/fetch_reviews.py "{app_url}" --output {tmpdir}/asr-raw.json
(Note: Replace {tmpdir} with your operating system's temp directory, e.g., /tmp on macOS/Linux or C:\Temp on Windows).
This fetches both the store description metadata and the reviews.
google-play-scraper package — free, no authIf the script fails, read the error from stderr. Common causes:
pip install google-play-scraperpip install --upgrade google-play-scraper and retryThe script will print collection progress to stderr. Wait for it to complete. After completion, read {tmpdir}/asr-raw.json and display the collection summary to the user:
✓ Collected [N] reviews ([N] low-star 1–3★) from [platform]
Date range: [oldest] to [newest]
Package: [iTunes API | google-play-scraper]
Check the exit code:
metadata.store_description. If null: note this — Section 2 will use the degraded state. Proceed to Step 3.Gate 1 — Low signal stop: If the script exits with code 2, read the gate_message from {tmpdir}/asr-raw.json and surface it to the user verbatim. Do not proceed to Step 3. Do not produce a partial brief.
Load low_star_reviews from {tmpdir}/asr-raw.json.
Cluster all low-star reviews into 4–6 named complaint themes. Apply this formula to score each review:
complaint_weight = (4 - rating) × recency_factor
recency_factor:
review age ≤ 90 days → 1.0
review age 91–365 days → 0.7
review age > 365 days → 0.4
review age = (today's date) − (review date field) in days.
cluster_score = sum of complaint_weight for all reviews in the cluster.
Cluster naming — critical rule:
You will want to write abstract names. Resist. Use the exact verb and noun from reviews.
| ❌ Abstracted (wrong) | ✅ Reviewer language (correct) |
|---|---|
| "Stability issues" | "Crashes when exporting to PDF" |
| "Sync problems" | "Data lost after sync between phone and desktop" |
| "Monetisation friction" | "Paywall appears after 3 days, not 14 as promised" |
| "Performance degradation" | "App freezes every time I search" |
| "Onboarding issues" | "Can't figure out how to invite a teammate" |
Rules:
Gate 2 — Minimum cluster size: After discarding sub-3-review clusters, check how many clusters remain.
Gate 3 — Low-confidence flag: If fewer than 3 clusters remain:
⚠ LOW CONFIDENCE: Only [N] complaint cluster(s) met the minimum evidence threshold (≥ 3 supporting reviews). Output reflects limited data. Consider a competitor with more reviews, or broaden the rating filter.
Tier classification (for the leaderboard table in Section 1):
Write clusters to {tmpdir}/asr-clusters.json:
{
"clusters": [
{
"name": "cluster name in reviewer language",
"score": 34.5,
"tier": "High",
"review_count": 14,
"verbatim_quotes": [
{"rating": 1, "text": "exact reviewer words", "date": "YYYY-MM-DD"},
...
]
}
],
"discarded_noise": 2,
"gate_3_triggered": false
}
This is the step that differentiates this skill from every existing tool. It must run as a distinct, named step.
Load:
metadata.store_description from {tmpdir}/asr-raw.json{tmpdir}/asr-clusters.jsonIf store_description is null: Set store_description_available: false. Write {tmpdir}/asr-promises.json with empty broken_promises array and detection_note as specified below. Proceed to Step 5.
If store description is available:
Extract claims. A claim is any specific, testable assertion about app behavior. See references/broken-promise.md for the full definition and examples. Exclude vague superlatives, team descriptions, and press quotes.
Cross-reference. For each claim, check all cluster names and verbatim quotes. A contradiction exists when the cluster directly documents failure of the promised behavior (minimum 3 reviews).
Produce broken promise records — one per confirmed contradiction:
{
"claim_text": "verbatim excerpt from store description",
"complaint_cluster": "exact cluster name",
"gap_label": "Claims X; users report Y",
"evidence_count": 18
}
Write to {tmpdir}/asr-promises.json:
{
"store_description_available": true,
"broken_promises": [...],
"no_contradictions_found": false,
"detection_note": null
}
Degraded states:
store_description_available: false, detection_note: "Store description unavailable (fetched YYYY-MM-DD, returned empty). Broken promise comparison cannot be performed."no_contradictions_found: true, detection_note: "No broken promises detected. Store description does not appear to overclaim relative to complaint clusters."See references/broken-promise.md for anti-patterns (what NOT to flag).
Using clusters from Step 3 and broken promises from Step 4, generate Sections 3–5 of the brief.
Copy rules (apply to all three sections):
[cluster: "cluster-name"]product_context was provided: make "Say this" directions specific to that product's features. If not: write as positioning templates the user fills in.Section 3 — Landing Page H1 Bank (3–5 headlines):
"[headline text]" [cluster: "cluster-name"]Section 4 — Ad Copy Directions (exactly 3 pairs):
Cluster: [cluster name]
Not that: "[what the competitor claims or a generic weak alternative]"
Say this: "[counter-claim grounded in complaint evidence]"
Evidence: [N] reviewers reported [verbatim complaint summary]
Section 5 — Anti-Claim Warnings:
references/brief-format.md for exact wording)Before saving, verify the generated brief against these checks. If any check fails, fix the specific item and re-verify — do not save a failing brief.
| Check | Rule |
|---|---|
| Verbatim quotes present | Every cluster has ≥ 2 verbatim quotes |
| No banned words | None of the 9 banned words appear in Sections 3–5 |
| No uncited percentages | Any % in output must trace to a reviewer's actual words |
| All copy cited | Every headline and "Say this" has a [cluster: "name"] citation |
| Cluster count ≥ 1 | At least one cluster survived Gates 2/3 |
| Section 2 present | Section 2 appears in the output (in any state) |
| Quote ratings ≤ 3 | All verbatim quotes came from 1–3★ reviews |
Note on cluster count: The minimum for a passing brief is 1 cluster (not 3). The Gate 3 low-confidence flag handles cases where < 3 clusters survive — that is a warning, not a failure. Self-QA fails only if 0 clusters exist.
Assemble the full brief per the format in references/brief-format.md.
Save to:
docs/review-briefs/[app-id]-[YYYY-MM-DD].md
Create the docs/review-briefs/ directory if it does not exist.
Print the full brief to the user.
Clean up temp files: {tmpdir}/asr-raw.json, {tmpdir}/asr-clusters.json, {tmpdir}/asr-promises.json.
npx claudepluginhub varnan-tech/opendirectory --plugin opendirectory-gtm-skillsAudits App Store and Google Play listings against ASO best practices. Fetches live data, scores metadata and visuals, and produces a prioritized action plan.
Audits and optimizes App Store and Google Play listings. Fetches live metadata, visuals, and ratings, scores against ASO best practices, and produces a prioritized action plan.
Provides ASO toolkit for keyword research, competitor analysis, metadata optimization, review sentiment, and performance tracking on Apple App Store and Google Play.