App Store & Play Review Monitor
Pricing
from $2.10 / 1,000 delivered reviews
App Store & Play Review Monitor
Monitors new App Store reviews from Apple's public feed, and optional Play reviews with your own console credentials. Flags low ratings and the app version. The first run only saves a baseline. The public Play page stays off unless you confirm it. Not an archive. Not affiliated with Apple or Google.
Pricing
from $2.10 / 1,000 delivered reviews
Rating
0.0
(0)
Developer
Muhammet Mustafa Dincer
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare
What is App Store & Play Review Monitor?
App Store & Play Review Monitor watches app reviews and returns the ones that showed up since the last run. For Apple, it reads the public customer-reviews feed at itunes.apple.com/{country}/rss/customerreviews/.../json. For Google Play, the supported path is the official Android Publisher reviews API with your own Play Console credentials. A reader of the public Play page exists, and it stays off unless you turn it on and confirm it.
Each delivered review is one dataset row: store, country, review id, stars, title, text, the public display name, app version, date, helpful votes, link, and lowRatingAlert when the rating is at or below a threshold you set (default 2 stars).
The first run with New reviews only (the default) saves the review ids it saw and does not charge for them. The next run charges only for reviews that are actually new. There is no browser and no login for Apple. Play's official API is limited to apps that the credentials can manage.
Quick answer: when should you (or an AI agent) pick this Actor?
Pick this Actor when you want a scheduled alert for new App Store reviews, especially bad ones, without an Appbot or AppFollow subscription. A typical input is one Apple app id, one or a few storefronts, onlyNew: true, and a low-rating threshold of 2. Add Google Play only for an app you publish, with your own service account.
Pick something else when you need the full history of an app. Apple's feed is about the latest 500 reviews per country (10 pages), and pages in the middle are often empty. It is not a multi-year archive. Google's official API returns reviews from about the last week, and only for apps in that Play Console account. It is not a way to read a competitor's Play console.
Defaults that work: the prefilled input is Spotify's Apple id 324684580 in the US store, new reviews only. The first Start saves a baseline. Schedule that same input. To also fetch the reviews that are already in the feed, send {"appleAppIds": ["324684580"], "appleCountries": ["us"], "onlyNew": false, "maxReviewsPerSource": 50}.
At a glance
| Does | Reads Apple's public customer-reviews JSON feed. Optionally reads Google Play through your Play Console API. Flags low ratings and keeps the app version. |
| Input | Apple app ids and storefronts. Optional Play package, Play source, credentials, star range, keywords, low-rating threshold, onlyNew, stateName. |
| Output | recordType: "review" and "source" rows, plus RUN_SUMMARY and LOW_RATING_ALERTS in the key-value store. |
| Needs | Nothing for Apple. For Play's official API, your own service account or access token. |
| Depth | Apple: about the latest 500 reviews per country. Play API: about the last week, for your own apps. |
| Pricing | Pay per event. Free plan: $0.0005 per run and $0.003 per delivered review. A baseline is not charged per review. |
| Does not | Archive old reviews, reply to reviews, read emails or devices, or turn the Play page reader on by itself. |
Key terms used in this README
- Customer-reviews feed: Apple's public RSS JSON document for one app and one storefront. The Actor asks for
sortBy=mostRecent. A page holds up to 50 reviews. There are 10 pages. - Hole: a page that comes back as a valid feed with no reviews, while a later page, or another spelling of the same URL, has reviews. An empty page is not treated as the end of the list.
- Baseline: the review ids saved after the first successful read for a watchlist name. Those reviews are not delivered and not charged.
- New review: a review id that was not saved, and whose date is not older than the previous run (minus two hours, so a review that was posted just before the run can still arrive).
- Late reveal: a review that was missing from the saved list but is dated before the previous run. It is recorded so it does not alert later, and it is not charged. Apple's feed does this when a hole fills in.
- Low-rating alert:
lowRatingAlert: trueon a delivered review at or belowlowRatingThreshold. The same rows are also listed under the keyLOW_RATING_ALERTS(up to 200). This is not a second charge. - Official Play API:
GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{package}/reviewswith your OAuth token. Google documents that this list is about the last week. - Public page: the optional scraping path. It is labeled
fetchedVia: "google-play-page"on every row from it. Default is off.
What can you use it for?
A bad-review alert
Schedule the Actor every few hours with onlyNew: true and lowRatingThreshold: 2. Point an Apify webhook at the dataset or at LOW_RATING_ALERTS. You pay the start fee on quiet runs, and $0.003 per new review on the Free plan when something was actually delivered.
Release checks
appVersion is the version the reviewer had installed, when the feed or the API provides it. Filter the dataset to the version you just shipped.
Several storefronts
Pass appleCountries: ["us", "gb", "de"]. Each country is its own feed and its own baseline. The same review id in two countries is unlikely; they are stored separately.
Your own Play app
Set googlePlaySource to official-api, paste the service account JSON (invited in Play Console), and add the package name. Countries are ignored on this path: Google returns recent reviews for that app across languages. A competitor's package will not work with your key.
How does it work?
- Apple app ids are checked as digits, or taken from an
apps.apple.com/itunes.apple.comURL. Package names are checked ascom.example.app, or taken from aplay.google.comURL. Anything else is skipped. The Actor never requests a host you typed yourself. Allowed hosts areitunes.apple.com,oauth2.googleapis.com,androidpublisher.googleapis.com, andplay.google.com(only if the public page is confirmed). - For each Apple app and country it requests pages 1 to 10, one request at a time, with a pause (
requestDelayMs, default 400). Each page is tried as a few spellings of the same customer-reviews feed, including the storefront as accquery. Apple caches those spellings separately and one of them is often empty. The spelling that contains reviews is kept for later pages. The first empty spelling on a page is retried once. Review ids are deduplicated. - A 403 or 429 stops that source. The Actor does not try another address, switch proxy, or call a private App Store API. The baseline already saved is kept. If every spelling is a readable document with no reviews, the source row, the log and the run status say so. That run does not write or replace a baseline and does not charge. Set Proxy configuration to Apify Proxy and choose the residential group, then run again. Direct requests stay the default.
- Entries without a star rating are skipped (older feeds put the app itself in the first entry). The author profile URL is dropped. Only the display name is kept.
- With New reviews only, the ids are compared with the gzipped snapshot in the key-value store
app-store-play-review-monitor-state, under the watchliststateName. The first run that actually reads reviews writes the snapshot and a source row (baseline_saved) and no review rows. An empty feed does not write that snapshot. Later runs write the new reviews and then update the snapshot. A later empty feed leaves the saved ids in place. - If the run hits its maximum charge, reviews that did not fit are left out of the snapshot, and the saved timestamp does not move, so the next run can deliver them.
- Changing the star range, the keywords, or the review cap starts a new baseline instead of reporting the whole feed as new. Changing only the low-rating threshold does not.
- Google Play's official client exchanges the service account for a token (JWT, scope
androidpublisher) or uses the access token you passed. It pages withmaxResults=100. Device, OS and screen fields are not copied. A tab in the comment text is treated as the split between title and body, which is how that API joins them. - The public page, when confirmed, posts to Play's public reviews endpoint and stops if the body is not the expected shape or the server refuses it.
How to monitor an app (step by step)
- Open the Actor. Keep the prefilled Apple id, or paste your own.
- Add storefronts if you need more than the US.
- Leave New reviews only on. Leave Google Play source on Off unless you have Play Console credentials.
- Click Start. The dataset has a source row and no review rows. That run did not charge per review.
- Run it again later, or add a schedule with the same
stateName. New reviews appear from the second run. Low ratings are marked in the Low-rating alerts view.
To receive the reviews that are already public, turn New reviews only off for one run. That run charges for every review it delivers, and it does not update the baseline.
Input
| Field | Type | Default | Meaning |
|---|---|---|---|
appleAppIds | list | prefilled 324684580 | Up to 10 Apple ids or App Store URLs. At most 20 id-and-country pairs. |
appleCountries | list | us | Up to 5 storefronts. uk is read as gb. |
onlyNew | boolean | true | Baseline on the first run; only unseen reviews later. |
minRating, maxRating | integer | 1 and 5 | Inclusive star range. Reviews outside it are not charged. |
keywords | list | empty | Keep a review if the title or text contains at least one. At most 30. |
lowRatingThreshold | integer | 2 | Flag delivered reviews at or below this. |
googlePlayPackageNames | list | empty | Up to 10 package names or Play URLs. Ignored while Play is off. |
googlePlaySource | off | official-api | public-page | off | public-page is the scraping path. |
googlePlayServiceAccountJson | secret | empty | JSON key invited in Play Console. Not written to the dataset. |
googlePlayAccessToken | secret | empty | OAuth token for androidpublisher, used only if the JSON key is empty. An AIza API key is rejected. |
confirmGooglePlayPageScrape | boolean | false | Must be true for public-page. |
googlePlayCountries | list | us | Used only by the public page. |
stateName | string | default | Letters, digits, - and _. Same name, same memory. |
maxReviewsPerSource | integer | 500 | Cap per app and country. 500 is Apple's ceiling. |
requestDelayMs | integer | 400 | Pause between requests. Minimum 200. |
proxyConfiguration | object | Apify Proxy off | Optional. Turn on Apify Proxy and select residential when the Apple feed is empty. Proxy traffic is billed separately. |
Output
One dataset, two kinds of rows. Filter on recordType. Views: Reviews, Low-rating alerts, Sources.
An illustrative row (not a live run) is in assets/sample-run-data.json.
Review rows
| Field | Meaning |
|---|---|
recordType | review |
store | app-store or google-play |
country | Storefront, or null for the Play Console API |
appId | Apple id or Play package name |
reviewId | Store review id |
rating | 1 to 5 |
title, text | Title may be null on Play |
author | Public display name. No profile URL |
appVersion | Version string, or null |
reviewedAt | ISO 8601 time |
votes | Helpful votes |
url | Link from the feed, or the app's reviews page |
lowRatingAlert | True or false |
fetchedVia | apple-rss, google-play-api, or google-play-page |
language | Play reviewer language, or null |
Source rows
status is baseline_saved, no_new_reviews, reviews_found, empty, no_matches, charge_limit, blocked, fetch_failed, auth_failed, or invalid_response. Counts say how many reviews were read, new, delivered, filtered, already seen, revealed late, or held back by the spending limit. message explains the status.
Key-value store
| Key | Where | Meaning |
|---|---|---|
RUN_SUMMARY | default store | Sources, delivered reviews, alert count, warnings |
LOW_RATING_ALERTS | default store | Up to 200 alert rows and the full count |
STATE | default store | Internal resume marker |
seen--{stateName}--{source} | named store app-store-play-review-monitor-state | Gzipped review ids. Not for reading by hand. |
Up to 20,000 ids are kept per source. Older ids drop off the tail. A dropped id whose review date is before the last run is still not alerted, because of the date check.
Pricing
Pay per event. Prices below are US dollars. Apify's margin is 20%.
| Event | Free | Bronze | Silver | Gold and above | When |
|---|---|---|---|---|---|
| Actor start | $0.0005 | $0.0005 | $0.0005 | $0.0005 | Once per run (one event per GB of memory, minimum one) |
| Delivered review | $0.003 | $0.0027 | $0.0024 | $0.0021 | One per review row written |
The charge in the code is Actor.charge({ eventName: 'review-delivered', count }) after the rows are stored. pushData is called without an event name, so a review is not billed twice.
Not charged: the baseline, reviews already saved, reviews removed by the star or keyword filter, late reveals, source rows, the low-rating copy in the key-value store, empty feeds, and sources that fail or refuse the request. Apify Proxy, when you turn it on, is billed by Apify as platform usage, separate from these events.
A charge result of zero events is a spending limit only when eventChargeLimitReached is true. A run that is not on pay-per-event still stores the reviews it read.
A quiet daily run is the start fee. Ten new reviews on the Free plan are $0.03 plus the start fee. A one-off run with onlyNew: false and 500 reviews is 500 times the review price.
The band is $0.002 to $0.005 per new review: above the $0.0001 Apple-only scrapers, and aimed at a monitor that replaces a $49/month review dashboard when you only need new reviews. It is the wrong tool if you need to export the whole history in one cheap pass.
Comparison
| This Actor | thewolves App Store reviews | neatrat Google Play reviews | Appbot | |
|---|---|---|---|---|
| Apple | Public customer-reviews feed | Apple reviews | No | Yes |
| Google Play | Your API, or a confirmed public page | No | Public Play reviews | Yes |
| New since last run | Yes, saved in a key-value store | Not the product | Not the product | Yes, inside the dashboard |
| App version | Yes | Varies | Varies | Yes |
| Low-rating flag | Yes | No | No | Yes |
| Price signal | $0.003 per delivered review on Free | about $0.0001 per review | about $0.00015 per review | about $49–59/month |
Those competitor prices are public list prices from the research snapshot of 5 November 2026, not a measurement of this run.
Legal and privacy
Apple. The customer-reviews feed is public and needs no key. itunes.apple.com/robots.txt contains Disallow: /*/rss/*, and this feed is under /{country}/rss/. Apple's Media Services Terms (the text last updated 14 September 2026) say the services are for personal, noncommercial use, and they prohibit using an automated process to scrape, copy, or monitor the content. This Actor reads that feed anyway. It does not have Apple's permission. It does not rotate addresses or switch to a private API when Apple refuses. A proxy is used only if you set one; the Actor does not turn a proxy on after an empty page or a refusal. Whether you may use it is your decision. This README is not legal advice. The Actor is not affiliated with Apple.
Google Play, official API. This is the path to use. You supply credentials for a Play Console account, and Google returns reviews for apps that account manages. Follow Google's API terms and quota (the reviews list is a small number of reads per hour per app). The Actor is not affiliated with Google.
Google Play, public page. Off by default. You must set googlePlaySource to public-page and confirmGooglePlayPageScrape to true. The input label calls it scraping. It may conflict with Google Play's terms, it is unsupported, and it can break without notice. Every row is marked fetchedVia: "google-play-page". A browser user agent is sent on that path only, because the page expects one. A refusal stops the source.
Personal data. The display name is the name the store already shows next to the review. Profile URLs, account ids, and Play device details are not stored. If you keep the dataset, you are responsible for that copy.
No archive. Do not schedule this once a month on a busy app and expect every review. Apple only exposes about 500 recent reviews per country, and a gap larger than that between runs drops reviews that fell out of the window. Play's official API is about a week.
FAQ
Why did the first run return no reviews?
If the source row says baseline_saved, new reviews only is on and the ids were saved. Run the same input again later. If the source row says empty and the message starts with "Warning", Apple returned a document with no reviews. That is not a baseline. Turn on a residential proxy and run again.
Why is the Apple feed empty for a famous app? Page 1 is often a hole, so the Actor still requests the other pages and the other spellings, and it retries the first empty spelling once. If every one of them is an empty document, the run warns you. Datacenter addresses often get that empty document while the same URL still has reviews elsewhere. Set Proxy configuration to Apify Proxy, select the residential group, and run again. An existing baseline is kept. The Actor does not invent reviews and does not switch to a private App Store API.
Can I watch a competitor on Google Play? Not with the official API. That API only returns apps your Play Console credentials manage. The public page can be pointed at any package, and it is the path that stays off until you confirm it.
Does a 1-star review cost more? No. The flag is free. You pay once if the review was delivered.
What happens if I change keywords?
The next run saves a new baseline and does not dump the old reviews as new. Use onlyNew: false for one run if you want the current feed under the new filter.
Local run
From actors/app-store-play-review-monitor after npm install:
$mkdir -p storage/key_value_stores/default
Write storage/key_value_stores/default/INPUT.json, then npm start. npm test runs the unit tests and does not call Apple or Google.