competitors について
指定市場でアプリの競合を見つけ、比較する AppFollow スキルです。検索での露出、カテゴリ順位、評価を分析し、追跡への追加はアプリごとの承認後に行います。
主な機能
- 01プラットフォームと地域別の検索結果調査
- 02出現回数と順位による競合選定
- 03検索カバレッジとカテゴリ順位の比較
- 04直近 30 日の評価と星別内訳の分析
- 05承認後の競合追跡への追加
活用シーン
- 01国ごとの直接的なアプリ競合の特定
- 02競合アプリ間のキーワード露出比較
- 03対象を上回る未追跡アプリの発見
- 04評価推移と低評価の割合の確認
MCP 対応
AppFollow MCP ツールでアプリを検索し、順位と評価データを取得します。ユーザーがアプリごとに承認すると、追跡対象へ追加できます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ appfollow/ appfollow-ai-toolkit --skill competitorsインストール後、Claude Code で/competitorsを入力して読み込まれたか確認します。
同梱ファイルreferences/report-template.html
詳細
競合他社
まず using-appfollow を読んでください(セッション開始、書き込みの手順、エラーコード)。
このスキルが答えるのは、この市場で実際に競合しているのは誰で、競合に対してどのような立ち位置にあるのかという問いだけです。MCP が生成できるデータのみを使用します。以下の内容はすべて実際の API で検証済みです。検証済みの制限に記載されている制約は仮定ではないため、楽観的な見通しに基づいて設計しないでください。
入力
ステップ 1 で対話しながら収集します。何も前提としません。
- app — 名前、ストアの URL、または
ext_id。ストアの URL を指定してもかまいません。そこから ID を解析してください(App Store の場合は/id<digits>、Google Play の場合は?id=<package>)。ASO 検索エンドポイントで受け付けるのはフリーテキストの検索語のみで、URL や ID は指定できません。 - platforms —
ios、android、または両方。storeとdeviceに対応します。iOS →as+iphone、Android →gp+android。 - region — 2 文字の国コードを1 つだけ。複数指定ではスキルを続行しません。1 つのリージョンの指定は必須であり、デフォルトではありません。市場によって結果が大きく異なるため、複数市場を混ぜた回答には意味がありません。
フロー
0. セッション
whoami(using-appfollow を参照)。
1. 範囲
アプリ、プラットフォーム、リージョンを 1 回のやり取りで尋ねます。ユーザーが一言で受け入れられる妥当なデフォルトを提示してもかまいませんが、リージョンを推測せず、必ず指定を求めてください。
次に、開始前に以下を明確に伝えます。
- 実行するプラットフォーム(各プラットフォームで独立した調査を行い、作業量は倍になります)。
- 監査には対象アプリがアカウントでトラッキングされている必要があること。ただし、競合の発見には必要ありません。
2. 対象アプリを特定する
list_collections → list_apps(apps_id = 各コレクションの collectionId)を、アプリの extId が見つかるまで実行します。ext_id、store(list_apps が返す長い名前を短いコードに変換します。itunes = as、googleplay = gp)、およびコレクションの apps_id を記録します。
- 見つかった場合 → 続行します。
- 見つからない場合 → ストア検索エンドポイントはアカウントの範囲に限定されないため、発見(ステップ 3)は引き続き実行できます。そのことを伝えて発見を行い、ステップ 5 で対象アプリ自体を追加するよう提案します。トラッキングが必要な監査セクションは、追加されるまで利用できないものとして扱います。
list_collections のコレクションに含まれる countries(各エントリの name)に指定されたリージョンがない場合は、そのことを伝えてください。処理は妨げられません(リージョンは呼び出しごとに渡されます)が、その市場のデータがアカウントにあまりない可能性があり、6.4 では記載の方法で代替します。
3. 発見のスイープ(このスキルの中核)
プラットフォームごとに、選択した国で次を実行します。
- 検索語のセットを作成します。 アプリのブランド名と、市場で使われている言語のカテゴリ一般語 3~5 個を使って
aso_search_suggestionsを実行します。独自に翻訳せず、ストアが返す語を使ってください。候補文字列に競合他社の名前が含まれることが多く、尋ねなくても手がかりを得られます。 - 検索語を 8 個選びます:カテゴリ一般語 5 個、アプリ独自のブランド名 1 個、競合ブランド名 2 個。6 個未満では検索シェアのノイズが大きくなり、10 個を超えても候補の順位が変わることはほとんどありません。
- スイープを実行します。
aso_search_results(term, country, device)。各レスポンスには、ext_id、title、artist_name、rating_avg、genre/genre_idを含む、順位付きの完全なリストが返されます。
すべてのレスポンスを保持してください。ステップ 3、4、および監査セクション 1~3 は、すべてこの 1 回のスイープ結果を参照します。再取得しないでください。
4. 選定
まずスイープ全体での出現回数、次に平均順位で候補を並べ替えます。プラットフォームごとに上位 3 件を提示し、それぞれについて出現回数(n/8)、最高順位と平均順位、パブリッシャー、ストア評価を示します。
次に、ユーザーが独自の競合アプリ名を入力できる自由記述欄を用意します。入力された名前ごとに aso_search_results を 1 回呼び出し、一致したアプリを確認してから追加します。
プラットフォームごとのリストでブランドが対称にならないのは正しく、問題ありません。 確認済みの例として、Just Eat は App Store では 1 つの ext_id ですが、Google Play では別々の 2 つのパッケージ(com.justeat.app.es と com.justeat.app.uk)があり、どちらも同じスペインの検索結果にランクインしています。ブランドではなく市場を基準に照合してください。スペインのアプリと英国のアプリを直接比較するのは、正しそうに見えて実際は誤った回答です。
5. トラッキングへの追加(唯一の書き込み経路)
選択した競合アプリごと、プラットフォームごとに、次の順序で実行します。add_app_preview → 書き込まれる内容をそのまま表示 → そのアプリについて明示的な承認を得る → 同じ引数とトークンを付けて add_app を実行します。引数は store(短縮コード)、ext_id、apps_id(対象のコレクション。対象がまだトラッキングされていない場合は、どのコレクションに追加するかを確認します)、locale(地域)、is_competitor: true です。これを指定しないと、競合アプリはユーザー自身のアプリとしてトラッキングされます。ここで対象アプリ自体を追加する場合は、デフォルトの is_competitor: false のままにします。
一括ではなく、アプリごとに確認を取ります。理由は 2 つあります。
- 競合アプリを 1 つ追加するたびに、競合枠を 1 つ消費します。
is_competitor: trueを指定して追加したアプリは、ユーザー自身のアプリ数とは別のプラン上限に含まれ、上限に達している場合は追加が拒否されます。これを明確に、数字を使わずに伝えてください。どちらの上限も返すエンドポイントがないため、「M 件中 N 件を使用」は提示できません。また、list_collectionsのコレクションごとのcountApps(ユーザー自身のアプリ数)とcountCompetitorsは、上限ではなく使用数です。アカウントの残り枠はダッシュボードでのみ確認できることを伝えてください。 - MCP には削除ツールがありません。 誤って追加したアプリは、誰かが AppFollow ダッシュボードで削除するまで枠を使い続けます。最初の書き込みを行う前に伝えてください。書き込み後ではいけません。
書き込み後、もう一度 list_apps を呼び出し、追加した各 extId が意図した isCompetitor の値で一覧に表示されることを確認します。list_apps はアプリが保存された国を返しません。また、locale: es を指定したリクエストが country: gb として保存された例があります。要求したロケールが保存されたと決して断言しないでください。保存された国は AppFollow ダッシュボードで確認できます。
add_app には機能制限ゲートがないため、プランによる拒否が FEATURE_DISABLED として返ることはありません。アプリ数または競合アプリ数の上限に達している場合は VALIDATION_ERROR が返され、その他の拒否には別のコードが付くことがあります。エラーが発生した場合、具体的な原因を断定しないでください。追加を完了できなかったこと、おそらくプラン上の制限によることを伝え、すでにトラッキングされているアプリで続行します。
6. 監査
以下の順序で 5 つのセクションを提示します。競合アプリを追加した時点ですぐに利用できるものが 2 つあり、解析サイクルが必要なものが 1 つあります。空のテーブルを表示するのではなく、レポート内でどれがどれかを説明してください。
6.1 検索シェア
ステップ 3 のスイープ結果から算出します。追加の呼び出しは不要です。検索語セット全体で、アプリごとに次の指標を示します。
- カバレッジ — N 個の検索語のうち、アプリが少なくとも 1 回表示された検索語の数
- 平均順位 — 表示された検索語での平均順位
- トップ 3 率 — 順位が 3 位以内の検索語の割合
対象アプリとすべての競合アプリを 1 つのテーブルで順位付けします。これは重み付けなしの指標です。人気スコアは使用しないため、すべての検索語を同じ重みで扱います。レポートでもそのように明記し、トラフィックで重み付けされているかのように示さないでください。
6.2 新たに見つかった競合アプリ
調査で確認した ext_id と list_apps に含まれるすべての項目を比較します。対象アプリよりも対象自身の条件で上位にランクインし、まだ追跡されていないアプリを、出現回数と最高順位とともに出力します。追加のリクエストは不要です。データはすでに揃っています。最後に、追加を提案します(手順 5 のルールを適用してください)。
意外な発見が繰り返し生まれるのが、このセクションです。検証済みの事例:顧客が独占していると思っていた検索クエリで、汎用的なOperaの「Local News」アプリが4位にランクイン。Google Playのスペイン語の汎用検索クエリ2件で、iFood(ブラジルのアプリ)が4位にランクイン。
6.3 カテゴリ順位
アプリごとに get_rankings(ext_id, country, device) を実行します。genre_id、feed_type、pos、行の date を報告します。
- カテゴリの不一致に注意してください。 ジャンルは、調査のSERPカード(
genre、genre_id)またはlist_appsから取得します。競合アプリが対象アプリと異なるカテゴリに属する場合は、その旨を明記し、異なる順位グループでのランクインであるため順位を比較できないことも記してください。実際に確認された事例:Glovoはライフスタイル(6012)に属する一方、直接の競合アプリはフード&ドリンク(6023)に属しています。 - 空のリストは通常、「ランキング圏外」を意味し、「未準備」ではありません。
get_rankingsは、直前に追加したアプリの順位を返します。検証済みの例:実行中に追加した競合アプリ2つは、前日付の順位を返しましたが、2023年から追跡している対象アプリは空のリストを返しました。そのため、空の結果は、そのアプリが当該国のカテゴリランキングで、ストアが公開している範囲には表示されないことを示すものと解釈するのが基本です。競合アプリの順位と並べてランキング圏外と報告してください。その対比が重要な発見です。 - データの鮮度が実際に問題となる場合に限り、断定を避けてください。 実行中に追加したアプリの順位が空で、さらに同じ呼び出しに含まれる他のアプリもすべて空だった場合は、ランキングではなく解析サイクルが原因かもしれません。データの収集に時間がかかる可能性があると伝え、おおよその日付を示し、再実行するための正確なコマンドを記載してください。ただし、同じバッチ内の他のアプリが順位を返した場合は、保留中であることを示す注記を決して記載しないでください。
6.4 過去30日間の平均評価
アプリごとに get_ratings_history(ext_id, store, from, to, country, period, type) を実行します。コレクションの参照は不要です。アプリは ext_id と短縮形の store コードで指定し、市場は country で指定します。
type: "diff"は累積値ではなく増分値です。このセクションの要点はここにあります。累積平均はほとんど変化しません(1か月で4.706 → 4.704という実績)。一方、増分平均は大きく変動します(同じアプリで8週間の間に4.617 → 4.673)。diffはApp Store専用です。store: "gp"とtype: "diff"の組み合わせは、呼び出し前に拒否されます(VALIDATION_ERROR、課金なし)。Androidではtype: "total"を呼び出し、累積平均と評価数を累積値と明記して報告します。新規評価の情報(ここでの増分平均と6.5の全項目)はAndroidでは取得できないため、そこから算出せず、その旨を伝えてください。diffモードでは、行のvalueはその期間に付けられた新規評価の平均です。算術計算で検証済みです:(108·1 + 13·2 + 66·3 + 220·4 + 1996·5) / 2403 = 4.658。返された値と小数第3位まで一致します。countryに指定できるコードは1つだけです(デフォルトはallで、全世界を対象)。そのため、呼び出しごとに国を1つずつ指定してください。料金は呼び出しごとに発生します。単一コードで正しく絞り込まれることは、対照試験で検証済みです(同じアプリでesとusでは異なる数値が返されました)。単一国の呼び出しが失敗した場合、またはアプリの結果が空だった場合は、そのアプリについて該当地域のデータを利用できないと報告し、country: "all"の利用を提案してください。その際は地域限定ではなく、全世界対象であることを明記します。period: "weekly"を指定すると、合計だけでなく内訳も得られます。最後の行は1~2日分の不完全な期間であることが多いため、合計から除外し、別途報告してください。- 追加初日から利用できます。 評価履歴はアプリの追加時に遡って補完されます。前日に追加したアプリで、8週間分の完全な履歴が返された事例があります。
6.5 過去30日間の新規評価と星評価の内訳
6.4と同じ呼び出しで、追加リクエストは不要です。対象はApp Storeのみです(6.4)。アプリごとに、新規評価の合計数
(starsTotal)と、starsから取得した内訳(stars1…stars5。それぞれcountとpercent)を、件数と割合の両方で報告します。
合計数ではなく、低評価(1~2★)の割合から説明してください。件数の差はたいてい規模の差にすぎません。流入が健全になっているか、悪化しているかを示すのは割合です。確認済みの例では、あるアプリの新規評価数は競合の5.7倍でしたが、低評価の割合はそれぞれ5.2%と5.0%でした。興味深いのは、インストール済みユーザー数に対して見ると、規模の小さいアプリのほうが速いペースで評価を集めていたことです。
数値から判断できる場合は、ベース数に対する比較も加えてください。対象期間中の新規評価数を、アプリの累計評価数で割ります。こうした単純な計算だけで、表面的な結論が覆ることは十分にあるため、計算する価値があります。ただし、これはApp Storeのみです。rating_cntはスイープのSERPカードから取得され、Google Playの行にはrating_avgがあってもrating_cntはありません。Androidでは、別の分母に置き換えず、この比較はできないと伝えてください。
結論を出す前に、不自然な急増がないか確認してください。 実際の例では、週ごとの件数が4、1、1と推移した後、ある週に158件(うち155件が5★)、さらに続く3日間で159件の評価があり、その159件すべてがちょうど2★でした。ほぼゼロの状態から単一の評価値が一様に並ぶのは、自然な動きではありません。このような形であれば、検証が必要だと明記し、そのアプリの評価状況を要約しないでください。このような系列から5つ星の割合が97.6%だと報告するくらいなら、何も報告しないほうがましです。
7. 出力
references/report-template.htmlを基にcompetitors-<app-slug>-<country>-<date>.htmlを作成し、appfollow.toolkit.findings/v1に準拠したfindings.jsonをreport_type: "competitors"で作成します。Claude CodeではHTMLをアーティファクトとして公開し、Codexではファイルを書き出してパスを伝えてください。ユーザー自身の接続済みトラッカーエージェントで調査結果を登録できることも伝えてください。
scopeは、共有スキーマですでに定義されている形式を維持します。つまり、type: "app"とし、appsには対象アプリのみを含めます。これはschemas/findings.schema.jsonの定義どおりです。競合は独立したトップレベルのcompetitorsブロックに記述し、scope.appsには含めないでください。enumには対象アプリと競合を含むレポートに対応する値がなく、競合をappsに紛れ込ませると、そのフィールド自身の説明に矛盾します。enumの拡張は別個の契約変更であり、このスキルの範囲外です。
{
"report_type": "competitors",
"scope": { "type": "app", "apps": [ { "store": "gp", "ext_id": "...", "title": "...", "country": "us", "device": "android" } ] },
"competitors": [ { "store": "gp", "ext_id": "...", "title": "...", "tracked_before_run": false } ]
}
各調査結果にはevidence[]{source:"mcp:<tool>", args, observed, at}を含め、レポート内の各数値を、その数値を生成した呼び出しまで追跡できるようにしてください。
確認済みの制限事項
制限に該当した場合は明示してください。制限を回避できると約束してはいけません。
| 制限事項 | 影響 |
|---|---|
トラッキングされていないアプリは拒否されます。コレクション apps_id に含まれない ext_id に対して、get_reviews は(データ呼び出しの前に)NOT_FOUND を返し、list_keywords と get_ratings_history は ACCESS_DENIED を返します | どのアプリでもディスカバリーは可能ですが、監査の各セクション(6.1 と 6.2 を除く)にはアプリのトラッキングが必要です |
| 削除ツールはありません | エージェントが追加したアプリは元に戻せず、枠は使用されたままになります |
枠の上限を取得するエンドポイントはありません。競合他社にも独自の上限があり、list_collections の countApps/countCompetitors は使用数であって、上限ではありません | 枠については数値を示さずに注意を促してください。実際の数値はダッシュボードでのみ確認できます |
add_app には機能ゲートがなく、アプリまたは競合他社の上限に達していると追加が拒否されます | ブロックは VALIDATION_ERROR、または FEATURE_DISABLED 以外のコードで示されます。原因を断定してはいけません |
保存された国は、リクエストした locale と異なる場合があり、list_apps にはその情報が表示されません | リクエストした locale が反映されたと断言してはいけません。保存された国はダッシュボードに表示されます |
get_rankings が空のリストを返す場合、通常はそのアプリが該当国のランキングに入っていないことを意味します。数分前に追加したアプリでは順位が返され、3年間トラッキングされているアプリでは何も返されませんでした | 「ランキング圏外」と報告してください。バッチ全体が空だった場合に限り、データの鮮度について留保を付けてください |
get_ratings_history は、gp に対する type: "diff" を拒否します(呼び出し前に VALIDATION_ERROR が返されます) | 増分平均と新規評価数の内訳(6.4~6.5)は App Store のみが対象です。Android では累積値の系列が取得されます |
get_ratings_history は1回の呼び出しにつき country を1つ受け取り(デフォルトは all で、全世界を指します)、呼び出しごとに料金が発生します | 国ごとに個別に呼び出してください。all の系列は全世界のデータとして表示してください |
Google Play は、完全一致するブランド名で検索した場合、1位の行の rating_avg: 0 を返します | ブランド名の検索結果の評価を参照してはいけません。一般的な検索語か評価履歴から取得してください |
Google Play の検索結果には rating_cnt がありません | 6.5 の基準値との比較は App Store のみが対象です |
App Store の SERP で詳細情報が付与されるのは最初の約12件のみで、それより下の順位は ext_id のみです | iOS では「上位N件に入っていない」という主張は、指定した範囲についてのみ述べてください。Google Play では全順位で完全な結果が返されるため、Android のディスカバリーのほうが信頼性が高いです |
| 同じブランドでも、ストアや市場が異なれば同じアプリとは限りません | 市場ごとに照合してください。一方のストアでは1つのIDでも、もう一方では国ごとにパッケージが異なる場合があります |
対象外
MCP にデータソースがないため、以下は提供しないでください。
- インストール数、ダウンロード数、MAU、収益、市場シェア。 保存済みの ASO レポートは連携機能が必要で、連携されていないアカウントでは
ASO Report Integration Not Foundで失敗します。ほかにデータソースはありません。 - SERP カードに記載されている情報以外の競合他社のメタデータ。 タイトル、サブタイトル、ジャンルは取得できますが、説明文と App Store のキーワードフィールドは取得できません。
- キーワード単位の直接比較。 このスキルでは意図的に対象外としています。対象には、その正確な(国、デバイス)の組み合わせで、アカウントがすでにキーワードをトラッキングしている必要があります。確認した5市場のうち3市場ではキーワードが空であり、新たに追加した競合他社のスコアを算出するには解析サイクルも必要です。
- 競合他社のターゲティングリストとしての Apple Search Ads。 試したすべてのアプリ(アカウント自身のアプリを含む)で、
aso_search_ads_recommendationsは空のkeywords配列を返しました。
失敗時の対応
どのセクションも実行全体を失敗させてはいけません。セクションをスキップし、エラーコードをそのままレポートに記載して、処理を続けてください。
- ストア検索で検索語の処理に失敗した場合 → その検索語を除外し、残りの検索語で検索シェアを再計算して、分母が変わったことを明記します。
get_rankingsが空の場合 → 6.3 に従い、日付を添えて保留として報告します。- あるアプリの
get_ratings_historyが失敗した場合 → ほかのアプリの結果を報告し、そのアプリの行は取得不可と明記します。 - いずれかのプラットフォームが完全に失敗した場合 → 何も出さないのではなく、もう一方のプラットフォームのレポートを提出します。