← Plugin catalog
Business & Operations

AppFollow

AppFollow v1.2.2

Analyze Reviews, Ratings & ASO

Create a free account to save this plugin.

From the developer

Declared capabilities

  • Interactive
  • Read
  • Write

Not specified in the available declarations: limitations, pricing & account requirements.

Onboarding example

Find and track our app on the App Store.
Sources & dates

Developer declarations; not independently tested. Listing last checked Nov 6, 2026. Package observed Nov 6, 2026.

View package source →

Description

From the marketplace listing

User ratings, reviews & ASO for App Store, Google Play, Trustpilot, Steam, Mac App Store, Microsoft Store, Samsung Galaxy Store, Huawei AppGallery, and more. Connect your AppFollow account via MCP for ratings, reviews, replies, AI summaries, rankings, keywords, apps & workspaces.

Language: English · Automatically detected from descriptions.

Changes

No changes recorded yet. Follow this plugin to keep track of future changes.

First seen Oct 30, 2026. Last seen Nov 6, 2026.

Keywords

Files & skills

File archives

Plugin package31 files · 158 KBBrowse files →
Skill instructions
aso-analysis7.37 KB

View saved version →

---
name: aso-analysis
description: >
  ASO performance for an app or collection — tracked-keyword positions and (gate-iv-gated) trends,
  category-rank trend, keyword opportunities with competitor context, an interactive add-keyword loop
  (the only write path), and honest metadata suggestions. Emits a structured findings.json plus a
  self-contained HTML report. Trigger on "ASO report", "keyword rankings", "keyword opportunities",
  "how do we rank for <keyword>", "suggest keywords to add".
---

# aso-analysis

Read `using-appfollow` first (session, write ritual, error codes).

## Inputs

