Google Play Store Reviews Scraper: Android App Reviews avatar

Google Play Store Reviews Scraper: Android App Reviews

Pricing

from $0.05 / 1,000 reviews

Go to Apify Store
Google Play Store Reviews Scraper: Android App Reviews

Google Play Store Reviews Scraper: Android App Reviews

Scrape Google Play reviews by app URL or package name, language and country: rating, text, reviewer nickname, date, app version, thumbs-up, developer reply and review id, newest first, most relevant or highest rating. Several apps per run, a cap per app, a free app row with a completeness verdict.

Pricing

from $0.05 / 1,000 reviews

Rating

0.0

(0)

Developer

Hyperbach

Hyperbach

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Google Play reviews by app, language and country, logged out: Play URLs or package names in, one row per review out — the star rating, the text, the reviewer's nickname and avatar, the date, the app version the reviewer used, the thumbs-up count, the developer's reply with its date, the criteria ratings and the review id — newest first, most relevant or highest rating first, several apps in one run, a cap per app. One free app row per app carries a completeness verdict: COMPLETE (the list's own end), CAPPED (your limit) or PARTIAL. An unknown package, an app with no review in the language: free typed rows. No login, no Google account, no API key, proxies handled for you.

Why this Google Play reviews scraper

  • Several apps in one run. Give Play URLs or package names: each app gets its own cap (maxReviewsPerApp), and the run's cap sits on top (maxItems). A URL's own hl and gl are used when language and country are empty.
  • Three orders. newest, mostRelevant (Google Play's own order) and rating (5 stars first, then 4, 3, 2, 1). The first pages of newest and most relevant shared no review on our test. Each row carries its rank in the order read.
  • Every field Google Play shows. The star rating and the text, the reviewer's nickname and avatar, the date (UTC), the app version the review was written on, the thumbs-up count, the developer's reply with who wrote it and when, the criteria ratings some apps ask for (criteria), and Google Play's review id with a link to the review; every row carries the app, the language, the country and the input it answers.
  • Deep walks. The reviews come 200 a call in the order asked, page after page, to the end of Google Play's list: our test read 12,000 of WhatsApp's newest English reviews with no end in sight (2026-10-22). The free app row says how many reviews were delivered from how many pages and why the walk stopped: the list's own end (COMPLETE), your cap (CAPPED), or a refusal or the time limit (PARTIAL).
  • Language is the set. Google Play lists the reviews written in the language asked (language, the store's hl): French reviews are another set from English ones. The country (the store's gl) is on every row; on our test it did not change the reviews listed.
  • Honest runs. A package Google Play does not know is a free not_found row (its app page answered 404 on two exits), an app with no review in the language a free empty row, a value that is no Play app a free invalid row, a repeated app a free duplicate row. Every input gets a row; a review is charged once a run.
  • Fast and light. Plain HTTP on the call Google Play's own web page makes: 200 reviews a call, about 30 KB on the wire for the newest 200. A run of 3 apps × 260 reviews took 4 seconds of reading on our test.

Who it's for

  • App developers and product teams — the newest reviews of your Android app in every language you ship, with the app version per review to see what a release changed, and your team's replies beside them.
  • ASO and market researchers — the reviews of a list of competitor apps in one run, newest, most relevant or highest rated first, with the criteria ratings some categories carry.
  • Data and analytics teams — typed rows keyed by app_id, language and review_id, a free row per app with the status and verdict, a run summary to check a pipeline against.

Quick start

The newest reviews of two apps (a Play URL and a package name)

{
"appIds": [
"https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=US",
"com.instagram.android"
],
"maxReviewsPerApp": 50
}

One app's reviews in German, up to 1,000

{
"appIds": [
"com.spotify.music"
],
"language": "de",
"country": "DE",
"maxReviewsPerApp": 1000
}

The most relevant reviews of an app

{
"appIds": [
"com.duolingo"
],
"sort": "mostRelevant",
"maxReviewsPerApp": 200
}

Output

One row per review (and one free app row per app):

fieldmeaning
row_typereview (one review, charged) or app (the app's row with the walk's verdict; free).
input_indexThe 1-based position in appIds of the input this row answers.
input_valueThe input as you gave it (the URL or package name).
app_idThe app's package name (com.whatsapp).
languageThe language read (Google Play's hl: en, pt-BR …).
countryThe store country sent (Google Play's gl: US, GB …).
sortThe order read: newest, mostRelevant or rating.
statusAn app row: ok, empty, not_found, invalid, duplicate, failed or not_read (see the FAQ). A review row: ok.
status_detailWhy, in words, when the status is not ok.
scraped_atWhen the row was read (ISO 8601, UTC).
review_idGoogle Play's review id.
rankThe review's position in the order read (from 1).
ratingThe star rating, 1 to 5.
textThe review's text.
reviewer_nameThe reviewer's nickname, as Google Play shows it.
reviewer_imageThe reviewer's public avatar image.
published_atWhen the review was written or last edited (ISO 8601, UTC).
app_versionThe app version the review was written on (null when Google Play does not show one).
thumbs_upHow many users marked the review helpful (thumbs up).
reply_byWho wrote the developer's reply (the developer's name), null when there is no reply.
reply_textThe developer's reply to the review, null when there is none.
replied_atWhen the developer replied (ISO 8601, UTC).
criteriaThe criteria ratings Google Play asks for in some categories, as {criterion, rating} pairs (vaf_app_quality_visual_appeal …); null when the review has none.
urlA link to the review on Google Play.
app_urlThe app's Google Play link in the language and country read (app row).
reviews_deliveredReview rows delivered for this app (app row).
pages_readPages of Google Play's review list read for this app (app row).
verdictCOMPLETE (the list's own end), CAPPED (your limit) or PARTIAL (a refusal or the time limit) (app row).
verdict_detailThe verdict in words, with the numbers (app row).

Example record:

{
"row_type": "review",
"input_index": 2,
"input_value": "com.spotify.music",
"app_id": "com.spotify.music",
"language": "en",
"country": "US",
"sort": "newest",
"status": "ok",
"status_detail": null,
"scraped_at": "2026-10-22T20:03:24Z",
"review_id": "7e211cf7-901d-448b-a5f5-41e0649d4b2d",
"rank": 3,
"rating": 1,
"text": "too much annoying ads after every song, atleast let us play 4-5 songs then give ads it will be still better 😡",
"reviewer_name": "nickname-redacted",
"reviewer_image": "https://play-lh.googleusercontent.com/a/avatar-redacted",
"published_at": "2026-10-21T20:01:44Z",
"app_version": "9.1.92.3058",
"thumbs_up": 0,
"reply_by": "Spotify AB",
"reply_text": "Hi. Thanks for bringing this up. We'll pass this on to our ads team. If you're seeing more ads than usual, can you try a quick reinstall? If that doesn't help, reach out to our Customer Service in support.spotify.com and search \"Contact us\". They'll help you report this.",
"replied_at": "2026-10-21T20:29:44Z",
"criteria": [
{
"criterion": "vaf_app_quality_ads_frequency",
"rating": 1
}
],
"url": "https://play.google.com/store/apps/details?id=com.spotify.music&reviewId=7e211cf7-901d-448b-a5f5-41e0649d4b2d",
"app_url": null,
"reviews_delivered": null,
"pages_read": null,
"verdict": null,
"verdict_detail": null
}

Pricing

Pay for the reviews a run delivers, plus one run start; no platform usage is billed to you. The review price falls with your Apify plan.

eventunitFreeStarterScaleBusiness
Review (review)per 1,000$0.10$0.085$0.07$0.05
Run start (start)per run$0.001$0.001$0.001$0.001

A review is $0.10 per 1,000 on the Free plan ($0.0001 a review). Each run that delivers a charged review also pays the run start, $0.001 once; a run that delivers no charged review pays nothing at all. So the 500 newest reviews of one app cost $0.0510 on the Free plan and $0.0435 on Starter, and 1,000 reviews $0.1010 / $0.0860; several apps in one run share one start. The free app row of every app, an unknown package (not_found), an app with no review in the language (empty), a value that is no Google Play app (invalid), a repeated app (duplicate), an app left at the cap or the time limit (not_read) and a refusal the run could not pass (failed) are never charged. A review is charged once a run. A run that stops early (a timeout, an abort) is charged for the reviews it delivered. maxItems counts the charged rows; before the first request the log names the price of each row at your plan and the most the run can cost. Enterprise plans have their own rates: the Actor's Pricing tab shows the price for your plan.

Usage patterns

  • Apps, language and country — appIds takes Google Play URLs (https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=US; market://details?id= links too) or package names (com.whatsapp). language takes Google Play language codes (en, de, pt-BR, es-419 …) and country two-letter codes (US, GB, DE …). Each app is read in the language and country given; when they are empty, in its URL's own hl and gl, else in en and US.
  • What a row is — row_type = review: one review with Google Play's record; rank is its position in the order read; sort the order. row_type = app: the free row of one app in one language and country — reviews_delivered, pages_read, the verdict with its verdict_detail, and the status with its reason.
  • How far an app goes — maxReviewsPerApp = 0 (the default) reads every review Google Play lists for the app, language and order — a big app lists millions, so set a cap, maxItems or a run timeout. maxReviewsPerApp = 100 is the first 100 in the order asked. maxItems caps the charged rows of the whole run. The app row's verdict says where the walk stopped and why.

Input configuration

fieldtypedefaultwhat it does
appIdsarrayThe apps to read: Google Play URLs (https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=US) or package names (com.whatsapp). A URL's own hl and gl are used when language and country are empty. Up to 1,000 apps a run; a value that is no Google Play app gets a free invalid row, an app given twice for the same language and country a free duplicate row.
languagestringThe reviews' language as Google Play codes it (en, de, fr, pt-BR, es-419 …). Google Play lists the reviews written in this language, so each language is a different set of reviews. Empty: the app URL's hl, else en.
countrystringThe two-letter Google Play country (US, GB, DE, IN …; UK is read as GB), sent as the store's gl and written on every row. Empty: the app URL's gl, else US. On our test the country did not change which reviews Google Play lists; the language does.
sortnewest / mostRelevant / rating"newest"newest: the newest reviews first. mostRelevant: Google Play's own most-relevant order. rating: the highest star rating first.
maxReviewsPerAppinteger0Stop each app after this many review rows (0 = every review Google Play lists for the app, language and order; a big app lists millions, so set a cap or maxItems).
maxItemsinteger0Stop the run after this many review rows across every app (0 = no limit). App rows are free and not counted; an app left unread at the cap gets a free not_read row.

Errors

A run does not fail because of your input. When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends Succeeded, charges nothing, and says what to change:

  • the status message starts with INPUT REJECTED;
  • the dataset holds one row, {"error": true, "code": "…", "message": "…"}, and no results;
  • the key-value store record ERROR holds the same object.

From code, check error on the first row before reading results.

An app with no review in the language asked is not an error: it gets one free app row with status empty, and the run goes on with the others. A run that ends Failed is a fault on our side, never your input; it charges nothing, and we are alerted.

FAQ

Which status is which?

An app row's status is ok (reviews served), empty (the app exists and has no review in that language), not_found (Google Play does not know the package; its app page answered 404 on two exits), invalid (a value that is no Google Play app), duplicate (the same app, language and country twice: read once), failed (a refusal or an error; free) or not_read (left at maxItems, the charge limit or the run's time limit). A review row's status is ok.

Is there a review title?

No. A Google Play review has a star rating and a text, no title; the row carries what Google Play shows.

Does it read ratings without a text?

No. Google Play lists the reviews with a written text; a star rating given without one is not in the list, so the review count of an app on its page (the ratings) is larger than what any review scraper returns.

Is the reviewer's nickname on the row?

The nickname and the avatar are on every review row as Google Play shows them publicly. They are personal data: process them under your own lawful basis.

Does it need a Google account or API key?

No. Everything is read from Google Play's public web pages, logged out.

Integration

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('hyperbach/google-play-reviews-scraper').call({"appIds": ["https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=US", "com.instagram.android"], "maxReviewsPerApp": 50});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Python

from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('hyperbach/google-play-reviews-scraper').call(run_input={'appIds': ['https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=US', 'com.instagram.android'], 'maxReviewsPerApp': 50})
items = client.dataset(run['defaultDatasetId']).list_items().items

CLI

$apify call hyperbach/google-play-reviews-scraper --input '{"appIds": ["https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=US", "com.instagram.android"], "maxReviewsPerApp": 50}'

REST

curl -X POST "https://api.apify.com/v2/acts/hyperbach~google-play-reviews-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' -d '{"appIds": ["https://play.google.com/store/apps/details?id=com.whatsapp&hl=en&gl=US", "com.instagram.android"], "maxReviewsPerApp": 50}'

Support

apify@hyperbach.com

This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.