Google Play Reviews & Play Store Scraper – Ratings, Dates avatar

Google Play Reviews & Play Store Scraper – Ratings, Dates

Pricing

$0.10 / 1,000 result items

Go to Apify Store
Google Play Reviews & Play Store Scraper – Ratings, Dates

Google Play Reviews & Play Store Scraper – Ratings, Dates

Google Play reviews and app details by package ID or app-name search. Filter by star rating, keyword, reply status, helpfulness votes or date range, so you are only charged for the rows you want. Country/language targeting, HTTP-only: no browser, no proxy, no login. Includes Google Play ratings.

Pricing

$0.10 / 1,000 result items

Rating

0.0

(0)

Developer

Fetch Smith

Fetch Smith

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

20 hours ago

Last modified

Share

Google Play Reviews Scraper

Get Google Play app reviews and app details (ratings, installs, developer info) by app ID or search term. HTTP-only (no browser), so runs are fast and cheap, and you're charged only for the rows you actually get.

It works as a Play Store data API and a Google Play data API in one Actor: pull the same review and app-details fields — ratings, installs, developer info, aspect ratings — as a clean dataset instead of scraping the storefront yourself. Use it as a mobile app reviews data source for any Android app, with country/language targeting and de-duplicated, watch-mode-ready results.

What it does

  • Fetches reviews for one or more Google Play apps, plus an optional app-details record (title, developer, score, installs, price, description, rating histogram).
  • Accepts package names (com.spotify.music), full Play Store URLs (paste the link straight from your browser), or searchTerms — the top matching app for each term is resolved automatically.
  • Supports country/language targeting and sort order (newest / rating / helpfulness).
  • Filter server-side by star rating (range or an exact set like 1★+5★), keyword(s), app version, or date range — so you're only charged for reviews you actually want, not the whole feed.
  • Reviews are de-duplicated by reviewId, so a repeated row from Google Play is never pushed — or charged for — twice.
  • Watch mode (watchLabel): run it on a schedule and get only the reviews posted since your last run instead of the same top-of-feed rows every time — a run with nothing new returns nothing and costs nothing. It also catches edits to reviews you already have: a reviewer changing their own star rating, or a developer reply being added or removed (watchEvents).
  • Includes per-review aspect ratings (aspectRatings) — the sub-scores Google Play attaches to a written review for specific aspects (e.g. ad frequency, ease of use) when the reviewer filled them in. None of the leading Store competitors expose this field (re-verified against their live output schemas 2026-09-17).

Input

