Apple App Store Reviews - Ratings, Reviews & App Metadata
Pricing
from $0.60 / 1,000 reviews
Apple App Store Reviews - Ratings, Reviews & App Metadata
Scrape Apple App Store reviews across 150+ country storefronts. Search by app name or URL and extract ratings, review titles and text, authors, dates, app versions, and country in clean JSON, with optional app metadata enrichment.
Pricing
from $0.60 / 1,000 reviews
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
1
Bookmarked
1
Total users
0
Monthly active users
10 days ago
Last modified
Share
App Store Reviews Scraper: Ratings, Text, Author & App Version
App Store Reviews Scraper turns Apple App Store reviews into a clean, structured dataset. Give it an app name or an App Store link and it returns one row per review: star rating, title, body, author, review date, the app version reviewed, and the storefront country. Reviews are storefront specific, so sweep as many countries as you like to build the full picture for one app, search by name or paste links, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- Reviews are the primary output: rating, title, body, author, date, app version and country on every row.
- Two ways in: search by app name, or paste one or more App Store app links.
- Multi-country sweep: list storefronts one by one, or use "all" for a broad built-in set of major markets in a single run.
- Sort by most recent or most helpful, and filter by minimum and maximum star rating.
- Optional app-metadata enrichment: developer, average rating, rating count, genre, icon, price and release notes attached to every review.
- Built for schedules: incremental mode returns only new and changed reviews on recurring runs, and resume continues an interrupted run without paying twice.
Use Cases
- App marketing and ASO teams: track sentiment and recurring themes across countries and app versions to plan messaging and release notes.
- Product and QA teams: catch problems early after a release by watching for new and updated low-rated reviews.
- Competitive research: compare your app's ratings and review volume against competitors across the same storefronts.
- Customer support and community teams: surface unresolved complaints and recurring issues from the most recent reviews.
- Data science and NLP teams: build labeled datasets of sentiment, feature requests and bug reports at scale.
Data You Get
Sample shape: values are illustrative placeholders, not from a live review.
| Field | Example |
|---|---|
reviewId | "9000000001" |
appId | "1234567890" |
appName | "Sample App" |
country | "us" |
rating | 5 |
title | "Sample review title" |
body | "Full review text appears here." |
author | "Reviewer Name" |
authorId | "500000001" |
authorUri | "https://itunes.apple.com/us/reviews/id500000001" |
reviewUrl | "https://itunes.apple.com/us/review?id=1234567890&type=Purple%20Software" |
appVersion | "1.0.0" |
reviewDate | "2026-01-01T00:00:00-07:00" |
voteSum | 0 |
voteCount | 0 |
contentType | "Application" |
changeType | "NEW" (also "UPDATED", "UNCHANGED", "REAPPEARED", "EXPIRED"; incremental mode only) |
changedFields | ["rating", "body"] (incremental mode, UPDATED rows only) |
firstSeenAt | "2026-01-01T00:00:00Z" (incremental mode only) |
lastSeenAt | "2026-02-01T00:00:00Z" (incremental mode only) |
With app-detail enrichment on, each review also carries: appSellerName, appAverageRating, appRatingCount, appAverageRatingCurrentVersion, appRatingCountCurrentVersion, appPrimaryGenre, appContentRating, appBundleId, appIconUrl, appStoreUrl, appPrice, appCurrency, appMinimumOsVersion, appCurrentVersion, appCurrentVersionReleaseDate, appReleaseNotes.
How to Use
- Pick a mode:
search(by app name) orurl(paste one or more App Store app links). - Set the countries to sweep, the sort order, and optional minimum/maximum rating filters.
- Turn on app-detail enrichment if you want app metadata attached, and set Max reviews (and optionally Max pages per country) to control run size and cost.
- Click Start, then download the dataset as JSON, CSV or Excel, or read it through the API.
Search by app name, US storefront:
{"mode": "search","queries": ["Instagram", "Spotify"],"appsPerQuery": 1,"countries": ["us"],"sortBy": "mostRecent","maxItems": 100}
Sweep several countries for one app via its link:
{"mode": "url","urls": ["https://apps.apple.com/us/app/instagram/id389801252"],"countries": ["us", "gb", "de", "jp"],"maxItems": 500}
Only high-rated reviews, with app details attached:
{"mode": "url","urls": ["https://apps.apple.com/us/app/instagram/id389801252"],"countries": ["us"],"minRating": 4,"fetchDetails": true,"maxItems": 200}
Multiple app links at once:
{"mode": "url","urls": ["https://apps.apple.com/us/app/instagram/id389801252","https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580"],"countries": ["us"],"maxItems": 200}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/app-store-reviews-scraper").call(run_input={"mode": "search", "queries": ["Instagram"], "countries": ["us"], "maxItems": 100})for review in client.dataset(run["defaultDatasetId"]).iterate_items():print(review["rating"], review["title"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/app-store-reviews-scraper').call({ mode: 'search', queries: ['Instagram'], countries: ['us'], maxItems: 100 });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
Resume (resumeFromRunId)
Paste a previous run ID (or dataset ID) from this actor and the run skips every review already collected there (matched on app, country and review id), so a run cut short by an error or a cost cap can be continued without paying twice. This works the same way for both search mode and url mode, including runs built entirely from pasted app links: a pasted-link run with resumeFromRunId set skips exactly the reviews the earlier run already collected for those same links, the same protection search mode gets.
Incremental mode (recurring/scheduled monitoring)
Turn on incrementalMode for a search you run on a schedule to get back only what changed since the last run instead of the whole dataset again: add "incrementalMode": true to any of the input examples above, for example the "Sweep several countries for one app via its link" example.
Each review gets a changeType: NEW (never seen before), UPDATED (a real field changed, see changedFields), UNCHANGED (nothing changed, suppressed from the output unless emitUnchanged is on), or REAPPEARED (was previously marked EXPIRED and is back). Set emitExpired: true to also get an EXPIRED row for a tracked review that disappeared, but only on a run that completes a full, uncapped scan: a maxItems or maxPages limit that actually cuts a walk short, resumeFromRunId, or a run that continued from a saved checkpoint all skip EXPIRED detection for that run rather than risk a false positive. EXPIRED means "no longer served by the storefront's review listing", which is not always the same as "deleted" (see the 500-review window below).
What counts as "changed": rating, title, body, author, review date, and the reviewed app version are real review content, a change to any of these is a real UPDATED. voteSum and voteCount are excluded: other users' helpful votes accrue on an old review indefinitely, so treating them as a content change would mark almost every historical review UPDATED on every run. When fetchDetails is on, the attached app-metadata fields (seller, average rating, rating count, genre, price, current version, release notes, and so on) are also excluded, since they describe the current state of the app, not the review, and drift independently every time the app itself updates.
State size: the saved baseline stores a per-field content fingerprint for each tracked review, never the review's actual title or body text, to stay well under the platform's key-value-store size limit even for large monitoring campaigns. One consequence: an EXPIRED row can only report the review's id, app, country and timestamps; its original title, body and rating are not retained in the incremental baseline and are not reproduced on the tombstone row.
State is keyed automatically by a hash of your search settings (mode, queries/URLs, countries, sort, rating filters and fetchDetails); two different filter setups never share a baseline, and raising maxItems or maxPages never starts a new one. Set stateKey to name a campaign explicitly, for example to track several searches independently or to intentionally share one baseline across otherwise different runs.
Known limits to plan around:
- The storefront lists at most about 500 reviews per app, per country, per sort order. Apple's review listing stops after 10 pages of 50, so no setting (not
maxPages: 0, notmaxItems: 0) returns more than that for one app in one country and one sort order. To widen coverage, add more countries or run bothmostRecentandmostHelpful. In incremental mode this window also drivesEXPIRED: on a busy app, a tracked review that scrolls past the 500 most recent (or drops out of the 500 most helpful) is no longer listed, so withemitExpiredon it is reported, and billed, asEXPIREDeven though it still exists on the App Store, and asREAPPEAREDif it ever comes back into the window. EXPIREDrows are not capped by Max reviews. They are computed once the main walk finishes, from every previously tracked review that was not seen again this run, and the whole batch is pushed regardless ofmaxItems. If a large number of tracked reviews disappear at once (for example the app itself is pulled), a single run withemitExpiredon can return, and bill, far more rows thanmaxItemssuggests. TurnemitExpiredoff, or expect this, when tracking a search where mass disappearance is plausible.- A run restarted by the platform (a migration or the Resurrect button) forgets the classification of everything it returned before the restart. The restarted run continues from its saved position and never pushes a review twice, but the incremental baseline is only saved once, when the run finishes, and the restarted run does not re-read the pages it had already walked. So every review returned before the restart (all of them, not just the last few) is left out of the saved baseline: on the next ordinary scheduled run those reviews come back, and are billed again, as
NEW(orUPDATED/REAPPEAREDagain if that is what they were). Reviews returned after the restart are saved normally, and the rest of the campaign's baseline is untouched. - Bootstrapping incremental mode from
resumeFromRunIdstarts every resumed review with an empty fingerprint. The run refuses to combineresumeFromRunIdwithincrementalModewhen the target state already has tracked reviews, but the very first time (an empty baseline, whether auto-keyed or a newstateKey), every review in the resume dataset is added to the new baseline with no known content. The next incremental run over that search then reports every one of those reviews asUPDATED, with every field listed inchangedFields, and bills them, even if nothing changed. Every row of the resume dataset is added, even ones for apps or countries outside the current search; withemitExpiredon, those are reported, and billed, asEXPIREDon the next complete scan. If you plan to track a search going forward, starting Incremental mode fresh (one fullNEWrun) is usually cheaper and clearer than bootstrapping from an old resume dataset. - Max reviews is split evenly across apps and countries up front and is not rebalanced. When a run covers several apps or countries in one go,
maxItemsis divided into an even share per stream before scraping starts. If one stream has fewer reviews available than its share (including the same app listed twice, or two search terms that find the same app), that leftover budget is not handed to the other streams, so the run can finish undermaxItemseven though another stream in the same run still had reviews left to give. Run a mix of very low-volume and very high-volume targets as separate runs, or raisemaxItems, if you need the cap fully used. - A rating filter can end a country's walk early. With
minRatingormaxRatingset, once at least one matching review has been collected for an app and country, a later page of 50 on which no review matches the filter is treated as the end of that country's reviews, and later pages are not read. Narrow filters on apps where matching reviews are rare (for examplemaxRating: 1on a highly rated app) can therefore return fewer reviews than exist. In incremental mode withemitExpiredon, tracked reviews on the unread pages are also reported, and billed, asEXPIRED. If you need every matching review, run without the rating filter and filter the dataset afterwards.
Send results into your apps (MCP connectors)
You can optionally pipe results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector under Apify, Settings, API & Integrations, then select it in the input. For Notion, set a parent page URL and each review is written as a page. Other connectors receive a best-effort write.
The connector receives a condensed, human-readable summary of each review (a heading plus the key fields and body text), not the full JSON. The complete record always stays in the Apify dataset. Leave the connector field empty to skip this step; it never changes the dataset output.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (by app name) or url (paste App Store app links). |
queries | array | ["Instagram"] | App names or keywords to look up (search mode). Ignored in URL mode. |
appsPerQuery | integer | 1 | How many top matching apps to take per search term. Ignored in URL mode. |
urls | array | sample Instagram link | App Store app links (URL mode). Multiple URLs supported. |
countries | array | ["us"] | Storefront codes to collect reviews from. Leave empty to use each URL's own storefront (URL mode) or us (search mode). ["all"] sweeps a broad built-in set of major storefronts. |
sortBy | string | mostRecent | mostRecent or mostHelpful. |
minRating | integer | (none) | Keep only reviews at or above this star rating (1 to 5). |
maxRating | integer | (none) | Keep only reviews at or below this star rating (1 to 5). |
fetchDetails | boolean | false | Attach app metadata (developer, average rating, rating count, genre, icon, price, release notes) to each review. Adds a billed lookup per app. |
maxItems | integer | 20 | Maximum reviews to collect in total. 0 means no limit. |
maxPages | integer | 0 | Bound on review pages walked per country (50 reviews per page). 0 walks every page the storefront serves, which is at most 10 (about 500 reviews) per app, country and sort order. |
resumeFromRunId | string | (none) | Previous run ID (or dataset ID) from this actor. Reviews already collected there are skipped. |
incrementalMode | boolean | false | For a search run on a schedule: remember reviews already seen and return only what changed. |
stateKey | string | (none) | Name this monitoring campaign to run several tracked searches independently. Leave empty to derive it automatically from your search settings. |
emitUnchanged | boolean | false | Also return reviews with changeType = UNCHANGED. Turning this on bills every scanned review, every run. |
emitExpired | boolean | false | Also return a row per previously tracked review no longer found, once a run completes a full scan. See the Incremental mode notes above for the Max reviews caveat. |
proxy | object | Apify Proxy | Connection settings. |
mcpConnectors | array | (none) | Optional: send a summary of each review to apps you authorized under Integrations. |
notionParentPageUrl | string | (none) | Notion connector only: page under which review pages are created. |
maxNotifyListings | integer | 50 | Cap on items written to each connector per run. Does not affect the dataset. |
Output Example
Sample shape: values are illustrative placeholders, not from a live review.
{"reviewId": "9000000001","appId": "1234567890","appName": "Sample App","country": "us","rating": 5,"title": "Sample review title","body": "Full review text appears here.","author": "Reviewer Name","authorId": "500000001","authorUri": "https://itunes.apple.com/us/reviews/id500000001","reviewUrl": "https://itunes.apple.com/us/review?id=1234567890&type=Purple%20Software","appVersion": "1.0.0","reviewDate": "2026-01-01T00:00:00-07:00","voteSum": 0,"voteCount": 0,"contentType": "Application"}
Plan Requirement
Runs on any Apify plan; the default connection setting works out of the box. For very large multi-country sweeps, a proxy group with more exit rotation can help; pick it under Proxy configuration.
FAQ
How much does it cost?
You pay per review returned, plus one app-detail charge per app when enrichment is on. The Pricing tab shows the current rates. Use Max reviews (and Max pages per country) to cap the cost of any run.
Is it legal to scrape the App Store?
This actor collects only publicly available review data. You are responsible for how you use it: follow Apple's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Review text and ratings are user-submitted content, so treat authorship and attribution carefully in anything you publish from it.
Can I get only new or changed reviews on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated, reappeared and (optionally) expired reviews, and unchanged ones are not billed unless you turn that on too.
What's the difference between Resume from run ID and Incremental mode?
Resume from run ID continues one specific interrupted run: paste its id and this run skips whatever that run already collected. Incremental mode is for repeated scheduled monitoring of the same search: it remembers state itself, across as many runs as you like, without you pasting anything each time. Use resume to recover from an error or a cost cap on a single run; use incremental mode for an ongoing tracked search.
Why did my run return an empty dataset instead of failing?
An app with no reviews for the countries and filters you chose is a normal, valid result, not an error, so the run finishes with an empty dataset and a clear status message. The run only fails outright when a cross-run link it needs cannot be resolved: an invalid Resume from run ID, or combining Resume from run ID with Incremental mode on a search that already has saved incremental state.
Why did a multi-app or multi-country run finish under Max reviews?
Max reviews is split evenly across every app/country combination in the run before scraping starts. If one of them runs out of reviews early, its unused share is not passed on to the others. A narrow rating filter can also end a country early. See "Known limits to plan around" in How to Use for the full explanation and workarounds.
Why can't I get more than about 500 reviews for one app?
The App Store review listing serves at most 10 pages of 50 reviews per app, per country, per sort order, so that is the ceiling for any single combination no matter how high you set Max reviews or Max pages per country. Add more countries, or run both sort orders, to collect more.
Why did an Expired cleanup return more rows than Max reviews?
emitExpired rows are computed after the main scan and are not counted against Max reviews, so a run where many tracked reviews disappeared at once can return more rows than the cap suggests. On a busy app, reviews that simply scroll out of the 500-review window also count as disappeared. See "Known limits to plan around" in How to Use.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
π Want more leads data?
Pair this actor with these related scrapers from the same team:
| π± Google Play Reviews Collect Google Play reviews and ratings for any app across country storefronts. Search by... | π± Clutch Scraper Scrape Clutch company directories and profiles. Get names, ratings, review counts, hourly... |
| π± Mastodon From $1/1K. Scrape trending Mastodon profiles and related posts from any Mastodon... | π Google Maps Scraper Extract business data from Google Maps at scale. Get names, addresses, phone numbers... |
| π± TrustMate.io Scrape complete company review histories from TrustMate.io. Paste company profile URLs... | π Houzz Pro Scraper From $1/1K. Pull Houzz pro listings across global sites. Search by category and location... |
π Browse all abotapi scrapers
π¬ Support & custom scrapers
- π Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- π οΈ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
- β Enjoying it? A quick review on the actor page helps other users find it.