# Google Play Review Intelligence (`skootle/google-play-review-intelligence`) Actor

Google Play reviews across many languages in one run, with rating by app version, release regression flags, per locale sentiment, complaint themes, developer reply rate and joined app metadata. Export normalized records, use the API, schedule monitoring, or connect integrations and agent workflows.

- **URL**: https://apify.com/skootle/google-play-review-intelligence.md
- **Developed by:** [Skootle](https://apify.com/skootle) (community)
- **Categories:** AI, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 google play review intelligence records

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/platform/actors/running/actors-in-store#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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

<!-- skootle:growth-loop-hook -->
**Google Play Review Intelligence pulls public Google Play reviews for the apps you name, across many languages in one run, and turns them into release-regression signals, complaint themes and per-locale sentiment.** It is built for app teams tracking a release, competitor analysts watching a rival's ratings slide, support leads mining complaints, and AI agents that need clean structured rows instead of scraped text. Three ways to run it: paste one package name and press Start, add five languages and watch coverage multiply, or schedule it daily and diff the summaries.

![Google Play Review Intelligence](https://raw.githubusercontent.com/kesjam/skootle-actors-assets/main/heroes/google-play-review-intelligence.png)

### TL;DR

You give it Android package names such as `com.duolingo`. You get back:

- **`REVIEW` rows**, one per unique review, with `reviewId`, `appId`, `locale`, `language`, `country`, `rating`, `sentiment`, `body`, `bodyLength`, `reviewedAt` (ISO 8601), `reviewedAtEpochMs`, `authorName`, `authorAvatarUrl`, `thumbsUpCount`, `appVersion`, `appVersionMajor`, `hasDeveloperReply`, `developerReplyBody`, `developerReplyAt`, `themes`, `fieldCompletenessScore` and `agentMarkdown`.
- **One `APP_SUMMARY` per app**, with `ratingDistribution`, `meanRating`, `medianRating`, `negativeSharePct`, `developerReplyRatePct`, `versionBreakdown`, `versionRegression`, `localeBreakdown`, `distinctVersionsAcrossLocales`, `versionRolloutSplit`, `topComplaintThemes`, `duplicateSuppressedCount`, plus joined store metadata: `appTitle`, `developer`, `storeRating`, `storeRatingCount`, `genre`, `priceText`.
- **One run `SUMMARY`** with provenance, per-locale status and the apps whose latest release was flagged as a regression.
- **One `AGENT_BRIEFING`** record, and the same briefing as `AGENT_BRIEFING.md` in the key-value store.

The pain it kills: you export 500 English reviews, see a 3.8 average, and have no idea that your Portuguese users rate you 4.8, that half your install base is still on last week's build, or that the drop you are staring at started with a specific version number.

<!-- skootle:review-cta -->
If this Actor earns its keep, a short review helps other buyers find it: [leave a review](https://apify.com/skootle/google-play-review-intelligence/reviews).

### What does Google Play Review Intelligence do?

It calls the public Google Play review listing for each app you name, once per locale you request, deduplicates every review by its Google review ID so you are never billed twice for the same row, normalizes each review into a stable versioned schema, and then computes the intelligence layer on top: rating by app version, release-over-release deltas, complaint themes, developer reply coverage, and how all of that differs by language.

Every run also joins the app's own store page so the summary carries `appTitle`, `developer`, lifetime `storeRating`, `storeRatingCount`, `genre` and price alongside the reviews you just collected. That lets you compare lifetime reputation against what people are saying this week.

### Why does language matter more than country on Google Play?

This is the finding that shaped the Actor, and it is worth stating plainly because it changes what you should ask for.

On Google Play, changing the **country** parameter alone returns the same review set. Changing the **language** returns a completely different one. We verified this against live Google Play on 21 July 2026 using `com.spotify.music`, 30 reviews per call:

| Locale requested | Unique review IDs | Overlap with `en-us` |
|---|---|---|
| `en-us` | 30 | 30 of 30 |
| `en-gb` | 30 | 30 of 30 |
| `en-de` | 30 | 30 of 30 |
| `de-de` | 30 | 0 of 30 |
| `fr-fr` | 30 | 0 of 30 |
| `es-es` | 30 | 0 of 30 |
| `ja-jp` | 30 | 0 of 30 |
| `pt-br` | 30 | 0 of 30 |

Union across those eight locales: **180 unique reviews, against 30 from a single locale**. Country-only variation added nothing. Language variation added everything.

That is why this Actor takes a `languages` array as its primary coverage control, and why it deduplicates globally per app. A tool that looped over countries and pushed every row would hand you the same 30 reviews six times and charge you for 180.

### How much more coverage do I actually get?

From the verification runs behind this listing, one app at 40 reviews per locale:

| Request | Unique reviews returned | Duplicates suppressed |
|---|---|---|
| 1 language (`en`) | 40 | 0 |
| 5 languages (`en`, `es`, `de`, `pt`, `fr`) | 200 | 0 |

Five times the reviews, one run, one start fee, zero duplicate rows.

### Worked example: Duolingo across five languages

Real output from a verification run on 21 July 2026, input `{"appIds":["com.duolingo"],"languages":["en","es","de","pt","fr"],"countries":["us"],"maxReviewsPerLocale":40}`.

#### The per-locale breakdown from `APP_SUMMARY.localeBreakdown`

| Locale | Unique reviews | Mean rating | Negative share | Most common version |
|---|---|---|---|---|
| `en-us` | 40 | 3.75 | 27.5% | 6.87.6 |
| `es-us` | 40 | 4.40 | 12.5% | 6.86.5 |
| `de-us` | 40 | 4.08 | 17.5% | 6.86.5 |
| `pt-us` | 40 | 4.80 | 0.0% | 6.86.5 |
| `fr-us` | 40 | 4.33 | 15.0% | 6.86.5 |

An English-only export would have told you the app sits at 3.75 with 27.5% negative reviews. Across five languages the real picture is a 4.27 mean, and the Portuguese-speaking cohort had **zero** negative reviews in the window. Same app, same day, completely different conclusion about where the problem is.

#### The release regression from `APP_SUMMARY.versionRegression`

```json
{
  "latestVersion": "6.88.2",
  "latestVersionMeanRating": 3.56,
  "previousVersion": "6.87.6",
  "previousVersionMeanRating": 4,
  "meanRatingDelta": -0.44,
  "regressionFlag": true,
  "comparable": true,
  "note": "Compared across versions with at least three reviews in this run."
}
````

Version 6.88.2 is landing 0.44 stars below 6.87.6. `regressionFlag` turns true at a drop of 0.3 stars or worse, comparing versions that have at least three reviews in the run, so a single angry reviewer cannot trip it.

#### The rollout split

```json
{ "distinctVersionsAcrossLocales": 2, "versionRolloutSplit": true }
```

The `en-us` cohort was on 6.87.6 while every other locale was still on 6.86.5. Staged rollouts mean your language cohorts are literally reviewing different software. If you only pull one locale you cannot see this at all.

#### Lifetime versus current

```json
{ "appTitle": "Duolingo: Language Lessons", "developer": "Duolingo",
  "storeRating": 4.728, "storeRatingCount": 47248051, "genre": "EDUCATION" }
```

Lifetime store rating 4.728 from 47.2 million ratings, against 4.27 in the 200 reviews collected this run. The gap between the badge on the listing and what people are writing right now is exactly the number product managers get asked about.

#### Proof artifact

![Verified run output](https://raw.githubusercontent.com/kesjam/skootle-actors-assets/main/heroes/google-play-review-intelligence-proof.png)

Every number in the tables above is rendered from the same verification run, so you can check the listing against the output rather than taking the copy on trust.

#### A single `REVIEW` row

```json
{
  "recordType": "REVIEW",
  "appId": "com.duolingo",
  "locale": "en-us",
  "rating": 1,
  "sentiment": "negative",
  "reviewedAt": "2026-07-20T11:24:59.000Z",
  "thumbsUpCount": 1,
  "themes": ["ads_and_monetization"],
  "hasDeveloperReply": false,
  "fieldCompletenessScore": 83,
  "body": "\"free\" app (you can do barely anything without paying absurd amounts in subscriptions). filled with ads. now using ai slop courses. avoid"
}
```

`fieldCompletenessScore` is 83 rather than 100 because this reviewer's client did not report an `appVersion`. The Actor tells you that instead of hiding it.

#### Complaint themes from `topComplaintThemes`

```json
[
  { "theme": "ads_and_monetization", "count": 2, "sharePctOfNegative": 6.9 },
  { "theme": "support_and_service", "count": 1, "sharePctOfNegative": 3.4 },
  { "theme": "notifications", "count": 1, "sharePctOfNegative": 3.4 }
]
```

Themes are matched over negative reviews only, using published deterministic keyword rules, not a language model. The same input produces the same labels every time, which matters if you are diffing runs on a schedule.

### Worked example: Spotify, one app, five languages

Input `{"appIds":["com.spotify.music"],"languages":["en","es","de","pt","fr"],"countries":["us"],"maxReviewsPerLocale":40}` returned 200 unique reviews and 0 duplicates, with `Spotify: Music and Podcasts`, developer `Spotify AB`, lifetime rating 4.339 across 35,972,075 ratings, category `MUSIC_AND_AUDIO`. The largest version cohort in the window was `9.1.64.1676` at a 3.96 mean and 21.7% negative share.

### Worked example: two apps in one run

The prefilled demo input runs `com.spotify.music` and `com.duolingo` together across five languages. It returns **404 dataset items**: 400 unique reviews, 2 `APP_SUMMARY` records, 1 run `SUMMARY`, 1 `AGENT_BRIEFING`. Mean field completeness across the review rows was 99%. Three consecutive cloud runs on this exact input returned 404 items every time.

### Worked example: a query that is genuinely empty

Input `{"appIds":["com.skootle.no.such.package.exists"],"languages":["en"],"countries":["us"],"expectedNoMatch":true}` returns 3 items: an `APP_SUMMARY` with `sourceStatus: "no_match"`, a run `SUMMARY` with the same status, and the briefing. No invented rows, no silent success.

Run the same input **without** `expectedNoMatch` and the Actor fails on purpose, with this message:

> Google Play returned zero reviews for every requested app and storefront. Set expectedNoMatch to true if this query is genuinely expected to be empty.

and writes `DEBUG_ZERO_PARSE.json` to the key-value store. An empty dataset that you did not ask for is a bug, not a result.

### How is this different from a plain Google Play reviews scraper?

| Dimension | This Actor | Typical Google Play review scraper |
|---|---|---|
| Coverage axis | `languages` array, many locales per run, deduplicated globally | one country and one language per run |
| Duplicate billing | `duplicateSuppressedCount` reported, duplicates never pushed | no dedupe across locale loops |
| Release intelligence | `versionBreakdown`, `versionRegression`, `regressionFlag` | raw `appVersion` string only |
| Locale intelligence | per-locale mean, negative share and modal version | none |
| App metadata | joined `storeRating`, `storeRatingCount`, `developer`, `genre` | not joined |
| Themes | deterministic keyword clusters over negative reviews | none |
| Empty results | fails closed with saved evidence unless you declare `expectedNoMatch` | silent empty dataset |
| Agent output | `agentMarkdown` per row, `AGENT_BRIEFING.md` per run | raw JSON |

This is a comparison of shipped features, read from public input schemas and output on 21 July 2026. Competitors change; check their listings before you decide.

Where a plain scraper is the better buy: if all you need is a large volume of English-language review text at the lowest possible unit price, a raw extractor will be cheaper per row than this Actor. This one is priced for the intelligence layer, not for bulk text.

### Tutorial: your first three runs

1. **Baseline.** Paste one package name into `appIds`, leave `languages` at `["en"]`, set `maxReviewsPerLocale` to 40, press Start. Look at the `APP_SUMMARY` row. Note `meanRating` and `negativeSharePct`.
2. **Multiply coverage.** Add `es`, `de`, `pt`, `fr` to `languages` and run again. Compare `localeBreakdown`. If the per-locale means differ by more than half a star, your single-language baseline was misleading you.
3. **Watch a release.** Set `sortBy` to `newest`, schedule the Actor daily, and read `versionRegression.regressionFlag` from each run. When it flips true, the `versionBreakdown` row for that version tells you the review count and negative share behind it.

To pull complaints only, set `maxRating` to 2. To audit one specific build, put its exact version string into `appVersions`.

### Input

```json
{
  "appIds": ["com.spotify.music", "com.duolingo"],
  "languages": ["en", "es", "de", "pt", "fr"],
  "countries": ["us"],
  "sortBy": "newest",
  "maxReviewsPerLocale": 40,
  "includeAppDetails": true,
  "expectedNoMatch": false
}
```

`appIds` accepts either a package name or a full Google Play URL; the package name is extracted for you. `languages` multiplied by `countries` is capped at 40 locale pairs per run. Optional `minRating`, `maxRating` and `appVersions` filter the rows that reach your dataset.

### Output

Every record carries `schemaVersion`, `recordType`, `retrievedAt`, `queryFingerprint`, `sourceUrl` and `fieldCompletenessScore`, so you can diff two runs and know exactly which query produced which rows. Dates are ISO 8601 with numeric epoch mirrors. Ratings and counts ship as numbers, not strings.

The dataset has three prepared views: **Reviews and review intelligence** (everything), **Review rows** (just `REVIEW`), and **Per app intelligence** (just `APP_SUMMARY`).

### API, scheduling, monitoring and integrations

This Actor runs on the standard Apify platform, so everything platform-level works out of the box:

- **API:** start runs and pull the dataset over the Apify REST API or any Apify client library. Results are also exposed as JSON, CSV, Excel and RSS through the dataset endpoints.
- **Scheduling:** run it nightly or hourly from the Schedules tab. Scheduled runs are what make `versionRegression` useful, because you get a time series instead of a snapshot.
- **Monitoring:** point Apify monitoring at the run and alert on failures. The Actor fails closed on unexpected empties, so a monitoring alert means something real changed at the source.
- **Integrations:** push results to Google Sheets, Slack, Zapier, Make, webhooks, or your own endpoint using the standard Apify integrations.
- **Agents:** every row carries `agentMarkdown`, and each run writes `AGENT_BRIEFING.md`, so you can hand a run straight to an LLM without writing a formatter.

### Pricing

Pay per event. **$0.01 per run start, $0.0015 per dataset item, which is $1.50 per 1,000 records.** Usage is not passed through to you, so the price you see is the price you pay. Each run is capped at $5.

A dataset item is any record: a review row, an app summary, the run summary, or the briefing. The prefilled demo input produces 404 items, which costs $0.01 + $0.61, about **$0.62 per run**.

Two things that make this cheaper than it looks. Duplicate reviews are removed before they are pushed, so multi-language runs never bill you twice for the same row. And filters are applied before records reach the dataset, so `maxRating: 2` collects the same pages but only bills you for the complaints you asked for.

This Actor is priced above the cheapest bulk review extractors on the Store and below several mid-market ones. If your job is bulk English text at minimum unit cost, buy a raw extractor. If your job is knowing which release broke and for whom, this is the cheaper answer.

### Frequently asked questions

**Do I need a Google account, an API key, or a proxy?**
No. This Actor reads public Google Play listing data over plain HTTP. There is no login, no key to supply, and no proxy configuration to pay for.

**How many reviews can I get for one app?**
Google Play exposes a rolling window of public reviews per locale, not the full lifetime history. In practice you get up to `maxReviewsPerLocale` per locale, and the ceiling is set by Google, not by this Actor. Adding languages is the reliable way to increase unique coverage; the verification runs above show 5x from five languages.

**Why do two locales sometimes return the same review?**
Occasionally they do overlap. When that happens the review is pushed once and counted in `duplicateSuppressedCount`, so you can see exactly how much overlap there was and you are only billed for the unique row.

**What exactly triggers `regressionFlag`?**
The two most recent app versions that each have at least three reviews in the run are compared by mean rating. A drop of 0.3 stars or more sets the flag. If there are not two comparable versions, `comparable` is false and the flag is null rather than false, so you can tell "no regression" apart from "could not tell".

**Are the complaint themes generated by AI?**
No. They are matched with published deterministic keyword rules over negative reviews only. Two runs on the same reviews always produce the same labels. That is a deliberate choice so that scheduled diffs are meaningful.

**What happens if Google changes the response format?**
The Actor fails the run and writes `DEBUG_ZERO_PARSE.json` with the stage, the URL, the HTTP status and a response snippet. It does not return a partial or empty dataset and pretend it worked. If you see a failure, that file tells you and us what changed.

**Can I get reviews for an app that is not published in the US?**
Yes. Set `countries` to the storefront you want. Bear in mind the verification above: country changes little on its own, so pair it with the languages spoken in that market.

**Can I use this for competitor apps?**
Yes. All of the data is the public review content Google Play shows to any visitor. Put several package names in `appIds` and compare the `APP_SUMMARY` rows side by side.

### Is scraping Google Play reviews legal?

This Actor collects only publicly visible review content from Google Play listing pages, the same content any visitor sees without logging in. It does not access private data, does not log in, does not bypass authentication, and collects no data behind a paywall.

Review text is written by users and may be subject to their rights; reviewer display names and avatar URLs are personal data under GDPR, CCPA and similar regimes. You are the controller of anything you collect. Have a lawful basis, honour deletion requests, and do not republish reviewer identities without a reason you can defend. If you are doing anything beyond internal analysis, take your own legal advice.

Skootle is not affiliated with, endorsed by, or sponsored by Google LLC. Google Play is a trademark of Google LLC.

### Related Skootle Actors

- **[App Store Reviews](https://apify.com/skootle/app-store-reviews)** for the Apple side of the same question. Run both to compare how iOS and Android users receive the same release.
- **[Google Trends Intelligence](https://apify.com/skootle/google-trends-intelligence)** to check whether a ratings move lines up with a change in search demand.
- **[Website SEO Audit Intelligence](https://apify.com/skootle/website-seo-audit-intelligence)** and **[Website Tech Stack Intelligence](https://apify.com/skootle/website-tech-stack-intelligence)** for the marketing surface behind the app.

### Your feedback

Found a bug, hit a source change, or need a field this Actor does not emit yet? Open an issue on the Actor's **Issues** tab. That is the fastest route to a fix and it keeps the conversation attached to the run that showed the problem.

If it worked, a rating helps other buyers judge whether it fits their job: [leave a review](https://apify.com/skootle/google-play-review-intelligence/reviews).

# Actor input Schema

## `appIds` (type: `array`):

One to ten Android package names such as com.spotify.music, or full Google Play app URLs. The package name is pulled out of a URL automatically.

## `languages` (type: `array`):

Google Play returns a different set of public reviews for every language. Listing several languages here is what multiplies your coverage: five languages returned five times the unique reviews of one language in our verification runs. Duplicates are removed before you are billed.

## `countries` (type: `array`):

Two-letter country codes. Countries are collected alongside languages and every review is labelled with the locale it came from. Country alone changes little on Google Play, language is the axis that matters.

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

Newest first is the right choice for release monitoring and regression detection.

## `maxReviewsPerLocale` (type: `integer`):

Upper bound per app and locale. Locales are languages multiplied by countries, capped at 40 pairs per run.

## `minRating` (type: `integer`):

Keep only reviews at or above this rating. Leave empty for all ratings.

## `maxRating` (type: `integer`):

Keep only reviews at or below this rating. Set to 2 to pull complaints only.

## `appVersions` (type: `array`):

Keep only reviews written against these exact app versions, for example 9.1.64.1676. Leave empty for all versions.

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

Adds app title, developer, lifetime store rating, rating count, category and price to each app summary.

## `expectedNoMatch` (type: `boolean`):

Leave off for normal runs. When off, a run that finds zero reviews fails and saves diagnostic evidence instead of quietly returning an empty dataset.

## Actor input object example

```json
{
  "appIds": [
    "com.spotify.music",
    "com.duolingo"
  ],
  "languages": [
    "en",
    "es",
    "de",
    "pt",
    "fr"
  ],
  "countries": [
    "us"
  ],
  "sortBy": "newest",
  "maxReviewsPerLocale": 40,
  "appVersions": [],
  "includeAppDetails": true,
  "expectedNoMatch": false
}
```

# Actor output Schema

## `results` (type: `string`):

Deduplicated review rows followed by one summary per app, one run summary and one agent briefing.

## `briefing` (type: `string`):

Markdown briefing for the run.

# 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 = {
    "appIds": [
        "com.spotify.music",
        "com.duolingo"
    ],
    "languages": [
        "en",
        "es",
        "de",
        "pt",
        "fr"
    ],
    "countries": [
        "us"
    ],
    "maxReviewsPerLocale": 40
};

// Run the Actor and wait for it to finish
const run = await client.actor("skootle/google-play-review-intelligence").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 = {
    "appIds": [
        "com.spotify.music",
        "com.duolingo",
    ],
    "languages": [
        "en",
        "es",
        "de",
        "pt",
        "fr",
    ],
    "countries": ["us"],
    "maxReviewsPerLocale": 40,
}

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

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

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

```

## CLI example

```bash
echo '{
  "appIds": [
    "com.spotify.music",
    "com.duolingo"
  ],
  "languages": [
    "en",
    "es",
    "de",
    "pt",
    "fr"
  ],
  "countries": [
    "us"
  ],
  "maxReviewsPerLocale": 40
}' |
apify call skootle/google-play-review-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=skootle/google-play-review-intelligence",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Play Review Intelligence",
        "description": "Google Play reviews across many languages in one run, with rating by app version, release regression flags, per locale sentiment, complaint themes, developer reply rate and joined app metadata. Export normalized records, use the API, schedule monitoring, or connect integrations and agent workflows.",
        "version": "1.0",
        "x-build-id": "6jwvCRTYx7HjfxpQ4"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/skootle~google-play-review-intelligence/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-skootle-google-play-review-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/skootle~google-play-review-intelligence/runs": {
            "post": {
                "operationId": "runs-sync-skootle-google-play-review-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/skootle~google-play-review-intelligence/run-sync": {
            "post": {
                "operationId": "run-sync-skootle-google-play-review-intelligence",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "appIds"
                ],
                "properties": {
                    "appIds": {
                        "title": "Android app IDs or Play Store URLs",
                        "minItems": 1,
                        "maxItems": 10,
                        "type": "array",
                        "description": "One to ten Android package names such as com.spotify.music, or full Google Play app URLs. The package name is pulled out of a URL automatically.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "languages": {
                        "title": "Review languages",
                        "minItems": 1,
                        "maxItems": 12,
                        "type": "array",
                        "description": "Google Play returns a different set of public reviews for every language. Listing several languages here is what multiplies your coverage: five languages returned five times the unique reviews of one language in our verification runs. Duplicates are removed before you are billed.",
                        "default": [
                            "en"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "countries": {
                        "title": "Country storefronts",
                        "minItems": 1,
                        "maxItems": 10,
                        "type": "array",
                        "description": "Two-letter country codes. Countries are collected alongside languages and every review is labelled with the locale it came from. Country alone changes little on Google Play, language is the axis that matters.",
                        "default": [
                            "us"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "sortBy": {
                        "title": "Sort reviews by",
                        "enum": [
                            "newest",
                            "rating",
                            "mostRelevant"
                        ],
                        "type": "string",
                        "description": "Newest first is the right choice for release monitoring and regression detection.",
                        "default": "newest"
                    },
                    "maxReviewsPerLocale": {
                        "title": "Max reviews per app per locale",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Upper bound per app and locale. Locales are languages multiplied by countries, capped at 40 pairs per run.",
                        "default": 100
                    },
                    "minRating": {
                        "title": "Minimum star rating",
                        "minimum": 1,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Keep only reviews at or above this rating. Leave empty for all ratings."
                    },
                    "maxRating": {
                        "title": "Maximum star rating",
                        "minimum": 1,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Keep only reviews at or below this rating. Set to 2 to pull complaints only."
                    },
                    "appVersions": {
                        "title": "App versions filter",
                        "maxItems": 20,
                        "type": "array",
                        "description": "Keep only reviews written against these exact app versions, for example 9.1.64.1676. Leave empty for all versions.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "includeAppDetails": {
                        "title": "Join app metadata",
                        "type": "boolean",
                        "description": "Adds app title, developer, lifetime store rating, rating count, category and price to each app summary.",
                        "default": true
                    },
                    "expectedNoMatch": {
                        "title": "This query is expected to return nothing",
                        "type": "boolean",
                        "description": "Leave off for normal runs. When off, a run that finds zero reviews fails and saves diagnostic evidence instead of quietly returning an empty dataset.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
