app-store-review-arbitrage
競合のApp StoreまたはGoogle Play URLを入力するだけで、ワンセッションで使えるGTMブリーフを生成します。優先順位付きの苦情クラスタ、約束と実態の乖離マップ、ランディングページの見出し、広告コピーの方向性——すべて実際のレビューから抽出します。
重要ルール(Step 1の前に必読)
以下のルールは全ステップに適用されます。違反するとSelf-QA(Step 6)で失敗します。
- すべての引用は原文ママであること。 言い換え、文法修正、クリーニングは禁止。レビュアーの言葉をそのまま使用します。
- 統計データの捏造禁止。 レビュアーが明示的に類似の言葉を使っていない限り、「40%高速化」「2倍信頼性向上」などと記述しないでください。Self-QAステップでは、引用元のないパーセンテージをチェックします。
- クラスタ名はレビュアーの言葉を使用すること。 Step 3のアンチパターン表を参照してください。
- すべての見出しと広告コピーの方向性は、そのソースクラスタを引用すること。 形式:
[cluster: "クラスタ名"] - セクション2は常に出力に含めること。 たとえ劣化状態であっても。省略してはいけません。
- 生成するコピーに禁止ワードを使用しないこと: powerful, robust, seamless, innovative, game-changing, streamline, leverage, revolutionize, transform
Step 1 — 入力の解析とプラットフォームの検出
1つのアプリURLを含む自然言語プロンプトを受け付けます。URLを抽出します。
プラットフォーム検出:
apps.apple.com→ App Storeplay.google.com/store/apps/details?id=→ Google Play- その他のURL → 処理を停止し、「直接のApp StoreまたはGoogle Play URLを提供してください。他のソースからのレビューデータは分析できません。」と応答します。
ID抽出(スクリプト実行前に行うこと):
| プラットフォーム | 抽出するもの | 方法 |
|---|---|---|
| App Store | 数値の app_id | URL内の /id の後の数字 |
| App Store | country | apps.apple.com/ の後の2文字コード(例: us, gb) |
| Google Play | package_name | id= クエリパラメータの値 |
抽出した値は保持しておきます。Step 7で出力ファイル名に必要です。
ユーザーのプロンプトに product_context(自社製品の説明)が含まれている場合は、それを保存します。Step 5でコピーをパーソナライズするために使用します。
Step 2 — レビューとメタデータの収集
フルフェッチスクリプトを実行します:
python3 scripts/fetch_reviews.py "{app_url}" --output {tmpdir}/asr-raw.json
(注: {tmpdir} はオペレーティングシステムの一時ディレクトリに置き換えてください。例: macOS/Linuxでは /tmp、Windowsでは C:\Temp)
これにより、ストアの説明メタデータとレビューの両方が取得されます。
- App Store: iTunes API — 無料、認証不要。App StoreのレビューはAppleの公開iTunes RSSフィードを介して取得されます。AppleのAPI制限によりレビューが0件になるアプリもあります。その場合は、利用可能なデータで処理を続行し、警告をログに記録します。Google Playが主要な対応パスです。
- Google Play:
google-play-scraperパッケージ — 無料、認証不要
スクリプトが失敗した場合は、stderrからエラーを読み取ります。一般的な原因:
- パッケージがインストールされていない:
pip install google-play-scraperを実行 - アプリが見つからない: URLが現在有効な公開リストであることを確認
- Google Play APIエラー:
pip install --upgrade google-play-scraperを実行して再試行
スクリプトは収集の進行状況をstderrに出力します。完了するまで待ちます。完了後、{tmpdir}/asr-raw.json を読み取り、収集サマリーをユーザーに表示します:
✓ [N]件のレビュー(うち低評価1〜3★ [N]件)を [プラットフォーム] から収集しました
期間: [最古] 〜 [最新]
パッケージ: [iTunes API | google-play-scraper]
終了コードを確認:
- 終了コード0 → 収集成功。
metadata.store_descriptionを確認。nullの場合は、その旨をメモします — セクション2は劣化状態になります。Step 3に進みます。 - 終了コード1 → エラー(stderrメッセージを読み取り、ユーザーに表示して停止)
- 終了コード2 → ゲート1発動(低評価レビューが10件未満)
ゲート1 — シグナル不足による停止: スクリプトが終了コード2で終了した場合、{tmpdir}/asr-raw.json から gate_message を読み取り、そのままユーザーに表示します。Step 3には進みません。部分的なブリーフは生成しません。
Step 3 — 苦情のクラスタリング
{tmpdir}/asr-raw.json から low_star_reviews を読み込みます。
すべての低評価レビューを 4〜6個の名前付き苦情テーマ にクラスタリングします。各レビューのスコアは以下の式で計算します:
complaint_weight = (4 - 評価) × 最近性係数
最近性係数:
レビュー経過日数 ≤ 90日 → 1.0
レビュー経過日数 91〜365日 → 0.7
レビュー経過日数 > 365日 → 0.4
レビュー経過日数 = (今日の日付)−(レビューの date フィールド)の日数。
cluster_score = そのクラスタ内のすべてのレビューの complaint_weight の合計。
クラスタ名 — 重要ルール:
抽象的な名前をつけたくなるでしょう。それを抑えてください。レビュー内の正確な動詞と名詞を使用します。
| ❌ 抽象化(誤り) | ✅ レビュアーの言葉(正しい) |
|---|---|
| "安定性の問題" | "PDFにエクスポートするときにクラッシュする" |
| "同期の問題" | "電話とデスクトップ間の同期後にデータが失われた" |
| "収益化の摩擦" | "約束の14日後ではなく、3日後にペイウォールが表示される" |
| "パフォーマンス低下" | "検索するたびにアプリがフリーズする" |
| "オンボーディングの問題" | "チームメイトを招待する方法がわからない" |
ルール:
- 各レビューは正確に1つのクラスタに属する(主要テーマに割り当てる)
- レビューが3件未満のクラスタは破棄 — ノイズとして記録
- クラスタごとに3〜4個の原文引用を選択: まず最も低い星評価、次に最も新しいもの
ゲート2 — 最小クラスタサイズ: 3件未満のクラスタを破棄した後、残っているクラスタの数を確認します。
ゲート3 — 低信頼性フラグ: 残ったクラスタが3個未満の場合:
- 停止しないでください。出力を続行します。
- ブリーフヘッダーのアプリメタデータの直後に以下を先頭に追加します:
⚠ 低信頼性: 最小エビデンス基準(裏付けレビュー3件以上)を満たした苦情クラスタは [N] 個のみです。出力は限られたデータを反映しています。より多くのレビューを持つ競合を検討するか、評価フィルタを広げてください。
- 出力にMedium層のクラスタ(スコア5以上)を含めます
層の分類(セクション1のリーダーボード表用):
- Critical: スコア60以上
- High: スコア15〜59
- Medium: スコア5〜14(ゲート3が適用される場合のみ含める)
- Noise: スコア5未満(破棄、含めない)
クラスタを {tmpdir}/asr-clusters.json に書き込みます:
{
"clusters": [
{
"name": "レビュアーの言葉でのクラスタ名",
"score": 34.5,
"tier": "High",
"review_count": 14,
"verbatim_quotes": [
{"rating": 1, "text": "レビュアーの正確な言葉", "date": "YYYY-MM-DD"},
...
]
}
],
"discarded_noise": 2,
"gate_3_triggered": false
}
Step 4 — 約束と実態の乖離検出
このステップが、このスキルを既存のツールと差別化するものです。明確な名前付きステップとして実行する必要があります。
以下を読み込みます:
{tmpdir}/asr-raw.jsonのmetadata.store_description{tmpdir}/asr-clusters.jsonのすべてのクラスタ
store_description が null の場合: store_description_available: false を設定します。{tmpdir}/asr-promises.json に空の broken_promises 配列と、以下で指定する detection_note を書き込みます。Step 5に進みます。
ストアの説明が利用可能な場合:
-
主張を抽出します。 主張とは、アプリの動作に関する具体的で検証可能な主張のことです。完全な定義と例については
references/broken-promise.mdを参照してください。漠然とした最上級表現、チームの説明、プレスからの引用は除外します。 -
クロスリファレンスします。 各主張について、すべてのクラスタ名と原文引用をチェックします。クラスタがその約束された動作の失敗を直接文書化している場合(最低3件のレビュー)、矛盾が存在します。
-
ブロークンプロミスレコードを生成します — 確認された矛盾ごとに1つ:
{ "claim_text": "ストア説明からの原文", "complaint_cluster": "正確なクラスタ名", "gap_label": "「X」と主張するが、ユーザーはYと報告", "evidence_count": 18 }
{tmpdir}/asr-promises.json に書き込みます:
{
"store_description_available": true,
"broken_promises": [...],
"no_contradictions_found": false,
"detection_note": null
}
劣化状態:
- 説明なし:
store_description_available: false、detection_note: "ストアの説明が利用できません(YYYY-MM-DDに取得、空を返しました)。ブロークンプロミスの比較は実行できません。" - 矛盾なし:
no_contradictions_found: true、detection_note: "ブロークンプロミスは検出されませんでした。ストアの説明は苦情クラスタと比較して過剰主張しているようには見えません。"
アンチパターン(フラグを立てるべきでないもの)については references/broken-promise.md を参照してください。
Step 5 — コピーの生成
Step 3のクラスタとStep 4のブロークンプロミスを使用して、ブリーフのセクション3〜5を生成します。
コピールール(3つのセクションすべてに適用):
- すべての見出しと方向性は、そのソースクラスタを引用すること:
[cluster: "クラスタ名"] - 禁止ワードを使用しない: powerful, robust, seamless, innovative, game-changing, streamline, leverage, revolutionize, transform
- 統計データの捏造禁止 — レビュアーが使用していない限り、パーセンテージや数値は記載しない
product_contextが提供された場合: 「Say this」の方向性をその製品の機能に特化させる。提供されていない場合: ユーザーが埋めるポジショニングテンプレートとして記述する。- 見出しにはレビュアーの言葉を使用 — 実際のレビューテキストから派生させるか引用する
セクション3 — ランディングページH1バンク(3〜5個の見出し):
- 各:
"[見出しテキスト]" [cluster: "クラスタ名"] - 可能な限り8単語以内
- 不満を抱えるユーザーに直接語りかける
セクション4 — 広告コピーの方向性(正確に3組):
クラスタ: [クラスタ名]
それではなく: "[競合が主張していること、または一般的な弱い代替案]"
これを言え: "[苦情エビデンスに基づいた反論]"
エビデンス: [N]人のレビュアーが [原文の苦情サマリー] と報告
セクション5 — アンチクレーム警告:
- Step 4のブロークンプロミスごとに1つの警告
- セクション2が劣化状態の場合: 単一の注意書き(正確な文言については
references/brief-format.mdを参照)
Step 6 — 自己QA
保存する前に、生成されたブリーフが以下のチェックに合格しているか確認します。いずれかのチェックが失敗した場合は、該当する項目を修正して再確認します — 不合格のブリーフは保存しません。
| チェック | ルール |
|---|---|
| 原文引用が存在する | すべてのクラスタに2件以上の引用がある |
| 禁止ワードがない | セクション3〜5に9つの禁止ワードが1つも現れない |
| 引用元のないパーセンテージがない | 出力内のすべての % はレビュアーの実際の言葉に遡れる必要がある |
| すべてのコピーが引用されている | すべての見出しと「これを言え」に [cluster: "名前"] の引用がある |
| クラスタ数が1以上 | 少なくとも1つのクラスタがゲート2/3を生き残っている |
| セクション2が存在する | セクション2が出力に(任意の状態で)現れる |
| 引用の評価が3以下 | すべての原文引用は1〜3★のレビューからのもの |
クラスタ数に関する注記: 合格ブリーフの最小クラスタ数は1つです(3つではありません)。ゲート3の低信頼性フラグは、3つ未満のクラスタが生き残った場合を処理します — これは警告であり、失敗ではありません。自己QAは、クラスタが0個の場合にのみ失敗します。
Step 7 — 出力の保存
references/brief-format.md の形式に従って完全なブリーフを組み立てます。
以下に保存します:
docs/review-briefs/[app-id]-[YYYY-MM-DD].md
docs/review-briefs/ ディレクトリが存在しない場合は作成します。
完全なブリーフをユーザーに出力します。
一時ファイルをクリーンアップします: {tmpdir}/asr-raw.json、{tmpdir}/asr-clusters.json、{tmpdir}/asr-promises.json。