Skip to content

Repository files navigation

app-regression-radar

Find apps whose ratings crater right after a release — with users naming the exact regression — and pitch the fix. Timed to the release, not the reputation.

app-regression-radar builds a prospect list of app publishers who just shipped a bad release. Because every app-store review is tagged with the app version it was written against, a fuzzy "reputation" signal becomes a sharp, event-anchored one: "1-star share on v4.0 is 87% vs 0% on the prior version, all mentioning crash-on-launch, and the developer hasn't replied." It pulls reviews from Google Play and the Apple App Store via official Apify actors, buckets them by version, detects the regression, and emits a prospect record with the offending version, the defect cluster, the evidence, and a tailored pitch angle.

Provenance. This is a sibling of the "find businesses with a fixable weakness" pattern, specialised for app stores. It re-implements source → trigger → enrichment → qualification → prospect record → pitch angle on official Apify actors. The app-version tag is what makes this variant distinct — see The trigger logic. Where the literal source couldn't be followed, see Deviations.


Table of contents

How it works

config.yaml  (app ids, thresholds — no app/publisher in code)
   │
   ▼
[1] Source     official Apify actors  ── reviews tagged with APP VERSION
   │           Google Play · Apple App Store        (or offline `mock`)
   ▼
[2] Normalize  each actor's shape -> canonical App/Review records
   ▼
[3] Bucket     group reviews by version; pick the newest release (by recency)
   ▼
[4] Triggers   regression · defect_cluster · unanswered  (all anchored to the new version)
   ▼
[5] Qualify    clears volume floors AND >=1 allowed signal fired?
   ▼
[6] Analyse    name the regression + a pitch angle   (deterministic | LLM)
   ▼
prospects.csv  +  dropped.csv  +  report.md

The trigger logic

The app-version tag is the whole point — it lets the tool attribute a complaint to a specific release, which is both a sharper signal and a more actionable pitch than "this app has some bad reviews."

Signal What it detects
regression Negative-review share on the newest version exceeds the older baseline by ≥ regression_jump percentage points
defect_cluster The same defect word/phrase (crash, "since the update", login, freeze…) across ≥ N negative reviews on that new version
unanswered ≥ X% of the new version's negative reviews have no developer reply

The "newest version" is chosen by most-recent review activity (no fragile version-string parsing). An app qualifies if it clears min_reviews / min_reviews_per_version / baseline_min_reviews and at least one allowed signal fires.

Who this is for

The seller is whoever prevents or fixes bad releases:

  • Mobile crash / observability vendors (Sentry / Instabug-class).
  • QA & test-automation, mobile CI/CD, release-gate tooling.
  • App-support-automation and review-response vendors (→ the unanswered signal).
  • Mobile localization (locale-specific defect clusters) and mobile dev agencies.
  • Or a competitor app running displacement while a rival stumbles.

The pitch names the version and the defect: "v4.0 shipped a crash your users are screaming about and you haven't replied — here's a QA gate / crash diagnostics."

Strengths

  • Sharpest timing on the review-mining landscape. The version tag makes causality legible and the pitch land within days of a bad release.
  • Clean entity resolution. App ids are exact — no fuzzy business matching.
  • High-adoption, high-success actors that return per-review version + date + developer-reply — exactly the fields the signals need.

Limits & failure modes (read this)

  • A rating dip isn't always a fixable regression. A pricing/policy change, a review-bombing campaign, or seasonality can all depress a new version's ratings. The defect-cluster signal is what separates a real regression from noise — keep it in require_signals and tune defect_keywords, or expect false positives.
  • Apple App Store coverage is capped. The App Store actor reads Apple's public RSS feed, which returns at most ~500 reviews per app. Fine for a recent-release velocity read; not a full history. Google Play is the richer source.
  • Small/long-tail apps lack the volume to compute a per-version comparison; the per-version and baseline floors deliberately drop them rather than fire on noise.
  • Version attribution depends on the actor. If reviews come back without a version field, the regression/defect/unanswered signals (all version-anchored) can't fire. See docs/SETUP.md → "Field mappings".
  • The publisher can be hard to reach as a named buyer versus an app-store listing — this tool finds the app, not the decision-maker's inbox.

Inputs and outputs

