About feedback-analysis
feedback-analysis is a read-only skill for analyzing AppFollow app reviews and ratings across a selected app, collection, or subset. It produces findings and reports with coverage-aware trends, anomalies, and feedback themes.
Key features
- 01Review and rating trend analysis
- 02App, collection, and subset scopes
- 03Coverage-aware feedback findings
- 04JSON, HTML, and Markdown reports
Use cases
- 01Compare feedback across two time windows
- 02Find recurring bugs and feature requests
- 03Analyze selected apps in a collection
MCP support
Uses AppFollow tools through the companion using-appfollow skill. It probes available tools and degrades to documented fallbacks when optional tools are unavailable.
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ appfollow/ appfollow-ai-toolkit --skill feedback-analysisAfter installing, type/feedback-analysisin Claude Code to confirm it loaded.
Bundled filesreferences/method.mdreferences/report-template.html
Details
From the project READMEfeedback-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 "). 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_reviewspage caps 2 / 5 / 10 per pull. A whole-collection pull gets the cap once; app and subset pulls apply it per app. Defaultdeep.quick/standardonly on an explicit user request. - testing feedback (optional, Google Play only): what testers left on a closed or open testing track — a separate review set, off by default; pulled only on an explicit user request (Gather step D).
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
- Session (
using-appfollow). A. Scope resolve. Collection lookup is mandatory even for a bare ext_id —get_reviews,get_reviews_summaryandget_gp_console_ratingstake the collection'sapps_id(collectionIdinlist_collections), andget_reviews_ai_summarytakes itscollection_name(collectionCode) +store.list_apps(apps_id) gives each app'sextId(theext_idargument) and reportsstoreas the long name — map it to the short code before anystoreargument (using-appfollow→references/tool-map.md). A whole collection means its own apps (isCompetitor: falseinlist_apps): run every per-app call below on those only. For a subset scope: resolve the collection vialist_collections, list its apps vialist_apps, then gather data for only the chosen subset — emitscope.type: "collection_subset"withcollection_nameset andapps= the chosen subset (not the full collection). B. Cheap aggregates first. Per app, oneget_ratings_historyspanning both windows (ext_id+ shortstore,period=daily,type=total, onecountry— the user's, elseall): the full series comes back in one call, no paging; split client-side.get_reviews_summaryonce for the current window (Tier B) on step C's scope (apps_id, plusext_idwhere step C pulls per app): itstotal.value,previousanddiffcover the current and the preceding equal period, andtotal.valuesizes step C — review pages carry no total.get_gp_console_ratings(apps_id+ each Google Play app'sext_id+ the report-windowfrom+to,fields: ["ratings"]) is degradable — the app may have no Google Play Console connection, or the feature may be unavailable server-side. On any error (FEATURE_DISABLED,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. Per app,get_reviews_ai_summarywith the report-windowfrom+to, the app'sext_id, the collection'scollection_name(collectionCode) and shortstore(skip on any error: without the AI summary feature it answersFEATURE_DISABLEDorACCESS_DENIED).reviews_semantic— client-side classification is the first-class fallback. Thenget_reviewsraw pages: a whole collection is one pull (apps_id, noext_id— its own apps; the collection's competitor apps are left out), an app or a subset one pull per app (apps_id+ext_id). Page by passing eachnextCursorback ascursor(same arguments) up to the depth cap; stop early whennextCursoris null or absent; record coverage % against step B's total (references/method.md). D. Testing feedback (opt-in, Google Play). A separate review set: for a Google Play app,get_reviewsreturns only public reviews unlesstesting_feedback: true, and then only testing feedback (typeList: ["beta"]) — never both in one call, and never merged into the public-review sections. Run it only on an explicit user request for tester / beta / testing-track feedback: a separateget_reviewspass per Google Play app, each call with the collection'sapps_id, that app'sext_idandtesting_feedback: trueover the report window, same paging and depth cap as step C. Other stores ignore the flag and always return their public reviews: skip them, never send a workspace-widetruecall, and keep only reviews whosetypeListcontainsbeta. Whenget_reviewsdoes not listtesting_feedbackamong its arguments, skip the step and note it — a server without the flag returns public reviews. An empty set is a result, not an error — no testing feedback in the window, or no Google Play Console connection to AppFollow, and the tool does not say which: report it as empty, do not retry. If the user asked only for tester feedback, run steps 0, A and D, skip B and C, and emit the testing section alone. Analyze it apart from the public set (references/method.md).
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
each app's rating count (starsTotal of its latest get_ratings_history row) 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>/:
findings.json—appfollow.toolkit.findings/v1,report_type:"feedback". Validate it againstschemas/findings.schema.jsonbefore writing. Each finding: stableid,type,title,description,severity,priority_hint,affected_apps,metrics,evidence(3–5 quotes ≤200 chars via review ids — no permalink scheme exists),suggested_labels, stablededup_key(so re-runs update rather than duplicate),status:"proposed".report.html— fillreferences/report-template.html; inline SVG charts; no external requests.report.md— the same content in Markdown.
On Claude Code, also publish the HTML artifact; on Codex, write the files and state their path.
Findings hand-off
Tell the user their own connected tracker agent can file findings.json into their tracker — the
toolkit never talks to a tracker.