mcpField
C
competitors

competitors

github.com/appfollow营销与增长468 次安装今天更新
代码仓库

关于 competitors

该 AppFollow 技能根据指定市场的 ASO 搜索结果发现并比较应用竞争者,面向需要评估市场对手的团队。它还提供排名、评分与新增评分分析,并以逐项确认控制跟踪写入。

主要功能

  1. 01按平台和地区扫描搜索结果
  2. 02按出现频次与排名筛选竞争者
  3. 03比较搜索覆盖率与类别排名
  4. 04分析近 30 天评分及星级分布
  5. 05逐个确认后添加竞争者跟踪

适用场景

  1. 01为应用识别特定国家的直接竞争者
  2. 02比较目标应用与竞争者的关键词曝光
  3. 03发现搜索结果中未跟踪的竞争应用
  4. 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 — 恰好一个两字母国家代码。此技能不会在提供多个国家代码时继续执行。必须指定一个地区,而不是使用默认值:不同市场的结果差异足够大,混合后的答案没有意义。

流程

0. 会话

whoami(参见 using-appfollow)。

1. 范围

在一轮对话中询问 app、平台和地区。提供合理的默认选项,供用户用一个词确认,但不要猜测地区——必须要求用户指定。

开始前,明确说明:

  • 将运行哪些平台(每个平台都是一次独立的扫描,工作量会翻倍)。
  • 审计需要目标 app 已在账户中跟踪;发现竞争对手则不需要。
2. 确定目标 app

依次执行 list_collections → list_apps(apps_id = 每个集合的 collectionId),直到找到 app 的 extId。记录 ext_id、store(list_apps 返回完整名称——映射为短代码:itunes = as,googleplay = gp)和集合的 apps_id。

  • 已找到 → 继续。
  • 未找到 → 仍可进行发现(步骤 3),因为商店搜索端点不受账户范围限制。说明这一点,运行发现,并在步骤 5 中询问用户是否要添加目标 app。需要跟踪的审计部分在 app 添加前会标记为不可用。

如果 list_collections 中集合的 countries(每个条目的 name)不包含用户指定的地区,请告知用户——这不会阻止操作(每次调用都会传入地区),但账户可能在该市场的数据较少;6.4 会按该处说明进行回退。

3. 扫描发现结果(此技能的核心)

针对所选国家的每个平台:

  1. 生成种子词集。 对 app 品牌名以及 3–5 个该市场语言的品类通用词调用 aso_search_suggestions。使用商店返回的内容,不要自行翻译——建议词字符串中经常会出现竞争对手名称,这能提供有用信号,无需专门询问用户。
  2. 选取 8 个词:5 个品类通用词 + app 自身品牌名 + 2 个竞争对手品牌词。少于 6 个会导致搜索份额数据噪声过大;超过 10 个通常不会改变候选项排名。
  3. 扫描。 aso_search_results(term, country, device)。每个响应都是完整的排名列表,包含 ext_id、title、artist_name、rating_avg、genre/genre_id。

保留每个响应:步骤 3、4 和审计部分 1–3 都会读取这次扫描结果。不要重新获取。

4. 选择

先按整个扫描中出现的次数对候选项排序,再按平均排名排序。每个平台列出前 3 名,并为每项显示:出现次数(n/8)、最佳排名和平均排名、发布者、商店评分。

然后提供一个自由文本字段,让用户填写自己的竞品名称,以替代或补充你列出的竞品。 对每个输入的名称,调用一次 aso_search_results 解析,并在添加任何内容前确认匹配到的应用。