FieldTypeDescription
appIdsarray of stringsGoogle Play package names (e.g. com.spotify.music) or full Play Store URLs (e.g. https://play.google.com/store/apps/details?id=com.spotify.music) — the package name is extracted from the URL's ?id= param
searchTermsarray of stringsAlternative to appIds: search terms; the top match for each is used, or the first genre-matching hit of the top 5 when genres is also set — see FAQ
countrystringPlay Store country code (default us)
languagestringLanguage for reviews/details (default en)
sortstringNEWEST (default), RATING, or HELPFULNESS
maxReviewsPerAppintegerReviews to fetch per app before moving to the next one (default 100, max 5000) — counted before rating/keyword/appVersion/date filtering, see FAQ
includeAppDetailsbooleanAlso push one app-details record per app (default true)
genresarray of stringsOnly scrape apps in these Google Play genres — every other app is skipped before any review is fetched, so it costs nothing. Takes the genre id (GAME_STRATEGY, EDUCATION), the display name (Strategy, Music & Audio) or GAME for any game genre, case-insensitive. See FAQ
maxResultsintegerHard cap across all apps and records (default 500)
minScore / maxScoreintegerOnly keep reviews with a star rating in this range (1-5)
ratingFilterarray of integersOnly keep reviews whose rating is one of these exact values, e.g. [1, 5] — use it when you want a non-contiguous set that minScore/maxScore can't express
keywordstringOnly keep reviews whose title or text contains this word/phrase (case-insensitive)
keywordsarray of stringsOnly keep reviews containing at least one of these words/phrases (case-insensitive)
appVersionsarray of stringsOnly keep reviews written against one of these app versions, e.g. ["9.1.78.2218"]. Google Play leaves version null on roughly 1 review in 6 — those are dropped when this filter is set
minThumbsUpintegerOnly keep reviews with at least this many "helpful" votes from other users
replyFilterstringany (default), hasReply (only reviews the developer already responded to), or noReply (only reviews still waiting for a response — the support-queue use case)
minReviewLengthintegerOnly keep reviews whose text is at least this many characters — filters out one-word/emoji-only reviews
sinceDate / untilDatestringOnly keep reviews posted within this ISO date range
watchLabelstringOptional. Name a saved watch (e.g. my-app-alerts) to get only reviews not delivered under that label before — see "Watch mode" below
watchEventsarrayOptional, watch mode only. Which changes to report: new, scoreChanged, developerReplied, replyRemoved. Empty = all four
webhookUrlstringOptional. An http(s) URL to POST a small JSON completion summary to when the run finishes — see FAQ.

Watch mode — only new reviews since the last run

Set watchLabel to any name and this Actor stops re-delivering the same reviews on every scheduled run:

  1. First run for a label is a free baseline. It records which reviews already exist (walking at least 1000 per app, regardless of your maxReviewsPerApp, up to 5000 reviews total) and returns zero rows — you are charged nothing.
  2. Every run after that returns only reviews that weren't in the baseline, and adds them to it. Nothing new → zero rows → zero charge.
  3. Reviews already in the baseline are re-delivered when they actually change. Google Play keeps a review's id stable when the reviewer edits their own star rating and when you add or delete a developer reply, so an id-only watch would go silent forever on exactly those events. Pick which ones you want with watchEvents (new, scoreChanged, developerReplied, replyRemoved; leave empty for all four). Changed rows carry watchEvent, previousScore and previousHasDeveloperReply so you can see what moved.

The baseline lives in your own Apify account, in a named key-value store called fetchsmith-google-play-reviews-watch, keyed by your label plus a fingerprint of the apps/search terms, country, language, sort order and every rating, keyword, app-version, thumbs-up, reply, genre and date filter. Change any of those and you get a fresh baseline rather than a silently wrong one — otherwise widening a filter would hide the newly-matching older reviews as "already seen". Delete the record to start over; use different labels to watch several filter sets in parallel.

Details worth knowing:

  • Change events need one run to warm up. A baseline created before watchEvents existed stores review ids but not the star rating/reply state to diff against; the first run after upgrading records that state (and says so in the log), so scoreChanged/developerReplied/replyRemoved start firing from the run after that. New reviews are unaffected.
  • A score edit that also added a reply is one row, not two. The change is reported under its primary event (scoreChanged) and charged once; the row's own replyText shows the current reply state.
  • Use sort: "NEWEST" (the default). With RATING or HELPFULNESS a brand-new review isn't necessarily inside the first maxReviewsPerApp rows, so new reviews can be missed; the run logs a warning if you do it anyway.
  • maxReviewsPerApp is your fetch-depth budget on incremental runs and is left exactly as you set it. If every matching review inside that window turned out to be new, the run warns you (and says so in the status message) that reviews posted before the window may have been missed — raise maxReviewsPerApp or run the watch more often.
  • App-details records are only returned on a run where that app actually has a new review, so a quiet run really does cost nothing. On non-watch runs they behave as before.
  • If a searchTerms lookup resolves to a different app than last time, that app is baselined on the spot rather than having its entire back catalogue delivered as "new".
  • Baseline size cap. The saved record holds at most 20,000 review ids; once a long-running label grows past that, the oldest ids fall off and those reviews would be reported (and charged) as "new" again on a later run. The run now says so explicitly — a WARNING in the log, in the run's status message, and baselineTruncated/baselineTruncatedTotal in the webhookUrl payload and the saved record (truncatedLastRun/truncatedTotal) — so you can narrow the filters or split the apps across labels before it costs you anything.

Output

One item per row, either an app-details record (recordType: "app") or a review (recordType: "review").

Sample review row:

{
"recordType": "review",
"appId": "com.spotify.music",
"reviewId": "24191734-8bd7-4aac-a714-46193c46b4d4",
"userName": "Nikhil Rathod",
"reviewerProfileImageUrl": "https://play-lh.googleusercontent.com/a-/...",
"score": 5,
"title": null,
"text": "my motivation",
"date": "2026-09-08T03:01:35.135Z",
"language": "en",
"thumbsUp": 0,
"version": null,
"replyText": null,
"replyDate": null,
"aspectRatings": [
{ "criteria": "vaf_app_quality_ads_frequency", "rating": 2 }
],
"url": "https://play.google.com/store/apps/details?id=com.spotify.music&reviewId=..."
}

Sample app-details row includes: title, developer, score, ratings, reviewsCount, histogram, installs, price, free, genre, contentRating, released, updated, url.

Pricing

result — $0.0001 per returned item (review or app-details row). The run start is free. Matches the two largest real-usage competitors' flat rate (thewolves and theagents, both $0.0001/review, no start fee) and undercuts the niche's biggest listing by users, neatrat, whose tiered price starts at $0.00015/review on the free plan. Re-verified against their live pricing 2026-09-17.

FAQ

Can I get reviews in a specific country or language? Yes, set country and language (Play Store returns different review sets per locale — run the Actor for each locale you need). Can I search by app name instead of package ID? Yes, use searchTerms; the top matching app is resolved automatically. Why did I get fewer reviews than the app's total rating count? Google Play's review API only returns a subset of written reviews, not every rating — this is a platform limitation, not a bug. Does keyword/keywords handle accented words correctly? Yes, as of v0.1.20 — both fields and the review text they're matched against are Unicode-normalized before comparing, so an accented word (e.g. "café") matches regardless of which of Unicode's two equivalent representations (composed vs. decomposed) you typed it in. Can I filter to just negative or just recent reviews? Yes — set maxScore (e.g. 2) for negative-only, ratingFilter: [1, 5] for only the extremes, or sinceDate/untilDate for a date window; filtering happens before you're charged, so you never pay for rows you filtered out.

Can I restrict a run to games (or to any one app category)? Yes — set genres. ["GAME"] keeps every game genre (GAME_STRATEGY, GAME_CASUAL, GAME_PUZZLE, …); ["GAME_STRATEGY", "Music & Audio"] mixes an exact genre id with a display name. Verified 2026-09-28: with genres: ["GAME"], com.king.candycrushsaga (GAME_CASUAL) and com.supercell.clashofclans (GAME_STRATEGY) were scraped while com.spotify.music (MUSIC_AND_AUDIO) and com.duolingo (EDUCATION) were skipped with zero reviews fetched and zero charged. It needs one app-details lookup per app, so it works with includeAppDetails off too, and if the genre can't be read the app is skipped rather than scraped unfiltered — you are never billed for rows the filter exists to exclude.

With genres set, does a searchTerms lookup still use just the top hit? No — when genres is set it pulls the top 5 search hits (instead of 1) and keeps the first one whose own genre already matches, falling back to the top hit only if none of the 5 do. Without genres, searchTerms still resolves to the single top hit, same as always. This matters because Play's #1 result for a term is not always the right category: verified 2026-09-28, searchTerms: ["sky"] with genres: ["EDUCATION"] resolved to com.noctuasoftware.stellarium_free (EDUCATION, Play's 4th-ranked hit for "sky") — the unranked #1 hit for "sky" is a role-playing game. Before this fix, a term like that returned zero apps instead of the education one buried a few ranks down.

Can I see what broke in a specific release? Set appVersions to the version string(s) you care about (they match the version field on each review row) and, if you want, combine it with maxScore: 2 and keywords to isolate the complaints. Reviews where Google Play reports no version are excluded rather than guessed at.

Can I find reviews my support team hasn't answered yet, or check response quality on the ones we have? Yes — replyFilter: "noReply" returns only reviews with no developer response (combine with maxScore: 2 for an unanswered-complaints queue); replyFilter: "hasReply" returns only the ones you already responded to, e.g. to audit response quality or turnaround. minThumbsUp and minReviewLength are the same idea applied to helpfulness votes and review length — e.g. minThumbsUp: 5 surfaces the reviews other users found worth upvoting, and minReviewLength: 100 filters out one-word/emoji-only noise. All three were already computed on every review row (thumbsUp, replyText, text) but unfilterable before this — live-verified on a real app (Discord) that 21/50 recent reviews had a developer reply and the other 29 didn't, split exactly by replyFilter.

What is aspectRatings? Google Play sometimes prompts a reviewer to rate specific aspects of the app (e.g. "Ads frequency", "Ease of use") alongside their overall star score. When present, each row's aspectRatings array has one {criteria, rating} entry per aspect the reviewer answered — verified live across 800 reviews on 4 major apps (Spotify, WhatsApp, Duolingo, Candy Crush Saga): 27.3% carried at least one aspect rating, and the taxonomy is category-aware (games get dozens of genre-specific criteria, utility apps get a small generic set). It's [] when the reviewer didn't answer any (most reviews). We're the only Google Play reviews Actor on the Store that surfaces this field — the top 3 competitors by users don't include it in their output schema (re-verified 2026-09-17). One quirk worth knowing: ~2% of criteria entries use a vaf_never_display_* prefix — Google's own internal name implying its UI won't render that category, yet it comes back in the same array as every normal one, with nothing distinguishing the two. See the full write-up for the per-app numbers.

