# App Review Change Monitor (`silicon1235/app-review-change-monitor`) Actor

Monitor public App Store review feeds for new reviews, rating drops, and competitor review digests.

- **URL**: https://apify.com/silicon1235/app-review-change-monitor.md
- **Developed by:** [X L](https://apify.com/silicon1235) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## App Review Change Monitor

Monitor public Apple App Store review feeds for new reviews, low-rating alerts, and competitor review digests.

This Actor is designed for scheduled product and competitor monitoring. It is intentionally narrower than generic review scraping: the first value is a compact change report that tells a product team what changed since the previous run.

### Input

- `apps`: App Store app IDs with optional labels and countries.
- `maxApps`: maximum app entries processed in one run. The default is `5` and the hard cap is `20`.
- `fallbackCountries`: country feeds to try when the primary country has an empty RSS feed.
- `previousReviewIds`: optional IDs from a previous run.
- `maxReviewsPerApp`: maximum recent reviews per app. The default is `50` and the hard cap is `100`.
- `lowRatingThreshold`: ratings at or below this value are flagged.
- `alertKeywords`: words such as `bug`, `crash`, `login`, `refund`, or `privacy` that mark a new review as an alert.
- `snapshotKey`: key-value-store record used for scheduled change detection.
- `saveSnapshot`: stores current review IDs for the next run.

### Output

Dataset rows include:

- app ID, app label, and country
- review ID and URL
- rating, title, author, update time, and content
- `NEW`, `SEEN`, or `ERROR` status
- alert flag, priority, risk category, keyword matches, and reasons

Key-value-store records:

- `SUMMARY`: machine-readable counts and averages
- `REPORT`: Markdown digest for quick inspection

The report also includes a competitive snapshot when multiple apps are monitored:

- average rating per app
- alert rate per app
- top risk category per app
- 1-5 star rating distribution

This is the main difference from a generic App Store reviews scraper: the output is shaped for product and competitor monitoring, not raw review extraction.

The Actor intentionally reads the public Apple RSS feeds and keeps conservative per-run caps. It is not positioned as a full historical App Store review archive or browser-based bulk scraper.

### Monetization plan

First release should be free or usage-cost-only. If organic usage appears, the clean paid unit is a scheduled digest or a `new-review-alert` event. Do not charge for simply seeing unchanged reviews. Good paid events are new low-rating reviews, billing/privacy complaints, and keyword-triggered alerts.

### Public-source smoke evidence

Latest local live smoke against the public App Store RSS source passed:

- artifact: `_target_checks/live-smoke/2026-07-01T12-54-13-311Z.json`
- app: public App Store app id `333903271`
- rows: `10`
- new reviews: `10`
- low-rating alerts: `4`
- high-priority alerts: `4`
- average rating: `3.1`

This smoke test does not use Apify remote runs, proxies, or browser automation. It exercises the same public-feed parsing and alert logic used by the Actor.

### Release sequence

1. Keep local validation and public-source smoke green.
2. Run one guarded private Apify test only after explicit approval:

```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\apify-run-approved-remote-test.ps1 -Actor app-review -Apply -ConfirmText 'APPROVE guarded app-review remote private test <= $0.02'
````

3. Publish free or usage-cost-only first.
4. Consider PPE only after organic usage appears and run cost is measured.

### Local validation

```powershell
npm test
npm run sample
npx apify-cli validate-schema
npm pack --dry-run --json
```

# Actor input Schema

## `apps` (type: `array`):

Apps to monitor. Use Apple App Store app IDs and optional labels.

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

Default two-letter App Store country code used when an app does not specify one.

## `fallbackCountries` (type: `array`):

Optional country codes to try when an app's primary App Store review feed is empty.

## `maxReviewsPerApp` (type: `integer`):

Maximum recent reviews to read from each public App Store RSS feed. Values above 100 are capped by the Actor to protect scheduled-run cost.

## `maxApps` (type: `integer`):

Maximum app entries to process in one run. Keep this low for the first remote test and scheduled runs.

## `previousReviewIds` (type: `array`):

Optional review IDs from a previous run. Reviews not in this list are marked NEW.

## `lowRatingThreshold` (type: `integer`):

Reviews at or below this star rating are flagged as low-rating alerts.

## `alertKeywords` (type: `array`):

Keywords that mark a new review as an alert even when the star rating is not low.

## `snapshotKey` (type: `string`):

Key-value store record used to load and save review IDs for scheduled monitoring.

## `saveSnapshot` (type: `boolean`):

Save current review IDs to the key-value store so the next run can detect new reviews automatically.

## Actor input object example

```json
{
  "apps": [
    {
      "appId": "333903271",
      "label": "Sample App",
      "country": "ca"
    }
  ],
  "country": "ca",
  "fallbackCountries": [
    "ca",
    "au",
    "us",
    "gb"
  ],
  "maxReviewsPerApp": 50,
  "maxApps": 5,
  "previousReviewIds": [],
  "lowRatingThreshold": 2,
  "alertKeywords": [
    "bug",
    "crash",
    "broken",
    "login",
    "refund",
    "subscription",
    "charged",
    "privacy"
  ],
  "snapshotKey": "APP_REVIEW_SNAPSHOT",
  "saveSnapshot": true
}
```

# Actor output Schema

## `reviews` (type: `string`):

Default dataset rows with app, review, rating, status, and alert fields.

## `summary` (type: `string`):

No description

## `report` (type: `string`):

No description

## `snapshot` (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 = {
    "apps": [
        {
            "appId": "333903271",
            "label": "Sample App",
            "country": "ca"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("silicon1235/app-review-change-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 = { "apps": [{
            "appId": "333903271",
            "label": "Sample App",
            "country": "ca",
        }] }

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

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

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

```

## CLI example

```bash
echo '{
  "apps": [
    {
      "appId": "333903271",
      "label": "Sample App",
      "country": "ca"
    }
  ]
}' |
apify call silicon1235/app-review-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=silicon1235/app-review-change-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "App Review Change Monitor",
        "description": "Monitor public App Store review feeds for new reviews, rating drops, and competitor review digests.",
        "version": "0.1",
        "x-build-id": "UFsxWHk2bHkTRRQO4"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/silicon1235~app-review-change-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-silicon1235-app-review-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/silicon1235~app-review-change-monitor/runs": {
            "post": {
                "operationId": "runs-sync-silicon1235-app-review-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/silicon1235~app-review-change-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-silicon1235-app-review-change-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "apps"
                ],
                "properties": {
                    "apps": {
                        "title": "App Store apps",
                        "type": "array",
                        "description": "Apps to monitor. Use Apple App Store app IDs and optional labels."
                    },
                    "country": {
                        "title": "Default country",
                        "type": "string",
                        "description": "Default two-letter App Store country code used when an app does not specify one.",
                        "default": "ca"
                    },
                    "fallbackCountries": {
                        "title": "Fallback countries",
                        "type": "array",
                        "description": "Optional country codes to try when an app's primary App Store review feed is empty.",
                        "default": [
                            "ca",
                            "au",
                            "us",
                            "gb"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxReviewsPerApp": {
                        "title": "Maximum reviews per app",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum recent reviews to read from each public App Store RSS feed. Values above 100 are capped by the Actor to protect scheduled-run cost.",
                        "default": 50
                    },
                    "maxApps": {
                        "title": "Maximum apps per run",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Maximum app entries to process in one run. Keep this low for the first remote test and scheduled runs.",
                        "default": 5
                    },
                    "previousReviewIds": {
                        "title": "Previous review IDs",
                        "type": "array",
                        "description": "Optional review IDs from a previous run. Reviews not in this list are marked NEW.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "lowRatingThreshold": {
                        "title": "Low rating threshold",
                        "minimum": 1,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Reviews at or below this star rating are flagged as low-rating alerts.",
                        "default": 2
                    },
                    "alertKeywords": {
                        "title": "Alert keywords",
                        "type": "array",
                        "description": "Keywords that mark a new review as an alert even when the star rating is not low.",
                        "default": [
                            "bug",
                            "crash",
                            "broken",
                            "login",
                            "refund",
                            "subscription",
                            "charged",
                            "privacy"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "snapshotKey": {
                        "title": "Snapshot key",
                        "type": "string",
                        "description": "Key-value store record used to load and save review IDs for scheduled monitoring.",
                        "default": "APP_REVIEW_SNAPSHOT"
                    },
                    "saveSnapshot": {
                        "title": "Save review snapshot",
                        "type": "boolean",
                        "description": "Save current review IDs to the key-value store so the next run can detect new reviews automatically.",
                        "default": true
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