各平台的列表不会在品牌上完全对称,这是正确的。 已验证:Just Eat 在 App Store 上是一个 ext_id,但在 Google Play 上是两个独立的软件包(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。

逐个确认每个应用,而非一次确认整批应用。原因有两个:

  • 每个竞品都会占用一个竞品名额。 添加时设置 is_competitor: true 的应用会占用套餐的竞品上限;该上限与用户自有应用的上限分开,达到上限后将无法添加。请直白说明这一点,不要提供数字:没有任何端点会报告这两种上限,因此无法得知“已使用 N / M”;而 list_collections 返回的每个集合的 countApps(自有应用数)和 countCompetitors 是使用量,不是容量。请说明账户剩余容量只能在控制面板中查看。
  • 整个 MCP 中没有任何移除工具。 误添加的应用会一直占用名额,直到有人在 AppFollow 控制面板中将其删除。请在首次写入前说明这一点,而不是事后说明。

写入后,再次调用 list_apps,并确认每个已添加的 extId 均已列出,且 isCompetitor 的值符合预期。list_apps 不会报告应用保存时所用的国家/地区;曾有一个 locale: es 的请求被保存为 country: gb——绝不能声称请求的地区就是实际保存的地区;保存的国家/地区会显示在 AppFollow 控制面板中。

add_app 没有功能门控,因此套餐限制不会以 FEATURE_DISABLED 返回:应用数或竞品数达到上限时会返回 VALIDATION_ERROR,其他拒绝也可能返回其他代码。遇到任何错误时,不要指出具体原因:告知用户添加未能完成,可能是套餐限制所致,然后继续处理已经跟踪的应用。

6. 审核

按以下顺序分为五个部分。其中两个部分在添加竞品后即可生成;另一个部分需要等待解析周期。请在报告中说明哪些部分可立即生成,而不要输出空表格。

6.1 搜索份额

根据第 3 步的扫描结果计算,无需额外调用。针对每个搜索词,按应用统计:

  • 覆盖率——应用至少出现一次的 N 个搜索词数量
  • 出现时的平均排名
  • 前三名率——排名 ≤ 3 的搜索词占比

在同一张表中排列目标应用和所有竞品。该指标为未加权:每个搜索词的权重相同,因为没有使用人气评分。请在报告中明确标注这一点,不要暗示结果按流量加权。

6.2 新发现的竞品

将本次扫描中看到的 ext_id 与 list_apps 中的所有条目进行比对。输出排名超过目标、且尚未跟踪的应用,并列出出现次数和最佳排名。不要发起额外请求——所需数据已在手中。最后询问是否要添加这些应用(适用步骤 5 的流程)。

本节反复带来意外发现。已验证的示例:在客户以为自己占据优势的搜索词下,一款通用的 Opera“本地新闻”应用排名第 4;在 Google Play 上,巴西应用 iFood 在两个西班牙语通用搜索词下都排名第 4。

6.3 类别排名

对每个应用调用 get_rankings(ext_id, country, device)。报告 genre_id、feed_type、pos 和该行的 date。

  • 标记类别不匹配。 从扫描结果的 SERP 卡片(genre、genre_id)或 list_apps 中获取类别。如果竞品与目标应用所属类别不同,请明确说明,并指出两者在不同的排名榜单中排名,因此排名不可比较。已验证的真实案例:Glovo 属于 Lifestyle(6012),而其直接竞品属于 Food & Drink(6023)。
  • 空列表通常表示“未上榜”,而不是“尚未就绪”。 get_rankings 会返回刚添加的应用的排名——已验证:运行期间添加的两款竞品都返回了前一天日期的排名,而自 2023 年起就已跟踪的目标应用却返回空列表。因此,空结果默认应解读为该应用未出现在该国家商店所提供深度的类别榜单中。请将其报告为未上榜,并与竞品的排名并列,因为这种对比正是发现所在。
  • 仅在确实可能受数据新鲜度影响时才使用保留说法。 如果应用是在本次运行中添加、排名为空,且同一次调用中的其他应用也都返回空结果,原因可能是解析周期,而非榜单本身。请说明数据可能需要时间收集,给出大致日期,并附上可重新运行的确切命令——但如果同一批次中的其他应用已返回排名,则绝不要注明排名待出。
6.4 过去 30 天的平均评分

对每个应用调用 get_ratings_history(ext_id, store, from, to, country, period, type)——无需查询集合:应用由其 ext_id 和短 store 代码标识,市场由 country 标识。

  • type: "diff"——表示增量,而非累计值。本节的重点就在于此:累计平均分几乎不动(观察到一个月内从 4.706 变为 4.704),而增量平均分却会显著变化(同一应用在 8 周内从 4.617 变为 4.673)。
  • diff 仅适用于 App Store。 在 Android 上,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,与返回值精确到小数点后三位一致。
  • country 必须且只能填写一个代码(默认值 all,表示全球),因此每次调用只循环查询一个国家;每次调用都会单独计费。单个代码可正确筛选——已通过对照验证(同一应用的 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★),接着三天内又收到 159 条评分,且 全部 159 条 都恰好是 2★。在评分量接近于零之后,出现全部集中在单一评分值的情况并非自然现象。若数据呈现这种形态,应标记为需要核实,并拒绝据此概述该应用的评分健康状况——根据这样的序列报告 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 上,写入文件并告知用户文件路径。告诉用户,他们自己的已连接跟踪器 Agent 可以提交这些发现。

scope 应沿用共享架构已定义的结构——type: "app",且 apps 中包含唯一的目标应用,与 schemas/findings.schema.json 中的定义完全一致。竞品应放在独立的顶层 competitors 区块中,绝不能放在 scope.apps 内:枚举中没有适用于目标加竞品报告的取值,而将竞品塞入 apps 会与该字段自身的说明相矛盾。扩展枚举属于单独的契约变更,不属于此技能的职责。

{
  "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 外,审计的每个部分都要求应用已被跟踪
不存在移除工具Agent 添加应用后无法撤销;已占用的名额会一直占用
没有名额上限查询端点;竞品也有各自的上限,list_collections 中的 countApps / countCompetitors 表示用量,而非容量提醒用户存在名额限制,但不要给出具体数字;实际数值只能在仪表板中查看
add_app 没有功能门控;应用或竞品名额已满时,添加操作会被拒绝拒绝会返回 VALIDATION_ERROR 或其他非 FEATURE_DISABLED 代码——不要推断原因
已存储的国家/地区可能与请求的 locale 不同,且 list_apps 不会报告此信息绝不可声称请求的 locale 已生效;仪表板会显示已存储的国家/地区
空的 get_rankings 列表通常表示该应用未进入该国家/地区的榜单——几分钟前添加的应用返回了排名,跟踪了 3 年的应用却没有返回结果报告“未上榜”;仅当整个批次都为空时,才对数据时效性加以保留说明
对 gp 使用 type: "diff" 时,get_ratings_history 会拒绝请求(VALIDATION_ERROR,发生在任何调用之前)增量平均评分和新增评分拆分(6.4–6.5)仅适用于 App Store;Android 提供累计序列
get_ratings_history 每次调用只接受一个 country(默认为 all,即全球范围),每次调用都单独计费每次调用循环处理一个国家/地区;将 all 系列标注为全球范围
Google Play 在精确品牌名称查询中,会为排名第 1 的结果返回 rating_avg: 0绝不可读取品牌词结果中的评分;应从通用词或评分历史中获取
Google Play 搜索结果不包含 rating_cnt6.5 中相对于基准的解读仅适用于 App Store
App Store SERP 仅为前约 12 条结果补充详细信息;更靠后的结果只有裸 ext_id在 iOS 上,“未进入前 N 名”仅指明示的窗口范围。Google Play 始终返回完整结果,因此 Android 端的发现更可靠
同一品牌 ≠ 在不同商店和市场中属于同一个应用按市场匹配;一个商店可能只有一个 id,而另一个商店可能在每个国家/地区都有一个 package

不在范围内

不要提供以下内容——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 失败 → 报告其他应用,并将该应用的行标记为不可用。
  • 一个平台完全失败 → 提交另一个平台的报告,不要什么都不交。

评论

支持 Markdown