Input: a config.yaml — which stores, which app ids (Google Play package names; App Store numeric ids or URLs), and the thresholds.

Outputs:

  • prospects.csv — one row per qualifying app: app, platform, app_id, url, review_count, regressed_version, signals, weakness, pitch_angle, evidence.
  • dropped.csv — every app considered and not listed, with the reason.
  • report.md — counts, per-platform and per-signal tallies, config in effect.

Example: the synthetic sample

Synthetic fixtures under sample/ (invented apps — com.fiction.notesapp, Fiction Weather; no real data). With the offline mock transport (no token, no spend):

make sample
# → apps=2 evaluated=2 qualified=1

com.fiction.notesapp qualifies: its v4.0.0 negative share is 87% vs 0% on v3.2.0 (+87pp), with a crash / since update / login defect cluster and 85% of the new-version negatives unanswered. Fiction Weather (all one version, high ratings) is dropped — "no regression signal fired." See out/prospects.csv.

Quick start

Prerequisites: Python ≥ 3.9. An Apify token is needed only for a real run. Full walkthrough: docs/SETUP.md.

python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt

make sample                 # offline; no token, no spend
cat out/report.md

cp config.example.yaml config.yaml    # add app ids + thresholds
cp .env.example .env                   # put APIFY_TOKEN here (git-ignored)
python -m radar --config config.yaml

Configuration

Everything is config, never code — see the fully-commented config.example.yaml. Key knobs:

Setting What it controls
transport apify (real) or mock (offline fixtures)
source.google_play.app_ids Package names (e.g. com.example.app) or Play URLs
source.app_store.app_ids Numeric app ids or App Store URLs
source.<platform>.country / language Storefront + review language
source.<platform>.max_reviews Reviews to pull per app (cost lever)
triggers.regression_jump Percentage-point jump that counts as a regression
triggers.defect_min_cluster / defect_keywords Recurring-defect detection
triggers.min_reviews* Volume floors (total / per-version / baseline)
triggers.require_signals Which signals may qualify an app
analysis.mode deterministic (offline) or llm (Claude)
output.redact Hash app names + drop ids/URLs for anything shared

Secrets live in .env (git-ignored). Copy .env.example.

Compliance & data handling

  • Platform terms & rate limits. The actors read Google Play / Apple App Store public review pages/feeds; those platforms have terms governing automated access, and the actors are third-party tools, not sanctioned integrations. Use within each platform's terms and Apify's, and keep volumes proportionate.
  • Personal data (GDPR / CCPA). Reviews carry reviewer usernames — lighter than named individuals, but still personal data. The tool aggregates to the app level and doesn't need reviewer identity; prefer not to retain usernames, and mind the review text you keep as evidence.
  • Don't label apps publicly. A "regressed release" list is for your outreach, not publication. output.redact: true hashes app names and drops ids/URLs for anything you share.
  • Not permission to contact. A qualified row is a signal, not consent — your outreach compliance is your responsibility.

Cost notes

Free tool; you pay Apify per review pulled (and Anthropic only in LLM mode). Full breakdown with the formula and small/medium/large estimates: docs/COSTS.md. Actor existence and pricing model verified against the live Apify Store API (2026-09); dollar figures are estimates — confirm current pricing. Cost formula: apps × max_reviews × per-review-rate (+ LLM tokens on qualified apps).

Deviations from the source

  1. Re-platformed onto Apify (the source used a self-hosted scraper stack). The trigger/qualification/pitch steps are faithful; the app-store version anchor is the specialization.
  2. LLM analysis is optional, not mandatory — deterministic by default (no key, offline, reproducible).
  3. No outreach/sequencing — this produces the qualified list and pitch angle; sending is yours.
  4. Field mappings are verified against a live Google Play reviews-mode run (2026-09): per-review score, text, version, date, replyText, userName. App Store mappings are tolerant of key renames; adjust in radar/sources.py if an actor's output diverges.

License

Apache-2.0 (see LICENSE, NOTICE). This project invokes third-party Apify actors and (optionally) the Anthropic API at arm's length; it does not bundle or modify them. Apple, Google, and the app publishers whose reviews the actors read are not affiliated with this project.

About

Find apps whose ratings regress on a specific release — on official Apify actors (Google Play/App Store).

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages