Apple App Store Reviews - Ratings, Reviews & App Metadata avatar

Apple App Store Reviews - Ratings, Reviews & App Metadata

Pricing

from $0.60 / 1,000 reviews

Go to Apify Store
Apple App Store Reviews - Ratings, Reviews & App Metadata

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

Abot API

Maintained by Community

Actor stats

1

Bookmarked

1

Total users

0

Monthly active users

17 hours 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 first. Rating, title, body, author, date, app version and country on every row.
  • Three ways in. Search by app name, paste App Store app links (apps.apple.com or itunes.apple.com), or give bare numeric app ids.
  • 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 and filter. Most recent or most helpful, with minimum and maximum star rating.
  • Optional app metadata. 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.

FieldExample
reviewId"9000000001"
appId"1234567890"
appName"Sample App"
country"us"
rating5
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"
voteSum0
voteCount0
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

  1. Pick a mode: search (by app name) or url (paste one or more App Store app links).
  2. Set the countries to sweep, the sort order, and optional minimum/maximum rating filters.
  3. 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.
  4. 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 ApifyClient
client = 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, which never produces EXPIRED rows).

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. To exclude more fields, list their output names in ignoreFieldsForChanges (for example authorUri): they stay in the output and the saved baseline and are only left out of the comparison and of changedFields. Changing this list never causes a one-time wave of UPDATED rows, because the saved fingerprints are re-checked against the current list.

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, App IDs, 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, not maxItems: 0) returns more than that for one app in one country and one sort order. To widen coverage, add more countries or run both mostRecent and mostHelpful. In incremental mode a walk that hits this ceiling (or a page that failed to load) is treated as a partial scan, so EXPIRED detection is skipped for that run and a tracked review that scrolled out of the window is never reported, or billed, as EXPIRED. Only an app whose whole listing fits inside the window and ends naturally can produce EXPIRED rows.
  • When the review feed stays empty, only a small selection of reviews is returned. If the first page of an app and country is still empty after 20 requests, the actor reads the reviews listed on the app's own App Store page instead (the log says so). That page lists at most 10 reviews, Apple's selection of helpful ones (ordered newest first when Sort is mostRecent), with no app version, author id, author link, review link or vote counts (those fields are empty), and has no further pages, so the run returns those 10 rows and stops that app and country. Run again later for the full history. A run whose pages were only read this way, or whose feed stayed empty on any page, never reports EXPIRED rows (an empty answer is not proof that reviews are gone), and reviews already tracked in incremental mode are not re-reported from that page. A review first read from that page is not reported as UPDATED (or billed again) when the feed later returns it with the fields the page lacks: only a real change to its rating, title, text or author makes it UPDATED. reviewDate on those rows is written in the same form as feed rows (the Pacific clock reading with the feed's -07:00 label), so the column has one format.
  • EXPIRED rows 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 of maxItems. If a large number of tracked reviews disappear at once (for example the app itself is pulled), a single run with emitExpired on can return, and bill, far more rows than maxItems suggests. Turn emitExpired off, 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 (or UPDATED/REAPPEARED again 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 resumeFromRunId starts every resumed review with an empty fingerprint. The run refuses to combine resumeFromRunId with incrementalMode when the target state already has tracked reviews, but the very first time (an empty baseline, whether auto-keyed or a new stateKey), 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 as UPDATED, with every field listed in changedFields, 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; with emitExpired on, those are reported, and billed, as EXPIRED on the next complete scan. If you plan to track a search going forward, starting Incremental mode fresh (one full NEW run) 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, maxItems is 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 under maxItems even 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 raise maxItems, if you need the cap fully used.
  • A rating filter can end a country's walk early. With minRating or maxRating set, reviews outside the range are skipped but still counted as seen, so a page full of non-matching reviews never ends the walk or marks tracked reviews EXPIRED. Narrow filters on apps where matching reviews are rare can still return few reviews, because the storefront window is about 500 reviews.

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

ParameterTypeDefaultDescription
modestringsearchsearch (by app name) or url (paste App Store app links).
queriesarray["Instagram"]App names or keywords to look up (search mode). Ignored in URL mode.
appsPerQueryinteger1How many top matching apps to take per search term. Ignored in URL mode.
urlsarrayempty (the form is pre-filled with one example per supported link shape)App Store app links (URL mode): apps.apple.com or itunes.apple.com app pages, with or without storefront or name, with query params, ?see-all=reviews or #see-all/reviews. Developer and charts/category pages are not apps: they are skipped with a warning. The form shows one example per link shape as a starting point; delete the ones you do not want. A caller who sends no urls in URL mode gets no URL targets (only their own appIds). Duplicates of the same app and storefront are collapsed.
appIdsarrayemptyBare numeric App Store app ids (for example 389801252), in either mode, added to the apps from search or URLs. Bare numbers are also accepted inside urls. Reviews come from countries (or us when empty). In search mode, a search term left at the sample value Instagram is ignored when App IDs are set (the sample is only a form prefill); to include it as well, enter it again under App IDs.
countriesarray["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.
sortBystringmostRecentmostRecent or mostHelpful.
minRatinginteger(none)Keep only reviews at or above this star rating (1 to 5).
maxRatinginteger(none)Keep only reviews at or below this star rating (1 to 5).
fetchDetailsbooleanfalseAttach app metadata (developer, average rating, rating count, genre, icon, price, release notes) to each review. Adds a billed lookup per app.
maxItemsinteger20Maximum reviews to collect in total. 0 means no limit.
maxPagesinteger0Bound 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.
resumeFromRunIdstring(none)Previous run ID (or dataset ID) from this actor. Reviews already collected there are skipped.
incrementalModebooleanfalseFor a search run on a schedule: remember reviews already seen and return only what changed.
stateKeystring(none)Name this monitoring campaign to run several tracked searches independently. Leave empty to derive it automatically from your search settings.
emitUnchangedbooleanfalseAlso return reviews with changeType = UNCHANGED. Turning this on bills every scanned review, every run.
emitExpiredbooleanfalseAlso 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.
ignoreFieldsForChangesarray(none)Incremental mode only: output field names that must not make a review count as UPDATED.
proxyobjectApify ProxyConnection settings. See Plan Requirement for the log messages when the selected connection is unavailable.
mcpConnectorsarray(none)Optional: send a summary of each review to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which review pages are created.
maxNotifyListingsinteger50Cap 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 is the standard Apify proxy pool, which is the one setting this actor was built around; Apple's open review, search and lookup feeds answer it normally. Apify free plans do not include proxy access or residential proxies, so on a free plan the run may need its backup connection. Pick a different proxy group, or supply your own proxy URLs, under Proxy configuration if you want to control the connection yourself.

What you will see in the run log:

  • If the selected connection is unavailable to the run, a notice says: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable. For residential access, upgrade at https://apify.com/pricing or supply your own proxy URLs."
  • Pages served that way are marked: "Served over the backup connection (the default connection was unavailable)."
  • If the proxy connection is refused for the whole run, it ends as failed with: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required: https://apify.com/pricing. If you entered your own proxy URLs, check that their credentials are valid."
  • If residential access is unavailable and the backup connection could not load the pages either, it ends as failed with: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested App Store pages. Upgrade at https://apify.com/pricing or supply your own proxy URLs, then try again."
  • If no results page could be loaded because the requests failed, it ends as failed with: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

A run that cannot load any page ends as failed instead of reporting an empty result; a feed that answers with no reviews is a normal empty result. The App Store review feed sometimes answers a request with no reviews even when reviews exist, so each page is requested again up to 20 times before it is treated as empty. When page 1 of an app and country is still empty after that, the reviews shown on the app's own App Store page are used instead (see "Known limits to plan around"). If a country returns nothing for an app, the log says so for that app and country, and when every app and country in a run returned nothing, the status message names them ("The reviews feed returned no reviews for ...") and the run still ends as succeeded with an empty dataset.

Output views

The dataset has three views in the Console: Reviews (the core review fields), Reviews with app details (adds the app metadata columns when fetchDetails is on) and Changes (incremental mode) (changeType, changedFields, firstSeenAt, lastSeenAt). The dataset schema declares every field as nullable, so a missing value never fails a run.

Pricing

This actor uses pay-per-event pricing. The Pricing tab shows the live rates; this README names only the events and when they fire:

  • Actor Start: once per run (one event per GB of memory, minimum one).
  • Review: once for each review row pushed to the dataset. Reviews suppressed as unchanged in incremental mode and failed pages are not charged.
  • App detail enrichment: once per app whose metadata is attached, only when fetchDetails is on.

FAQ

How much does it cost?

You pay per review returned, plus one app-detail charge per app when enrichment is on, plus the run start event. See Pricing above and the Pricing tab for the current rates. Use Max reviews (and Max pages per country) to cap the cost of any run.

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 store feed can also come back empty for a while for an app that does have reviews (the actor then falls back to the small selection of reviews on the app's own App Store page); if that is empty too, the status message names the apps and countries, and running again later or adding another country usually returns them. 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...
πŸ“± Mastodon Scraper
Scrape trending Mastodon profiles and related posts from any Mastodon instance. Extract...
🧩 JB Hi-Fi AU Scraper
Scrape JB Hi-Fi Australia (jbhifi.com.au) products from the public storefront. Extract...
πŸ“± TrustMate.io
Scrape complete company review histories from TrustMate.io. Paste company profile URLs...
πŸ“± Clutch Scraper
Scrape Clutch company directories and profiles. Get names, ratings, review counts, hourly...
πŸ›’ ProductReview.com.au Scraper
Scrape ProductReview.com.au products, businesses and customer reviews. Search by...

πŸ‘‰ Browse all abotapi scrapers

πŸ’¬ Support

  • 🐞 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 contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.