- **scope:** app, whole collection, or a **user-chosen subset of apps from one collection** (e.g. "just
  these 3 apps from my <collection>"). For a subset: resolve the collection via `list_collections`, list
  its apps via `list_apps`, then gather ASO data for only the chosen apps — emit `scope.type:
  "collection_subset"` with `collection_name` set and `apps` = the chosen subset (not the full
  collection). Spanning **multiple** collections in one report is not supported yet (deferred).
- **countries:** default 1 primary.
- **devices:** App Store → `iphone`, `ipad`; Google Play → `android`.
- **keyword seeds** (optional).

## Default depth

Estimate ≈ `A×C×D×[S×P×10 (list_keywords) + S×10 (get_rankings)] + A×C×[K_seed×5 (suggestions) +
K_serp×10 (search)] + A(as)×10 (search_ads) + A×10 (aso report, optional)`. **Default = `deep`:** max
`S=4` trend sample-dates (today / −7d / −14d / −28d), max `K_serp=10`. A single app/country/device at
`deep` ≈ **240 cr** (with full trend sampling). `quick`/`standard` only on explicit user request
(degrade `S` 4→2, `K_serp` 10→5).

## Trend section — verify-gated (smoke gate iv)

The trend features (per-sample-date keyword positions and category rank over `S = today, −7d, −14d,
−28d`) depend on `list_keywords` / `get_rankings` with `date=<past>` returning a **true historical
snapshot**. This is gated on smoke gate iv. **Build the trend section only if gate iv passed.** If it
did not, ship **current-snapshot-only** (buckets TOP3 / TOP10 / TOP30 / TOP100 / UNRANKED,
effectiveness tiers, competitor gaps); the HTML/method footer states plainly that trend-over-time is
unavailable pending a historical endpoint. **Never** re-read today's data under a past-date label.

## Add-keyword loop (the ONLY write path)

1. Propose a table of ≤15 candidate keywords; the user **explicitly selects** (never auto-add).
2. `edit_keywords` **REPLACES** the tracked keyword set for `(apps_id, country, device)` — any keyword
   not in the CSV is dropped. Never send only the new candidates.
3. Per `(country, device)`: read the current set with `list_keywords({ext_id, country, device})`
   **without `date`** (today), paging until exhausted. Read it fresh before each preview, even if an
   earlier read exists: after any `edit_keywords` on the same `(apps_id, country, device)` the old
   read is stale and would drop what that edit added. Current set = every tracked keyword in the
   response, ranked AND unranked (`no_pos`) — dropping the unranked ones deletes them on REPLACE. Any
   page fails → stop, no write.
4. CSV = current set ∪ selected (dedupe, case-insensitive).
   `edit_keywords_preview({country, device, keywords CSV, apps_id})` — **always pass `apps_id`
   explicitly** (omitting it defaults to the account's first collection — a wrong-collection hazard).
   A size refusal (`VALIDATION_ERROR` naming a byte limit) → stop and tell the user. Never split the
   set across calls (each call replaces the set; only the last chunk would survive) and never trim
   current keywords to fit unless the user names which to drop (then list them as dropped).
5. Show what the call replaces: collection, current keywords kept (count), added list, dropped = none.
   `list_keywords` reads by `ext_id` and does not say which collection it read. Check
   `list_collections` + `list_apps`: if the app sits in more than one collection, the current set may

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 1 — file references are metadata, not package contents.

competitors16.9 KB

View saved version →

---
name: competitors
description: >
  Find an app's real competitors in one region on one or both platforms, add the chosen ones to
  tracking, and build a competitive audit — share of search across live store results, newly
  discovered competitors, category position, and 30-day rating velocity with a star breakdown.
  Emits a structured findings.json plus a self-contained HTML report. Trigger on "who are our
  competitors", "competitor analysis", "competitive audit", "who outranks us in this country",
  "compare us against a named rival", "add competitors to tracking", "/competitors".
---

# competitors

Read `using-appfollow` first (session opening, write ritual, error codes).

This skill answers one question — *who are we actually competing with in this market, and how do we
stand against them* — using only data the MCP can produce. Everything below was verified against the
live API; the constraints in **Verified limits** are not hypothetical and must not be designed around
optimistically.

## Inputs

Collected interactively in step 1. Nothing is assumed.

- **app** — name, store URL, or `ext_id`. A store URL is fine: parse the id out of it (`/id<digits>` for
  App Store, `?id=<package>` for Google Play). The ASO search endpoints take free-text terms only, never
  a URL or an id.
- **platforms** — `ios`, `android`, or both. Maps to `store` + `device`: iOS → `as` + `iphone`,
  Android → `gp` + `android`.
- **region** — exactly **one** two-letter country code. The skill does not proceed with several.
  One region is a hard requirement, not a default: results differ enough between markets that a
  blended answer is meaningless.

## Flow

### 0. Session

`whoami` (see `using-appfollow`).

### 1. Scope

Ask for app, platforms and region in one turn. Offer sensible defaults the user can accept in a word,
but do not guess the region — require it.

Then state plainly, before starting:

- Which platforms will run (each platform is an independent sweep and doubles the work).
- That the audit needs the target app **tracked in the account**; competitor discovery does not.

### 2. Resolve the target app

`list_collections` → `list_apps` on each collection until the app is found. Record `ext_id`, `store`,
the collection `apps_id`, and the stored `country`.

- **Found** → continue.
- **Not found** → discovery (step 3) still works, because the store-search endpoints are not
  account-scoped. Say so, run discovery, and offer to add the target app itself in step 5. The audit
  sections that need tracking are marked unavailable until it is added.

If the app is tracked with a `country` different from the requested region, say so — it does not block
anything (the region is passed per call), but it explains storefront differences in titles and ratings.

### 3. Discovery sweep (the engine of this skill)

Per platform, in the chosen country:

1. **Seed the term set.** `aso_search_suggestions` on the app's brand name plus 3–5 category
   generics in the market's own language. Use what the store returns, never your own translation —
   suggestions frequently name competitors inside the suggestion strings, which is signal you get without
   having to ask for it.
2. **Pick 8 terms**: 5 category generics + the app's own brand + 2 rival brand terms. Fewer than 6 makes
   share of search noise; more than 10 rarely changes the ranking of candidates.
3. **Sweep.** `aso_search_results(term, country, device)`. Each response is the full
   ranked list with `ext_id`, `title`, `artist_name`, `rating_avg`, `genre`/`genre_id`.

Keep every response: steps 3, 4 and audit sections 1–3 all read from this one sweep. Do not re-fetch.

### 4. Selection

Rank candidates by appearances across the sweep first, average position second. Present **the top 3 per
platform** with, for each: appearances (`n/8`), best and average position, publisher, store rating.

Then give the user a free-text field to name their own competitors instead of or in addition to yours.
Resolve eac

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 1 — file references are metadata, not package contents.

feedback-analysis4.74 KB

View saved version →

---
name: feedback-analysis
description: >
  Analyze app or collection feedback over a window — KPIs with prev-window deltas, rating/volume/
  sentiment trends, anomaly callouts, and ranked top bugs + feature requests — then emit a structured
  findings.json plus a self-contained HTML report. Read-only (never writes). Trigger on "feedback
  report", "how are our reviews", "what are users complaining about", "review trends for <app>".
---

# feedback-analysis

Read `using-appfollow` first. This skill is **read-only** — it never calls a write pair.

## Inputs

- **scope:** an app (`ext_id`+`store`), a whole collection, or a **user-chosen subset of apps from one
  collection** (e.g. "just these 3 apps from my <collection>"). Spanning **multiple** collections in one
  report is not supported yet (deferred).
- **window:** default last 30 days; comparison = the preceding equal period.
- **country / lang** (optional).
- **depth:** `quick` | `standard` | `deep` = `get_reviews` page caps 2 / 5 / 10. **Default `deep`.**
  `quick`/`standard` only on an explicit user request.

## Two tiers, runtime-probed

Read the advertised tool list; pick the plan (toolkit and MCP release trains are decoupled):

- **Tier A (always):** `whoami`, `list_collections`, `list_apps`, `get_reviews`,
  `get_ratings_history`.
- **Tier B (degrade if the probe shows it absent):** `reviews_semantic`, `get_reviews_summary`,
  `get_reviews_ai_summary`.
- **Degradable, app-level (not a probe-gated tier):** `get_gp_console_ratings` — see Gather step B for
  the degrade rule.

## Gather (per app)

0. **Session** (`using-appfollow`).
A. **Scope resolve.** Collection lookup is **mandatory even for a bare ext_id** — `get_ratings_history`
   and `get_reviews_ai_summary` require `collection_name` + `store`. For a subset scope: resolve the
   collection via `list_collections`, list its apps via `list_apps`, then gather data for only the chosen
   subset — emit `scope.type: "collection_subset"` with `collection_name` set and `apps` = the chosen
   subset (not the full collection).
B. **Cheap aggregates first.** One `get_ratings_history` spanning both windows (`period=daily`,
   `type=total`, **explicit `limit`**); split client-side. `get_reviews_summary` × 2 windows (Tier B).
   `get_gp_console_ratings` is degradable — the app may have no Google Play Console connection, or the
   feature may be unavailable server-side. On any error (`VALIDATION_ERROR`, `UNKNOWN_TOOL`, or other),
   or an empty response, omit the GP-console rating signal, note the gap in the report, and continue; the
   App Store rating-history path is unaffected. Never fail the whole analysis on this call.
C. **Narrative.** `get_reviews_ai_summary` (skip on `AUTH_REQUIRED`/`UPSTREAM_ERROR`/`NOT_FOUND`).
   `reviews_semantic` — client-side classification is the first-class fallback. Then `get_reviews` raw
   pages **per app** (`ext_id` — the tool does not accept a collection; loop the scope's apps) up to the
   depth cap; stop early when `reviews.page.next` is null; replan after page-1 `total`; record coverage %.

## Analyze

Follow `references/method.md`: KPIs + deltas; daily-avg + 7-day-rolling trends; the anomaly heuristics
with their explicit thresholds; bug/feature mining (semantic-first, client-side classification the
default fallback). Apply **coverage gating** — demote text-derived findings below the 60% floor to
"indicative only". Ratings-derived findings are never coverage-gated. Group rollup weights by
`rating_cnt` and merges cross-app clusters into `affected_apps`.

## Error rails (`using-appfollow`)

`INSUFFICIENT_CREDITS` → stop, emit a **partial** report + coverage note. `RATE_LIMITED` → one backoff
then continue. `NETWORK_ERROR`/`UPSTREAM_ERROR` on a non-critical call → skip that section, keep going.
Missing Tier-B tool → documented fallback. Never fail the whole report on one tool error.

## Emit

Write `./appfollow-reports/<report_id>/`:

1. **`findings.json`** — `appfollow.toolkit.findings/v1

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 2 — file references are metadata, not package contents.

search2.73 KB

View saved version →

---
name: search
description: >
  Find an app on the App Store / Google Play and start tracking it in AppFollow, then hand structured
  app references to the feedback-analysis and aso-analysis skills. Read-only search + dedupe works on any
  plan; the add step degrades gracefully when the plan does not allow writes. Trigger on "find app X",
  "track our app", "add <app> to AppFollow".
---

# search — find + track apps

Read `using-appfollow` first (session opening, write ritual, error codes).

## Inputs

- `query`: app name (free-text search keywords).
- `store`: `as` (App Store), `gp` (Google Play), `ms`, `am` (Amazon).
- `country` (default `us`), `collection` (name; created if new), `locale`.

## Flow

0. **Session:** `whoami` (see `using-appfollow`).
1. **Normalize input.** Search takes free-text keywords only — the ASO search endpoints do not accept
   a store URL or an `ext_id`. Trim the query to the app name (strip any pasted URL down to the app
   name/title before searching).
2. **Search (read-only, any plan).** Call `aso_search_results` (optionally `aso_search_suggestions`,
   5 cr). Present numbered candidates. Auto-pick only a single exact-title match; otherwise the user
   picks.
3. **Resolve collection.** `list_collections`. If the target collection is new, run
   `add_collection_preview` → user approval → `add_collection`.
4. **Dedupe (read-only).** `list_apps`; if the app is already tracked, record it under
   `skipped_existing` and skip the add.
5. **Add (write — may be plan-gated).** `add_app_preview` → **explicit user approval** → `add_app`
   with identical args. Valid stores: `as`, `gp`, `ms`, `am`.
6. **Verify.** `list_apps` again; confirm the app now appears; capture its `apps_id`.
7. **Emit** the JSON block (below).

## Read-only degrade path (plan-gated writes)

`add_app` and `add_collection` require an **Advanced API / Custom** plan, and those routes carry **no
feature gate** — so a plan block does **not** arrive as `FEATURE_DISABLED`. It can surface as
`AUTH_REQUIRED`, `VALIDATION_ERROR`, or `UPSTREAM_ERROR`. Therefore:

- Always complete search + dedupe (read-only — works on any plan).
- Attempt the `add_*` confirm.
- On **any** error code from the add, **do not** assert a specific code. Report the candidate refs you
  found, state plainly that the add could not be completed (likely a plan limitation), and list the
  found refs under `not_added` so the report skills can still target them (they may already be tracked).

## Output (fenced JSON)

```json
{
  "added": [{"store": "as", "ext_id": "389801252", "apps_id": 12345, "collection": "Core apps", "locale": "en-US", "title": "Example App"}],
  "skipped_existing": [],
  "not_added": [],
  "collection_created": null,
  "credits_spent_estimate": 2
}
```
using-appfollow5.79 KB

View saved version →

---
name: using-appfollow
description: >
  Always-loaded discipline for every AppFollow toolkit skill. Read this before calling any AppFollow
  MCP tool. Enforces the preview→approval→confirm write ritual, the shared MCP error-code vocabulary,
  and the public-tools-only posture. Other skills reference this file rather than restating the rules.
---

# using-appfollow

You are driving the **AppFollow MCP server** (`mcp__appfollow__*` tools) on the user's own
OAuth-authenticated session. Every tool call bills the **user's own** workspace credits. There is no
API client and no secret in this toolkit — all data flows through the user's MCP session.

## Session opening (always, every run)

1. **Mint a `session_id` once.** Generate a high-entropy opaque id (e.g. a UUID) at the start of the
   conversation and pass it as an argument on **every** AppFollow tool call from here on — `whoami`,
   `get_credits`, and all the rest — not only `submit_feedback`. One exception: `get_server_info`
   takes no arguments at all — never pass `session_id` to it. The server stamps it on each
   tool-usage record, so an attached tool-usage log auto-links precisely to this conversation by
   reference. `session_id` is not identity — never ask the user for it.
2. Call `mcp__appfollow__whoami`. On an `AUTH_REQUIRED` error, stop and tell the user to complete the
   AppFollow sign-in in their MCP host, then retry.

## Elicitation

When the request is ambiguous — which app/collection, date range, store, country, competitor set, or
metric — ask **one** crisp scope-narrowing question and offer a sensible default the user can accept in
one word. Never silently guess, never stall. Volunteer the useful next step the user probably wants (an adjacent
metric, a competitor cut, a trend window). This keeps friction low and is separate from the write
ritual below — those stay mandatory regardless.

## Writes: preview → approval → confirm (never skip)

Every write tool is a pair — `<name>_preview` then `<name>`:

1. Call `<name>_preview(args)` → it returns a single-use, 60-second, args-bound `confirmation_token`
   (it validates nothing upstream — a wrong id fails at confirm).
2. Show the user exactly what will be written; get **explicit approval**.
3. Call `<name>(args + confirmation_token)` with **identical** args. On `CONFIRMATION_REQUIRED`
   (expired/mismatched token) re-preview.

Never auto-confirm. The user must approve each write.

## Group runs

For a collection or a multi-app list, resolve the full app set before running. No silent fan-out, and
no hard app cap. If `INSUFFICIENT_CREDITS` surfaces mid-run, stop and emit a **partial** report rather
than failing.

## MCP error-code vocabulary (surface verbatim; branch per skill)

`AUTH_REQUIRED`, `FEATURE_DISABLED`, `INSUFFICIENT_CREDITS`, `RATE_LIMITED`, `NOT_FOUND`,
`VALIDATION_ERROR`, `UPSTREAM_ERROR`, `NETWORK_ERROR`, `UNKNOWN_TOOL`, `CONFIRMATION_REQUIRED`.

Two traps to respect:

- **`FEATURE_DISABLED` is an unreliable plan-gate signal.** Some plan gates surface as `AUTH_REQUIRED`
  (403) instead. Never branch a degrade path solely on `FEATURE_DISABLED`.
- **`INSUFFICIENT_CREDITS` can be a false positive** (any upstream body mentioning "credits" trips it).
  Treat it like any other tool error — the universal rail below applies.

Universal rail: **a skill never fails the whole report on a single tool error** — skip the affected
section, note it, keep going.

## Public tools only

Only the tools in `references/tool-map.md` exist for you. Never invent or reference an internal tool
name, internal host, or internal API path.

## Findings hand-off

The report skills emit a `findings.json` under `appfollow.toolkit.findings/v1`. The toolkit does not
talk to any tracker — their own connected tracker agent can file the findings.

## Feedback discipline (optional, free)

After you finish a **meaningful unit of work** for the user (a completed report, a finished multi-step
task, a resolved request), you may offer a qui

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 3 — file references are metadata, not package contents.

Package details

Publisher declarations from the archived package. These are separate from our research and the live service's terms.

Package license
Apache-2.0
Package author
AppFollow
Keywords
See keywords

Declared capabilities

  • Interactive
  • Read
  • Write

Some manifest fields differ or could not be read. The structured report retains the source references.

Package observed Nov 6, 2026.

Technical details
First seen
Oct 30, 2026 · 22:33 UTC
Last seen
Nov 6, 2026 · 18:00 UTC
Collection status
Collected

plugin_asdk_app_6ac7e973de8481919c3e30951be3e9d9

Download plugin data (JSON)

Plugin details: freshly prepared. Prepared . Refreshed when plugin data changes or after 6 hours. Your account and Follow status are live.