Why did I get fewer reviews than maxReviewsPerApp? maxReviewsPerApp is a fetch cap, not a match count — Google Play returns up to that many reviews (newest-first by default), and rating/keyword/appVersion/date filters are applied after that, per review. A narrow filter combined with a low cap can miss real matches sitting further back in the feed: on WhatsApp (com.whatsapp) with keyword: "crash", maxReviewsPerApp: 20 fetches 20 reviews and keeps 0, but raising it to 200 finds 1 — the match was always there, just never fetched. When this happens the log carries a WARN naming the cap and how many fetched reviews were dropped, and the run's status message says the same — raise maxReviewsPerApp to search deeper. Filtered-out reviews are not charged either way. Why does ratingFilter: [1, 2] return 0 rows even though the app clearly has low ratings? Check sort. RATING sorts highest-first, so the maxReviewsPerApp fetch cap (applied before any filter, see above) can fill up entirely with 5-star reviews and never reach a 1★ or 2★ one — same root cause as the fetch-cap FAQ, just with sort order as the trigger instead of a low cap. Use sort: "NEWEST" (the default) when hunting for specific low ratings — raising maxReviewsPerApp will not rescue a RATING-sorted run on a popular app. Verified 2026-09-25 on Spotify (com.spotify.music): with sort: "RATING", maxReviewsPerApp: 5000 (the maximum) fetched all 5000 and kept 0 for both ratingFilter: [1, 2] and ratingFilter: [4] — every one of the 5000 was a 5★ review, so no allowed cap value can reach lower stars. The run now warns about this combination up front, before spending the fetch budget.

How do I get alerted about new reviews instead of re-downloading the same ones? Set watchLabel and schedule the Actor (Apify Console → Schedules). The first run is a free baseline that returns nothing; every later run returns only the reviews posted since the previous run, so a scheduled hourly watch on a quiet app costs nothing at all. See "Watch mode" above for how the baseline is keyed and what to watch out for.

Can I be alerted when someone edits a review I already downloaded? Yes — that is what watchEvents is for. Google Play lets a reviewer rewrite their own review (same review id, new star rating) and lets a developer add or delete a reply at any time, and a watch keyed only on review ids can never see either. With a watchLabel set, this Actor also diffs the star rating and reply state each review had when it was last delivered, and re-delivers it as watchEvent: "scoreChanged", "developerReplied" or "replyRemoved" with previousScore/previousHasDeveloperReply filled in. Restrict it to the events you care about (e.g. ["scoreChanged"] to track only rating downgrades) so you never pay for the rest. A baseline created before this existed needs one run to record the state it will diff against.

How is webhookUrl different from Apify's own platform webhooks? Apify's platform webhooks are configured separately per Task/Actor via the Console or the Webhooks API — useful if you already live in the Apify Console, but extra setup if you're calling this Actor's API directly and just want a completion ping. webhookUrl is a plain input field: set it on the run itself and it POSTs a JSON body (actorRunId, defaultDatasetId, finishedAt, pushed, and — if watchLabel is set — watchSeeding/watchNewCount/watchSkipped/baselineTruncated/baselineTruncatedTotal) once the run finishes and every review has already been pushed and charged. It's best-effort — a slow or failing webhook only logs a warning, it never fails the run, changes the result set, or affects billing.

Engineering write-ups behind this Actor:

Notes

Only public Google Play data is collected. Issues or feature requests: support@fetchsmith.com. Also available as a hosted API at https://fetchsmith.com/tools/google-play-reviews-scraper

Source code: https://github.com/Fetchsmith/fetchsmith/tree/main/actors/google-play-reviews-scraper