Google Play Reviews Scraper | Android App Reviews
Pricing
from $0.05 / 1,000 review delivereds
Google Play Reviews Scraper | Android App Reviews
Scrape Google Play Store reviews by app, country and language. Export ratings, text, app versions and developer replies to JSON/CSV. Filter dates, stars and keywords for Android feedback monitoring.
Pricing
from $0.05 / 1,000 review delivereds
Rating
0.0
(0)
Developer
tingyou333 zhuang
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
12 hours ago
Last modified
Categories
Share
Ready-to-use example: Open the preconfigured workflow. Review or change the target before starting; runs use your own account credits.
Practical tutorial: How to export low-star Google Play reviews for release feedback.
Scrape Google Play Store reviews by app, country and language. Export ratings, text, app versions and developer replies to JSON/CSV. Filter dates, stars and keywords for Android feedback monitoring.
Useful for: Monitor Android release feedback; find low-star complaints; compare apps across countries and languages.
Why choose this Actor: Batch apps and locales, filter reviews and suppress duplicates. Supported input envelopes and output projections help migrate existing review workflows.
Try a small sample
- Click Try for free, then open Input and switch to JSON.
- Paste the example below and click Start. It uses a small result limit.
- Open the dataset to inspect results, then export JSON, CSV or Excel. Source restrictions can still cause partial or failed runs.
{"appIds": ["com.whatsapp"],"maxReviews": 20}
Cost at a glance
Primary billing unit: Review delivered. Rates below are per 1,000 primary events.
| Free plan | Starter / Bronze | Scale / Silver | Business / Gold and higher |
|---|---|---|---|
| $0.08 | $0.07 | $0.06 | $0.05 |
Platform compute, proxy, transfer and storage are additional. Other event types, where enabled, are listed in the Pricing tab. “Try for free” uses available account credits; it does not make usage unlimited or unmetered.
Coverage to know: The source controls available reviews and reply fields. Filters can require more requests than the number of reviews ultimately delivered.
For Apple App Store reviews, see our companion Actor. It runs and bills separately.
Guides and full reference
Workflows · Pricing details · Inputs · API · FAQ
Form prefills, schema defaults and empty API input can differ. Use explicit targets and limits; see the technical reference for source and default behavior.
Locale selection and detailed ratings
The Input form offers 52 country and 54 language suggestions, with separate multi-country and multi-language fields. Custom values remain available; the source determines which combinations return data. Country selects a storefront and language selects a review language, not automatic translation.
criterias preserves Google's available category ratings as { "criteria": "vaf_app_quality_ads_presence", "rating": 1 } objects. These category-specific ratings are separate from the overall 1–5 review score. Missing ratings are not fabricated; an empty list means no parsed category ratings were supplied. Malformed entries generate warnings while valid siblings are retained.
Common workflows
Compare two Android apps
{"appIds": ["com.whatsapp","org.telegram.messenger"],"maxReviews": 40}
Collect English and German locale results
{"appIds": ["com.whatsapp"],"languages": ["en","de"],"maxReviews": 40}
Keep reviews with developer replies
{"appIds": ["com.whatsapp"],"includeRepliesOnly": true,"maxReviews": 20}
Output at a glance
Illustrative field subset below; these are example values, not a captured customer review or a claim about source coverage. Native and compatibility output profiles can differ.
{"type": "review","appId": "com.whatsapp","reviewId": "example-review-id","content": "Example feedback used to illustrate the output format.","score": 4,"country": "us","language": "en","replyContent": null,"coverage": "complete","warnings": []}
Google Play review totals are not a promise of retrievable written reviews. Locale queries do not classify the actual language of each review. Pages, source access and your global cap can limit results. Replies and version fields may be null.
Pricing
Pay per delivered event, with automatic discounts based on your Apify subscription plan. These are result fees in USD, not separate subscriptions sold by this Actor. All tiers have the same Actor features. Apify compute, storage, transfers and any proxy usage are charged additionally.
| Billable event (1,000 events) | Free | Starter | Scale | Business |
|---|---|---|---|---|
| Review delivered | $0.08 | $0.07 | $0.06 | $0.05 |
Platinum and Diamond currently use the Business rate. The Pricing tab is the source of truth for the active schedule and your applicable plan.
- Review delivered: One delivered review after filtering and output mapping. Error rows have no result fee. Apify platform usage is additional.
Example on the Free plan: 10 / 1,000 / 10,000 events cost $0.0008 / $0.08 / $0.8 in result fees, plus platform usage.
There is no additional developer setup or monthly rental fee. A run with no billable results can still consume platform resources. Start small, cap results and review run costs before scheduling a larger workload. Requested counts are ceilings, not guaranteed deliveries.
Input reference
Fields below are grouped like the Input form. Optional fields need not be supplied. Compatibility input envelopes and transformations are explained in the technical reference.
Targets and collection
| Field | Type | Default | Meaning |
|---|---|---|---|
appIdOrUrl | string | Not set | Single-app compatibility input, e.g. com.whatsapp or a Play Store app URL. |
appIds | array | Not set | Multiple Google Play package IDs in one run. |
startUrls | array | Not set | Compatibility input containing Google Play app detail URLs. |
country | string | "US" | Google Play country code used by the review RPC, e.g. US, GB, KR. Select a suggested locale or enter a custom code. Locale selection does not detect the language of each review. |
countries | array | Not set | Optional multi-country extension. When supplied, each app is queried for each country and review IDs are deduplicated. |
language | string | "en" | Google Play query locale, e.g. en or de. all sweeps the documented fixed locale list in round-robin pages; maxReviews is a global cap, not per language. This does not classify review text language. Select a suggested locale or enter a custom code. Locale selection does not detect the language of each review. |
languages | array | Not set | Explicit query locales, or ["all"] for the fixed locale sweep. Queried round-robin; unvisited sources are reported when the global limit is reached. |
deviceType | string | "mobile" | Google Play device review context. |
keywords | array | Not set | Return reviews containing at least one keyword, case-insensitive. |
appVersion | array | Not set | Optional exact app-version allow-list. |
since | string | Not set | ISO date/timestamp for scheduled incremental monitoring. |
recentDays | integer | 0 | Return reviews from the most recent N days; 0 disables this filter. |
startPage | integer | 1 | Compatibility page offset. Earlier pages are fetched only to obtain Google's continuation token, then discarded. |
pagesToScrape | integer | -1 | Maximum RPC pages per app/country after startPage. -1 means continue until maxReviews/maxItems or source exhaustion. |
reviewsPerPage | integer | 100 | Requested reviews per Google Play RPC call. |
requestDelayMillis | integer | 0 | Optional delay before each RPC attempt. |
until | string | Not set | theagents-compatible LOWER date bound: returns reviews newer than this date. Combined with since using the later bound. Use endDate for an upper bound. |
neatratInput | object | Not set | Explicit Neatrat migration: paste the original input object here. Do not combine with native fields (unchanged platform defaults are ignored). outputSchema remains top-level and independent. Preserves language arrays and defaults mostRelevant / 5 pages / 10000 reviews. Missing language uses en query locale; text-language filter equivalence is unproven. |
wolvesInput | object | Not set | Explicit thewolves migration: paste the original input object here. Do not combine with native fields (unchanged platform defaults are ignored). outputSchema remains top-level and independent. Requires explicit positive maxItems: competitor has UI prefill only, no documented API default. No explicit page limit; native safety bounds apply. |
theagentsInput | object | Not set | Explicit theagents migration: paste the original input object here. Do not combine with native fields (unchanged platform defaults are ignored). outputSchema remains top-level and independent. Requires explicit positive maxItems: competitor has UI prefill only, no documented API default. No explicit page limit; native safety bounds apply. |
Filters and ordering
| Field | Type | Default | Meaning |
|---|---|---|---|
sort | string | "NEWEST" | Compatibility sort: NEWEST, RATING or HELPFULNESS/MOST_RELEVANT. |
sortBy | string | Not set | Alternative compatibility sort used by another major Actor. |
rating | integer | Not set | Return reviews with exactly one star rating from 1 to 5. |
ratingFilter | array | Not set | Return only reviews whose score is in this 1-5 allow-list. Numeric arrays such as [1,2] are supported for migration compatibility. |
endDate | string | Not set | Compatibility upper date bound in YYYY-MM-DD or ISO format. |
includeRepliesOnly | boolean | false | Return only reviews that have a developer reply. |
uniqueOnly | boolean | true | Deduplicate by reviewId across pages/apps/countries. |
ratings | array | Not set | Additional allowed ratings, merged with ratingFilter. |
Result limits and cost
| Field | Type | Default | Meaning |
|---|---|---|---|
maxReviews | integer | Not set | Compatibility maximum number of saved reviews across the run. -1 uses maxItems or the safety ceiling. Defaults to 1000 only when neither limit is supplied. |
maxItems | integer | Not set | Alternative compatibility maximum. When supplied with maxReviews, the lower positive limit wins. |
maxRequestRetries | integer | 2 | Retries transient HTTP/rate-limit/network failures. |
Compatibility and transformations
| Field | Type | Default | Meaning |
|---|---|---|---|
customMapFunction | string | Not set | JavaScript function applied after output formatting to each review. Must return one JSON object. Isolated runtime with no network, file system or Python access; 50ms CPU and 16MB per row, 10s total. Not a filter. |
outputSchema | string | "extended" | Explicit migration format. Missing source values stay null; extended preserves diagnostics. |
Connection and advanced settings
| Field | Type | Default | Meaning |
|---|---|---|---|
proxyConfiguration | object | Not set | Accepted for migration compatibility. The validated public RPC path does not require or use a proxy. |
Output reference
The table describes native fields; fields can be absent or null when the source does not provide them. Error rows and selected compatibility profiles have different shapes. Nested objects remain structured in JSON; CSV exports may serialize them.
| Field | Type | Meaning |
|---|---|---|
type | string | Type |
appId | string | App ID |
reviewId | string | Review ID |
id | ['string', 'null'] | Compatibility review ID |
userName | ['string', 'null'] | User |
userImage | ['string', 'null'] | User image |
content | ['string', 'null'] | Review |
text | ['string', 'null'] | Compatibility review text |
score | ['integer', 'null'] | Score |
scoreText | ['string', 'null'] | Compatibility score text |
thumbsUpCount | ['integer', 'null'] | Helpful votes |
thumbsUp | ['integer', 'null'] | Compatibility helpful votes |
reviewCreatedVersion | ['string', 'null'] | Review app version |
at | ['string', 'null'] | Review date |
date | ['string', 'null'] | Compatibility review date |
replyContent | ['string', 'null'] | Developer reply |
replyText | ['string', 'null'] | Compatibility developer reply |
repliedAt | ['string', 'null'] | Reply date |
replyDate | ['string', 'null'] | Compatibility reply date |
appVersion | ['string', 'null'] | App version |
version | ['string', 'null'] | Compatibility app version |
url | ['string', 'null'] | Review URL |
inputSource | ['string', 'null'] | Compatibility input source |
country | string | Country |
language | string | Language |
sort | string | Sort |
deviceType | string | Device |
sourceUrl | string | Source URL |
coverage | string | Coverage |
retrievalMethod | string | Retrieval method |
warnings | array | Warnings |
scrapedAt | string | Scraped at |
errorCode | string | Error code |
message | string | Message |
API and automation
The API tab provides snippets for this Actor. For scheduled or larger collections, start a run asynchronously and poll its status instead of holding a synchronous request open. Keep your API token in an environment variable.
import os, time, requestsbase = "https://api.apify.com/v2"headers = {"Authorization": "Bearer " + os.environ["APIFY_TOKEN"]}actor_input = {'appIds': ['com.whatsapp'], 'maxReviews': 20}response = requests.post(base + "/acts/YaQpO5GGTRCoNPtD7/runs",headers=headers, json=actor_input, timeout=30,)response.raise_for_status()run = response.json()["data"]for _ in range(720):if run["status"] not in ("READY", "RUNNING", "TIMING-OUT", "ABORTING"):breaktime.sleep(5)response = requests.get(base + "/actor-runs/" + run["id"], headers=headers, timeout=30)response.raise_for_status()run = response.json()["data"]else:raise TimeoutError("Polling ended; inspect the existing run before starting another.")if run["status"] != "SUCCEEDED":raise RuntimeError(run.get("statusMessage", run["status"]))response = requests.get(base + "/datasets/" + run["defaultDatasetId"] + "/items",headers=headers, params={"format": "json", "limit": 1000, "offset": 0}, timeout=30,)response.raise_for_status()rows = response.json()print(rows) # Paginate with offset for larger datasets; inspect per-row coverage.
Scheduled monitoring and integrations
- Save a working input as an Apify Task.
- Attach a Schedule in your timezone; keep runs sharing an incremental state key sequential.
- Add a successful-run webhook or connect your downstream workflow to the dataset export/API.
- Inspect missing/partial data before sending alerts or treating absence as removal.
Use the platform Integrations/API options to connect external workflows such as Make, n8n or a data warehouse. An external sentiment or summarization step is separate from this Actor and may have its own charges. The platform also supports Actor tools through Apify MCP; availability and client setup depend on your integration.
FAQ
Where is the package name?
Copy the id parameter from the Google Play URL; for example, id=com.whatsapp.
Why are fewer reviews returned than the store rating count?
A rating count can include ratings without written reviews, and source pagination, locales and filters change the retrievable subset.
Can I reuse an existing integration?
Select the matching input envelope and outputSchema. Compatibility covers the documented fields; it does not promise identical source ordering or availability.
Can I export without writing code?
Yes. Run from the Input form, open the dataset and use the export controls for JSON or CSV. Select your preferred output profile before running when migrating an integration.
Does a successful run guarantee every field?
No. Inspect coverage, warnings and source-specific status fields. Optional enrichment may be missing even when usable rows were delivered.
Troubleshooting
| Symptom | What to check |
|---|---|
| Empty dataset | Validate the target, source availability and filters; try the small quick-start input. |
| Fewer rows than requested | Check source limits, pagination and filtering. Increasing a cap cannot create unavailable source records. |
| Partial fields | Inspect coverage/warnings and the relevant source or enrichment status. |
| Access or throttling errors | Check the run log and documented proxy configuration; retry at a lower request volume. |
| Migration mismatch | Check the explicit input/output profile and technical field mapping below. |
| Unexpected bill | Separate result events from platform resources; inspect enrichment, result caps and the Pricing tab. |
Technical reference
Migration compatibility
The Actor accepts the common input families used by leading Google Play review Actors:
appIdOrUrl,deviceType,sortBy,rating,startPage,pagesToScrape,reviewsPerPage,maxReviews,ratingFilter,keywords,endDate,recentDays,uniqueOnly,appVersionappIds,country,language,sort,startUrls,maxItems,customMapFunction
customMapFunction executes an isolated JavaScript function on each output row.
One schema-level migration difference is explicit: one tracked competitor defines language as an array while another defines the same key as a string. Apify validates a field as one type, so this Actor preserves the string-shaped language contract and adds languages for array-shaped multi-locale workflows. For native workflows, rename language to languages. For competitor defaults as well as original array keys, use the explicit envelope below; numeric ratingFilter arrays are preserved.
Extensions
- Multiple app IDs and countries in one run
- Multiple languages through
languages sincefor scheduled incremental review monitoring- Developer-reply-only filtering
- Explicit RPC request/retry/source diagnostics
- Stable structured output with source locale and coverage metadata
Output
Review rows include review ID, user name/image, text, score, helpful votes, app version, timestamp, developer reply/reply timestamp, app/country/language and source telemetry.
For drop-in migration from the major appIds/startUrls competitor family, rows also expose compatibility aliases such as id, text, date, replyText, replyDate, version, thumbsUp, scoreText, url, inputSource and criterias alongside the canonical fields.
Source boundary
The validated path uses Google Play's public oCPfdb review RPC. It requires no account or private endpoint. Source behavior can change, so the Actor reports source failures and retry counts explicitly.
Date and output compatibility
theagents until is a LOWER date bound (reviews newer than that date), combined with since using the later bound. endDate remains the upper bound. recent/top alias newest/mostRelevant; ratings merges with ratingFilter. Neatrat output date is date-only and has different rating/reviewer/body/position fields: select outputSchema=neatrat for its field layout. Use languages for Neatrat language-array migration through the input form; language remains a string in the schema. language=all now expands to the fixed query-locale list documented below.
Output profiles and custom JavaScript
The default outputSchema=extended preserves the existing output. Google Play supports wolves, theagents and neatrat. These are explicit field projections, not a guarantee of identical source pagination or data availability. Missing source fields remain null.
customMapFunction runs after output projection and before delivery. Example: (row) => ({...row, exported: true}). It must synchronously return one JSON object per row. Async functions, filtering and non-object results fail the run before delivery. Each row has 50 ms CPU, 16 MB memory and 256 KB stack limits; total mapping budget is 10 seconds. The interpreter has no network, filesystem or host callbacks.
Multiple locales and bounded coverage
Use language: "all" or languages: ["all"] to query these fixed locales: en de fr es it pt-BR pt-PT ja ko zh-CN zh-TW zh-HK af am bg ca hr cs da el en-GB es-419 et fi fil fr-CA he hi hu is id lt lv ms nl no pl ro ru sk sl sr sv sw th tr uk zu vi. This sweeps query locales, not all review text languages or historical reviews. Explicit languages: ["en", "de"] remains supported. Sources are scheduled one page at a time in round-robin order; output is source-page order, not a globally sorted merge. maxReviews remains global. A small cap can stop before later sources are visited. SOURCE_DIAGNOSTICS records all sources including unvisited ones, pages, accepted rows and stop reason. Repeated cursors terminate with limited coverage. Source locale does not classify actual text language.
The fixed locale list is based on Google's published locale table (https://support.google.com/googleplay/android-developer/table/4419860?hl=en-GB); this table does not prove that each review endpoint returns distinct data for every locale. Refer to the run diagnostics for actual coverage.
Explicit input migration
Keep existing native calls unchanged. Native defaults remain NEWEST, pagesToScrape=-1, maxReviews=1000 (when neither quantity limit is supplied). Input profiles are independent of outputSchema, which remains extended unless selected explicitly.
For Neatrat, replace the entire input JSON with one wrapper around the original object. No language key rename or manual default copying is needed:
{"neatratInput":{"appIdOrUrl":"com.whatsapp","language":["en","de"]}}
In the form, paste the original object into Neatrat original input and clear unrelated native fields, including any prefilled appIds. Using the JSON tab and replacing the whole document is the shortest reliable migration. Do not submit the old language array at the top level: that field deliberately remains a string.
| Entry | Sort when omitted | Pages when omitted | Quantity when omitted |
|---|---|---|---|
| Native (no envelope) | NEWEST | -1 | 1000 unless maxItems supplied |
| neatratInput | mostRelevant / HELPFULNESS | 5 | 10000 |
| wolvesInput | NEWEST | no explicit page limit, native ceiling applies | Must provide positive maxItems |
| theagentsInput | NEWEST | no explicit page limit, native ceiling applies | Must provide positive maxItems |
The last two declared competitor schemas supply only prefill:1000, not a maxItems default. Their omitted API quantity behavior is unproven. Add maxItems only if the original input omitted it, then wrap:
{"wolvesInput":{"appIds":["com.whatsapp"],"maxItems":1000},"outputSchema":"wolves"}
{"theagentsInput":{"appIds":["com.whatsapp"],"maxItems":1000,"until":"2026-09-01"},"outputSchema":"theagents"}
Only one envelope is allowed. Inside it, use that competitor's fields, types and enum values; unknown or cross-profile fields fail as INVALID_INPUT before fetching. Explicit nested settings win over that profile's defaults. Native extension workflows should continue using the native entry. customMapFunction inside wolvesInput/theagentsInput still executes after the explicitly selected output projection.
Top-level native fields matching the existing Schema defaults are ignored in envelope mode because Apify injects them automatically; this is also reported in OUTPUT.warnings. Other top-level native fields fail rather than merge. Even an explicitly supplied top-level value identical to a default cannot override an envelope: put settings inside the envelope. outputSchema is the sole independent top-level control. OUTPUT.inputProfile and OUTPUT.resolvedInput show the selected profile and resolved sort/page/quantity controls for inspection.
Limits remain explicit: -1 is bounded by 100000 reviews and 10000 pages per query source; maxReviews/maxItems is global. Neatrat language arrays route query locales, not a proven equivalent of its described text-language filter. Empty/omitted Neatrat language uses en as this implementation's query fallback, not a verified competitor default. Page offsets and page limits are per source; raw page sizes, locale coverage, position semantics and cross-source global ordering are not guaranteed equal to competitors. The other actors' omitted page behavior is not proven by their schemas; this entry uses the documented native bounded traversal.
Support
Open an issue from this Actor’s Issues tab with the run ID, expected result and a redacted input. Do not include tokens, cookies or private credentials. Include the output profile and affected field when reporting a migration mismatch.
Presentation update
The current listing adds workflow examples, grouped input documentation, output-field explanations and plan-based result discounts. Source-specific limitations above still apply. This is an independent tool and is not affiliated with the source platform.
How to export low-star Google Play reviews for release feedback
Reading every app review manually is difficult. A small filtered export can help a product team inspect recent complaints before deciding whether a larger analysis is useful.
Disclosure: I maintain the paid Apify Actor in this tutorial. This is a documented workflow for my own product. Available account credits may cover a trial, but collection is metered.
Configure one app and one locale
Open the Actor, go to Input and choose JSON. This example requests up to five one- or two-star reviews from WhatsApp's US/English feed:
{"appIds": ["com.whatsapp"],"country": "us","language": "en","ratingFilter": [1,2],"maxReviews": 5}
The package name is the id value in a Google Play app URL. Replace com.whatsapp with your target. Country selects the source locale; language is a collection setting, not automatic translation. Keep these explicit for a reproducible comparison.
Inspect the result before drawing conclusions
After the run finishes, open the dataset and confirm that returned scores are one or two. Export CSV for manual triage or JSON for an analysis pipeline. Retain review IDs, timestamps, app version where available, text and developer replies rather than reducing the output to an average score.
A useful manual worksheet separates the review's actual statement, your proposed issue category, and your confidence. A complaint is not proof of a confirmed bug; missing app versions and replies should remain unknown. Don't classify sentiment or assign root causes as if the scraper had verified them.
Verification and limitations
A September 11, 2026 owner cloud sample returned five reviews for this configuration. It is a small functional check, not proof of comprehensive coverage or customer adoption. Source data changes, and filtering can require more requests than the number of results ultimately delivered.
The verified Free-plan result fee is $0.08 per 1,000 reviews: five results correspond to $0.0004 before platform compute, storage, transfer and proxy usage. Refer to the live Pricing tab for your applicable plan. A zero-result run can still use platform resources.
Low-star feedback is deliberately biased. It is useful for finding possible problems, but cannot establish the percentage of users experiencing them. For broader research, compare it with an unfiltered sample using the same date and locale settings. For recurring exports, use explicit date boundaries and deduplicate review identities downstream.
Try it
Open the Google Play review exporter. Start with five rows, inspect the original text and only then expand the scope. Report reproducible issues through the Actor's Issues tab without including credentials.