# Google Play Reviews Scraper (`superslowsloth/google-play-reviews`) Actor

Scrape Google Play Store reviews for any Android app - rating, text, date, thumbs up, app version and the developer reply - plus the app store listing, in any country and language.

- **URL**: https://apify.com/superslowsloth/google-play-reviews.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** E-commerce, AI, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.07 / 1,000 review scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Play Reviews Scraper

Returns reviews for any app on the Google Play Store: star rating, review text,
date, thumbs-up count, the app version the reviewer was running, and the
developer's public reply. It also returns the app's own store listing - name,
developer, category, content rating, icon, aggregate score, rating count and
price - so a run tells you what the app is as well as what people said about it.

Give it an Android package name (`com.spotify.music`) or just paste a Play Store
URL. Several apps in one run is fine.

### Read this before you pay for a run

- **It walks, it does not jump.** Play serves reviews in pages behind a
  continuation token, and this actor follows that token until it runs out or
  `maxReviews` is reached. There is no page number you can skip to, here or in
  any other tool, because Play does not expose one.
- **A quiet app returns everything it has, which may be little.** `maxReviews`
  is a ceiling, not a promise. If Play stops handing out tokens, the run stops
  and the log says so.
- **The three sort orders return different reviews.** `newest`, `rating` and
  `helpfulness` each walk their own ordering. Running more than one collects
  more than any single one does.
- **The star filter narrows the pool.** Asking for 500 one-star reviews of an
  app with a few thousand reviews will return fewer than 500. That is the app,
  not the actor.
- **`country` and `language` do different jobs.** `country` (Play's `gl`) picks
  which store the listing is read from - price, availability. `language`
  (Play's `hl`) is what actually biases which reviews come back: `hl=ja`
  returned Japanese reviews for the same app that `hl=en` answered in English.
  Neither one is a hard filter on the reviewers' countries; Play does not offer
  one.
- **Residential proxy is required**, and it is the default. Google rate limits
  its reviews endpoint per exit address. No proxy country is pinned on purpose -
  pinning one narrows the address pool enough to start drawing 403s.

### Output

One record per review, `type` = `"review"`:

| Field | Notes |
|---|---|
| `id` | Google's review id. Used for de-duplication across pages. |
| `app_id` | The Android package name, e.g. `com.spotify.music`. |
| `app_name` | The app's display name, read from its store page. |
| `country` / `language` | The `gl` and `hl` the run asked for. |
| `rating` | 1-5. |
| `content` | The review text. Empty string when the reviewer left a star rating and no words, which is common. |
| `updated` | ISO 8601, UTC. |
| `author_name` | The reviewer's display name. |
| `author_image` | Avatar URL, or null. |
| `app_version` | The version the reviewer was running. **Often null** - Play only attaches it when the review came from a device that reported one. Null means "not recorded", never "version 0". |
| `vote_count` | Thumbs up. Genuinely `0` for most reviews. |
| `reply_content` / `reply_updated` / `reply_author` | The developer's reply, its date, and who signed it. All three are null together when there is no reply. |
| `review_url` | A link that opens this review on the store page. |

Plus one record per app, `type` = `"app"`, unless you turn `includeAppDetails`
off. **App rows are not charged for.**

| Field | Notes |
|---|---|
| `app_id`, `app_name`, `url` | The listing. |
| `description`, `developer`, `developer_url` | From Google's own schema.org markup. |
| `category` | Google's category slug, e.g. `MUSIC_AND_AUDIO`. |
| `content_rating`, `icon` | As shown on the store page. |
| `score` | The aggregate star rating, 1.0-5.0. Null on apps with too few ratings. |
| `ratings` | How many ratings that aggregate is over. This is larger than the review count - most raters leave no text. |
| `price`, `currency`, `free` | `price` is `0.0` and `free` is `true` for a free app. All three are null when the page carried no offer, which happens for apps not distributed in the requested country. |

#### Nulls are measurements

Nothing here is filled in with a zero to make a column look tidy. A null
`app_version` means Play did not record one; a null `score` means the app has
too few ratings for an aggregate. If you see `0`, Google sent `0`.

### Pairing it with the iOS side

The field names match the **App Store Reviews Scraper** wherever the two stores
mean the same thing - `id`, `app_id`, `app_name`, `country`, `content`,
`rating`, `author_name`, `app_version`, `updated`, `vote_count` - so you can run
both and union the rows to get one table across both platforms. Two differences
are real rather than cosmetic: `app_id` is a package name here and a number on
iOS, and Play reviews have no title, so there is no always-empty `title` column
pretending otherwise.

### Billing

- `actor-start`, once per run, charged only after your input parses. A run that
  fails on its own input costs nothing.
- `review-scraped`, once per review row. App rows are free, and a review that
  Play hands back twice mid-walk is charged once.

# Actor input Schema

## `apps` (type: `array`):

One entry per app. Each entry is either an Android package name (com.spotify.music) or any Play Store URL that carries ?id=, pasted straight from the browser. An app named twice in one list is scraped once.

## `country` (type: `string`):

Two-letter country code, lower case, for example us, gb, de, br, in, jp. This is Play's `gl` parameter. It selects the store the app page is read from - the price and availability shown - and it does not restrict which reviews come back: Play returns reviews from everywhere and the language filter is the one that narrows them.

## `language` (type: `string`):

Play's `hl` parameter, for example en, ja, pt-BR. It sets the language of the app listing text and biases which reviews Play serves toward that language. Measured 2026-08-25: hl=ja returned Japanese reviews for the same app that hl=en answered in English.

## `maxReviews` (type: `integer`):

Upper bound on reviews collected per app, across pages, after duplicates are removed. The walk follows Play's continuation token and stops early if Play runs out - a quiet app returns everything it has, well below this number.

## `sortBy` (type: `string`):

newest returns the most recent reviews first; rating walks from five stars down; helpfulness returns the ones Play ranks as most helpful. The three return visibly different sets, so running more than one collects more than any one of them does.

## `rating` (type: `string`):

Optional. Collect only reviews with exactly this many stars - 1 for the complaints, 5 for the praise. Leave on "Any rating" for every rating. Note that the filter narrows the pool, so a thin app with a 1-star filter can return only a handful.

## `includeAppDetails` (type: `boolean`):

On (default): emit one extra row per app, type "app", carrying the listing - name, developer, category, content rating, icon, aggregate score, rating count and price. It is not charged for. Off: reviews only. The app page is fetched either way, because it is where the app's display name comes from.

## `proxyConfiguration` (type: `object`):

Residential is required. Google rate limits the Play reviews RPC per exit address, and a datacenter block of addresses is refused far sooner than a residential one. No country is pinned on purpose: pinning the proxy country narrows the address pool enough to cause 403s, and the store country is already chosen by the country field above.

## Actor input object example

```json
{
  "apps": [
    "com.spotify.music"
  ],
  "country": "us",
  "language": "en",
  "maxReviews": 100,
  "sortBy": "newest",
  "rating": "",
  "includeAppDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `reviews` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "apps": [
        "com.spotify.music"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/google-play-reviews").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "apps": ["com.spotify.music"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/google-play-reviews").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "apps": [
    "com.spotify.music"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call superslowsloth/google-play-reviews --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/google-play-reviews"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/lBNKqc2MDrW6RnZz5/builds/UyuJk5J05z8DXcaYh/openapi.json
