# App Store Reviews Monitor & Analyzer (`brianlee9527/app-store-reviews-monitor`) Actor

Fetches the most recent App Store reviews for any app from Apple's official public RSS feed and returns clean structured data plus a built-in summary: average rating, rating breakdown, low-rating share, most-reviewed app versions, and the top complaint signals in 1-2 star reviews. No login, no...

- **URL**: https://apify.com/brianlee9527/app-store-reviews-monitor.md
- **Developed by:** [Donghai Li](https://apify.com/brianlee9527) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 review scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## App Store Reviews Monitor & Analyzer — Apify Actor (deploy-ready, not yet published)

Fetches the most recent App Store reviews for any app and returns clean
structured data **plus a run summary** (average rating, rating breakdown,
low-rating share, most-reviewed app versions, top complaint signals in
1–2★ reviews). Built for ASO monitoring, indie devs, support/QA teams and
scheduled "new bad review" alert pipelines (Make/Zapier/n8n via Apify
schedules + webhooks).

**Status:** built and locally verified 2026-10-29 (offline sample test +
live test, both below). **No Apify account exists yet and nothing has been
published** — deployment steps are at the bottom.

### Why this niche (scan summary, Oct 2026)

Selection rules: public/legit data only, visible demand, no dominant free
incumbent, AI-maintainable, and pay-per-event economics that can't go
negative (Apify retired rental pricing Apr 2026 — PPE is the only model
for new Actors, and browser/proxy-heavy Actors can lose money per sale).

| Candidate | Demand evidence | Verdict |
|---|---|---|
| **App Store / Play Store reviews** ✅ | Oct 2026 public bench of Store review Actors (300-review jobs, field-fill 71–85%, $0.09–$0.43 per 1K reviews); G2 reviewers cite review fetching as a real Apify use; every app team needs review monitoring | **WINNER** — official public RSS feed, zero proxy/browser cost |
| Google Maps business leads | 541–577K users, 35K monthly, $1.50–$4.00/1K places | Rejected: dominant incumbent (compass/crawler-google-places), criterion (c) fails |
| Google SERP / SEO data | 171K users, 15K monthly, ~$1.80/1K pages | Rejected: dominant official Actor, saturated |
| Job postings (Indeed etc.) | valig/indeed-jobs-scraper 36.7K users but $0.10/1K jobs | Rejected: price already at floor, margin impossible; Indeed anti-bot = breakage |
| Shopify price/stock monitor (public `/products.json`) | Real merchant pain, public endpoints | Strong #2 — demand evidence thinner/less quantified; build next |
| E-commerce price monitoring (Amazon/Kroger) | Kroger Actors ~$3.30/1K products | Rejected for #1: ToS-hostile targets, residential-proxy costs eat PPE margin, high breakage |
| Public company registers (Georgia/Armenia-style) | Dev.to build log: 5 Actors live, top Store results — **0 paying users in week 1** | Rejected: no competition but demand UNPROVEN (weak evidence, marked honestly) |
| Google review monitors ("Review Radar" pattern) | Dev.to playbook sells $0.25/run + $0.01/review | Rejected for #1: depends on Google Maps scraping infra (browser + proxy cost, breakage) |

**Winner justification:** Apple's customer-reviews RSS feed is an official,
login-free, public feed — no scraping arms race, no proxy bill, compute per
run is a few plain HTTPS GETs, so PPE margin is structurally safe. Incumbents
are beatable on fields/speed (bench: most-used Actor 71% fields filled,
183s vs 57s for a 300-review job) and none lead with analytics. The summary
block (rating mix, low-rating share, top complaint words per version) is the
differentiator: raw scrapers sell rows, this sells "is the new update
hurting us?" in one scheduled run.

### What it does

Input: an App Store app ID or `apps.apple.com` URL, a storefront country,
and a max review count (≤500 — Apple's feed cap). Output: one dataset item
per review + a `SUMMARY` object in the key-value store. Optional mode pushes
only 1–2★ reviews to the dataset (alert pipelines) while the summary is
still computed over everything fetched.

#### Input (`/.actor/input_schema.json`)

| Field | Type | Default | Notes |
|---|---|---|---|
| `appIdOrUrl` | string (required) | `389801252` | Numeric id or full store URL |
| `country` | string | `us` | Storefront, e.g. `us`, `gb`, `de`, `jp` |
| `maxReviews` | int 1–500 | `100` | 50/page, max 10 pages |
| `onlyLowRatings` | bool | `false` | Dataset gets only 1–2★ reviews |

#### Output (per review)

`reviewId, appId, country, author, rating, title, body, appVersion,
updatedAt, helpfulVotes, totalVotes, isLowRating, negativeSignals, storeUrl`

#### Summary (`SUMMARY` key)

`reviewCount, averageRating, ratingBreakdown{5..1}, lowRatingCount,
lowRatingSharePct, topVersionsReviewed, topNegativeSignalsInLowReviews,
newestReviewAt, oldestReviewAt`

### Project layout

```
first-actor/
├── .actor/
│   ├── actor.json            # name/title/description, dockerfile + schema pointers
│   ├── input_schema.json
│   ├── output_schema.json    # dataset schema
│   └── pay_per_event.json    # PPE pricing (see below)
├── Dockerfile                # apify/actor-python:3.12
├── requirements.txt          # core is stdlib-only; SDK from base image
├── src/
│   ├── core.py               # ALL logic, pure stdlib — testable offline
│   └── main.py               # thin Apify entrypoint (charge → fetch → push)
├── local_run.py              # offline/live test harness, no account needed
├── tests/sample_feed.json    # real Apple feed page (captured 2026-10-29, trimmed)
└── output/                   # reviews.json / reviews.csv / summary.json from test runs
```

### Local test results (2026-10-29, actually run)

Offline (`python3 local_run.py --sample tests/sample_feed.json`):
6 reviews parsed, avg 1.67, breakdown {5:1, 1:5}, low-rating share 83.3%.

Live (`python3 local_run.py --app-id 389801252 --country us --max-reviews 20`):
20 reviews parsed from Apple's live feed, avg 2.55, breakdown
{5:7, 4:0, 3:0, 2:3, 1:10}, low-rating share 65.0%, newest review
2026-10-28. Full items in `output/reviews.json`; example item:

```json
{
  "reviewId": "14721711404", "appId": "389801252", "country": "us",
  "author": "Larmyclarmyparmy", "rating": 1,
  "title": "Pausing music when opening the app",
  "body": "This is new with the last update. Instagram now pauses my music when I open the app...",
  "appVersion": "453.0", "updatedAt": "2026-10-28T06:28:12-07:00",
  "helpfulVotes": 0, "totalVotes": 0, "isLowRating": true,
  "negativeSignals": ["bug"]
}
```

### Proposed pricing (pay-per-event, `.actor/pay_per_event.json`)

| Event | Price | Reasoning |
|---|---|---|
| `actor-start` | **$0.10 / run** | Covers fixed cost on every run — the documented PPE trap is per-result-only pricing losing money on small runs. Kept at half the $0.20–$0.25 start fee proven by monitor-style Actors because this Actor has no browser/proxy cost. |
| `review-scraped` | **$0.0005 / review ($0.50 / 1K)** | Comparables: raw review Actors charge $0.09–$0.43/1K for rows only. $0.50/1K is a small premium for the summary analytics, version breakdown and complaint signals — still trivially cheap for the buyer (a maxed 500-review run costs $0.35 total). |

Economics: a 500-review run bills $0.35; compute is a few seconds of a
small Python container (no browser, no proxy) ≈ $0.005–0.02 platform cost.
Creator keeps 80% of event revenue minus platform costs (Apify's standard
split; Apify reports $760K paid to creators in Jan 2026 and ~$1.6M in a
recent month across the Store). Every Apify user also gets $5/mo free
credits, so expect free-tier trial runs before real revenue — normal.

Honest expectation: week-1 paying users may be zero (a comparable niche
build log reported exactly that). Store ranking is driven by README quality,
working defaults, example tasks and early reviews — budget the first month
as distribution work, not passive income.

### Deployment steps (when Brian's Apify account exists — Brian's step)

1. Brian creates the Apify account and adds a payout method (PayPal/Wise) —
   account/payout are his alone; Muse never logs in.
2. From this folder: `apify login` (Brian) → `apify push` — or zip-upload
   via Console → Actors → Create Actor → upload.
3. In Console, confirm the PPE events from `.actor/pay_per_event.json`
   appear under the Actor's pricing (file placement matters: it must live
   in `.actor/`, or charges silently don't record).
4. Run the built-in example task (app `389801252`, `us`, 50 reviews) and
   verify `chargedEventCounts` in the run object shows 1× actor-start +
   50× review-scraped before making the Actor public.
5. Publish to Store with example tasks + this README's Store description
   (in `actor.json`), then submit for Store review.
6. Any publish/pricing change after that still goes through Brian's
   approval, per standing rules.

### Maintenance notes

- **Breakage risk: LOW.** The RSS-JSON format has been stable for years and
  is an official feed. Main risks: Apple retiring the feed (would hit every
  competitor equally) or an app having <50 reviews in a storefront (handled:
  pagination stops on an empty page; summary handles 0 reviews).
- **No proxies/browsers to babysit.** If a storefront returns non-JSON
  (rare regional quirk), the run fails loudly rather than billing for junk —
  `actor-start` is the only charge in that case; monitor failed-run rate
  after launch.
- **Known limits:** 500 reviews/app/run max (feed cap); most-recent order
  only (Apple offers `sortby=mosthelpful` — a v1.1 toggle is a one-line
  change in `core.py`); Play Store reviews are a separate v2 (different,
  unofficial endpoints — deliberately out of scope for v1's legit-data rule).
- **Roadmap if it gets traction:** v1.1 sort toggle + multi-app input;
  v1.2 scheduled-diff mode ("only reviews newer than last run" via KVS
  state — the monitor pattern that supports the $0.10 start fee best);
  then the Shopify price/stock monitor as Actor #2.

# Actor input Schema

## `appIdOrUrl` (type: `string`):

Numeric App Store ID (e.g. 389801252) or a full apps.apple.com URL for the app whose reviews you want.

## `country` (type: `string`):

Two-letter App Store storefront, e.g. us, gb, de, jp, au. Reviews differ per storefront.

## `maxReviews` (type: `integer`):

Most recent reviews to fetch, 1-500. Apple's public feed caps at 500 (10 pages x 50).

## `onlyLowRatings` (type: `boolean`):

Useful for alert pipelines: the summary is still computed over all fetched reviews, but the dataset only receives low-rating reviews.

## Actor input object example

```json
{
  "appIdOrUrl": "389801252",
  "country": "us",
  "maxReviews": 100,
  "onlyLowRatings": false
}
```

# Actor output Schema

## `appId` (type: `string`):

No description

## `appVersion` (type: `string`):

No description

## `author` (type: `string`):

No description

## `body` (type: `string`):

No description

## `country` (type: `string`):

No description

## `helpfulVotes` (type: `string`):

No description

## `isLowRating` (type: `string`):

No description

## `negativeSignals` (type: `string`):

No description

## `rating` (type: `string`):

No description

## `reviewId` (type: `string`):

No description

## `title` (type: `string`):

No description

## `totalVotes` (type: `string`):

No description

## `updatedAt` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "appIdOrUrl": "389801252",
    "country": "us"
};

// Run the Actor and wait for it to finish
const run = await client.actor("brianlee9527/app-store-reviews-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "appIdOrUrl": "389801252",
    "country": "us",
}

# Run the Actor and wait for it to finish
run = client.actor("brianlee9527/app-store-reviews-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "appIdOrUrl": "389801252",
  "country": "us"
}' |
apify call brianlee9527/app-store-reviews-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,brianlee9527/app-store-reviews-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jgKiD54nHxoZ1hcGF/builds/3woL6M49znB52b8r5/openapi.json
