# App Store and Google Play Scraper (Reviews and Charts) (`locaihost/app-stores`) Actor

Scrape App Store and Google Play reviews and app data in one schema: rating, title, text, date, app version and developer reply, plus installs, ratings count, price and rank from search and top charts. Filter by stars, date, keyword or version. Any country. No login. $0.10 per 1,000 reviews.

- **URL**: https://apify.com/locaihost/app-stores.md
- **Developed by:** [locaihost data](https://apify.com/locaihost) (community)
- **Categories:** Marketing, SEO tools, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.06 / 1,000 apps

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## App Store and Google Play Scraper (Reviews and Charts)

Get reviews and app data from the Apple App Store and Google Play in one run and one schema, as JSON or CSV rows: ratings, review text, app versions, developer replies, installs, prices and chart ranks, for any country. No login, no API key, no account.

What people use it for:

- Reading what users complain about: the newest 1- and 2-star reviews of your app from both stores in one table.
- Following a competitor's ratings, version history and reviews after each release.
- Watching the top free, paid and grossing charts, overall or in 40 categories, country by country.
- App-store optimisation: which apps each store returns for your keywords, in order, with rank.
- Review monitoring on a schedule: turn on `onlyNew` and pay only for reviews posted since the last run.

### Quick start

Paste this into the **JSON** tab of the input and click **Start**:

```json
{"mode": "reviews", "apps": ["com.duolingo", "570060128"], "maxReviewsPerApp": 5}
```

You get the 5 newest Google Play reviews and the 5 newest App Store reviews of Duolingo: 10 rows, usually in under a minute. App Store links or ids and Google Play links or package names can be mixed in one list.

More examples:

```json
{"mode": "reviews", "apps": ["570060128", "com.duolingo"], "reviewRatings": ["1", "2"], "reviewsSince": "30 days", "reviewKeywords": ["crash", "freezes"], "maxReviewsPerApp": 500}
```

```json
{"mode": "charts", "chartTypes": ["top-grossing"], "category": "games", "countries": ["us", "gb", "de"], "maxResults": 100}
```

```json
{"mode": "search", "searchTerms": ["habit tracker", "budget app"], "countries": ["us"], "maxResults": 25}
```

### Output

Six modes, set with `mode`: **details** (apps you list), **search** (apps for your words, with `rank`), **charts** (top free, paid or grossing, overall or by category, up to 200 per chart), **developer** (every app by a developer), **reviews** and **similar** (what each store shows as similar apps). An iPhone app and its Android twin come back with the same columns; a field one store doesn't publish is `null`, never a guess.

| Group | Fields |
|---|---|
| App | `store`, `appId`, `bundleId`, `title`, `summary`, `description`, `releaseNotes`, `url`, `icon`, `screenshots` |
| Developer | `developer`, `developerId`, `developerUrl` |
| Store listing | `category`, `categoryId`, `price`, `currency`, `free`, `contentRating`, `size`, `sizeBytes` (App Store) |
| Ratings and installs | `rating`, `ratingsCount`, `reviewsCount`, `installs`, `minInstalls` (Google Play) |
| Versions | `version`, `updatedAt`, `releasedAt` |
| Lists | `rank`, `chart`, `chartCategory`, `mode`, `query`, `country`, `language`, `detail` (full or list) |
| Review | `reviewId`, `rating`, `title` (App Store), `text`, `date`, `version`, `helpfulCount`, `voteCount` (App Store) |
| Developer reply | `developerReply`, `developerReplyDate` (Google Play) |
| Reviewer | `userName`, only when `includeReviewerNames` is on |

One real review row from each store and one app row (runs on 2026-10-16 and 2026-10-18, shortened):

```json
[
  {
    "type": "review",
    "store": "apple",
    "appId": "570060128",
    "reviewId": "14665086998",
    "rating": 5,
    "title": "Hi",
    "text": "I like it it helps me a lot",
    "date": "2026-10-14T10:45:00.000Z",
    "version": "7.144.0",
    "helpfulCount": 0,
    "voteCount": 0,
    "developerReply": null,
    "userName": null,
    "sort": "newest",
    "country": "us",
    "appUrl": "https://apps.apple.com/us/app/id570060128"
  },
  {
    "type": "review",
    "store": "google",
    "appId": "com.duolingo",
    "reviewId": "b4c911b9-b3d2-4782-a54f-0f1040e72d93",
    "rating": 5,
    "title": null,
    "text": "very good app",
    "date": "2026-10-15T02:56:42.000Z",
    "version": "6.100.3",
    "helpfulCount": 0,
    "developerReply": null,
    "country": "us",
    "language": "en"
  },
  {
    "type": "app",
    "store": "google",
    "appId": "com.duolingo",
    "title": "Duolingo: Learn Languages",
    "developer": "Duolingo",
    "category": "Education",
    "price": 0,
    "currency": "USD",
    "rating": 4.7451,
    "ratingsCount": 51054496,
    "reviewsCount": 965970,
    "installs": "500,000,000+",
    "minInstalls": 500000000,
    "updatedAt": "2026-10-12T16:38:11.000Z",
    "releasedAt": "2013-05-29T12:18:00.000Z",
    "contentRating": "Everyone",
    "summary": "Make language learning fun with Spanish, French, English, chess, math & music.",
    "mode": "details",
    "country": "us",
    "detail": "full"
  }
]
```

The dataset has four views (**Apps**, **Reviews**, **App details** with every field, and **Free rows**) and exports to JSON, CSV, Excel or HTML. The run's `SUMMARY` record counts rows by store and lists anything that failed.

### Pricing

You pay per app or review returned. There is no charge for Apify platform usage on top.

| Row | Free and Starter | Scale | Business |
|---|---|---|---|
| Review | $0.10 per 1,000 | $0.075 per 1,000 | $0.055 per 1,000 |
| App | $0.10 per 1,000 | $0.075 per 1,000 | $0.055 per 1,000 |

Plus $0.00005 per run start. **Apify's free $5 monthly credit covers about 50,000 apps or reviews.** Free-plan runs stop at 500 rows each; any paid Apify plan removes the cap.

**What's free:** apps, developers or searches that don't exist, apps not sold in a country, and apps with no reviews for your settings (each comes back as a free row saying why), reviews left out by `reviewsSince`, `reviewKeywords` or `appVersions`, and apps or reviews skipped by `onlyNew`. A run that returns nothing because of the input costs nothing. To cap a run's spend, set **Maximum cost per run** in the run options, or **Max rows** in the input.

### Limits

- App Store reviews: at most 500 per app, country and order. Apple's public review feed holds the newest 500 (or the 500 most helpful). Google Play has no such cap. App Store reviews carry no developer replies in the feed. Apple's review feed often answers with an empty page at first, so the Actor asks again (up to 48 times per page, several at once) before it reports an app as having no reviews.
- Google Play search shows about 30 results per search word. Charts and developer lists go up to 200 (`maxResults`, 1 to 200).
- Very deep Google Play review history: thousands of reviews in, Google Play sometimes stops answering for an app. The run keeps what it already has for that app, says so, and still ends successfully; run it again later for more.
- Google Play reviews come in the language you choose (`language`, default `en`); reviews written in other languages are not in that list. App Store text follows each country's store.
- Install counts are Google Play's public bands ("10,000,000+"); the App Store publishes no install numbers. Google Play no longer shows app size.
- Google Play list rows: with `fullDetails` off, search, chart, developer and similar rows come from the short list card (no ratings count, version or update date; `detail` is `list`). With it on (the default), each app's own page is read too. If a page can't be read, the app still comes back as a list row.
- Each country is read separately, because prices, charts, ranks and reviews differ by country.
- Ratings, ranks and prices are the stores' public figures at the time of the run.

### Only new since last run, and schedules

Turn on **Only new since the last run** and schedule the Actor daily. Each run skips apps and reviews that earlier runs with the same input already returned, and skipped rows cost nothing. For reviews in newest-first order, it stops reading an app once a page has nothing new. In charts mode it gives you only apps that are new to the chart. Set up a schedule under **Schedules** in Apify Console.

### Integrations: API, n8n, Make and AI agents

**API.** Run it and get the rows back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/locaihost~app-stores/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "reviews", "apps": ["570060128", "com.duolingo"], "reviewRatings": ["1", "2"], "maxReviewsPerApp": 50}'
```

Apify's API clients for Python and JavaScript work the same way.

**n8n, Make, Zapier, Google Sheets, Slack, webhooks.** Apify's built-in integrations send each run's dataset wherever you need it, for example new 1-star reviews into a Slack channel.

**AI agents (MCP).** Add this Actor to Claude, Cursor or any MCP client with `https://mcp.apify.com/?tools=locaihost/app-stores`, then ask something like *"What are people complaining about in Calm's 1- and 2-star reviews on both stores this month?"*

### FAQ

#### How much does it cost to scrape App Store and Google Play reviews?

$0.10 per 1,000 reviews or apps on the Free and Starter plans, less on Scale and Business. Apify's free $5 monthly credit covers about 50,000 apps or reviews.

#### Can I use it through the API or from Python?

Yes. Use the `run-sync-get-dataset-items` call above, or Apify's Python and JavaScript clients. Every run's data is also available as JSON, CSV or Excel from its dataset.

#### Can I use it from an AI agent?

Yes. Through the Apify MCP server (`https://mcp.apify.com/?tools=locaihost/app-stores`) any MCP client can call it with a list of apps, search words or a chart and read the rows back.

#### Is it legal to scrape app store reviews?

The Actor reads what any visitor to the stores can see, without logging in: Apple's public lookup, search, chart and review feeds, and Google Play's public pages. Google Play's terms restrict automated collection, so check them against your use. Reviews come without the reviewer's name unless you turn on `includeReviewerNames`, which adds only the public display name; reviewer account ids, profile pictures and contact details are never collected. App rows carry the developer's name, id and store link, never their email, phone or postal address. You are responsible for how you use the results, including the stores' terms and the data-protection law that applies to you.

#### How do I find an app's id?

Paste the store link: `https://apps.apple.com/us/app/duolingo-language-lessons/id570060128` (or just `570060128`) for the App Store, and `https://play.google.com/store/apps/details?id=com.duolingo` (or just `com.duolingo`) for Google Play. For an App Store bundle id, write `apple:com.example.app`.

#### Why are some fields empty?

Each store publishes different things: `installs` exists only on Google Play, `size` and review titles only on the App Store, and developer replies only on Google Play. Google Play list rows (`detail: "list"`) have no ratings count, version or update date; keep `fullDetails` on to get them.

### More from locaihost data

- [Trustpilot reviews and ratings](https://apify.com/locaihost/trustpilot-reviews): what customers say about the company behind the app.
- [YouTube transcripts](https://apify.com/locaihost/youtube-transcripts): what reviewers and creators say about an app in their videos.
- [Google Trends data](https://apify.com/locaihost/google-trends): search interest in an app or category over time.
- [Website traffic checker](https://apify.com/locaihost/website-traffic): monthly visits and traffic sources for the app's website.

### Did it help?

If this saved you time, a quick rating on the Store helps other people find it.

### Support

If something breaks or you need a field we don't return, open an issue on the **Issues** tab. We answer issues within 24 hours.

# Changelog

This Actor's version history is a separate document: https://apify.com/locaihost/app-stores/changelog.md

# Actor input Schema

## `mode` (type: `string`):

details: full records for the apps you list. search: apps for your search words. charts: top free, paid or grossing apps. developer: every app by a developer. reviews: reviews of the apps you list. similar: the apps each store shows as similar.

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

App Store links or ids (https://apps.apple.com/us/app/id570060128 or 570060128) and Google Play links or package names (com.duolingo). Mix both stores freely. For an App Store bundle id, write apple:com.example.app.

## `searchTerms` (type: `array`):

Words to search for, one per line, as a shopper would type them ("habit tracker", "budget app"). Used in search mode.

## `developers` (type: `array`):

An App Store developer link (https://apps.apple.com/us/developer/meta-platforms-inc/id284882218) or id, a Google Play developer link, or a Google Play developer name exactly as on Play ("Google LLC"). Used in developer mode.

## `stores` (type: `array`):

Which stores to read in search and charts mode. In the other modes each link or id already says its store.

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

Two-letter store countries, such as us, gb, de, jp, in, br. Each country is read separately: prices, ranks, charts and reviews differ by country.

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

Language for Google Play text and reviews (en, de, pt-BR ...). The App Store uses each country's own language.

## `chartTypes` (type: `array`):

Which charts to read in charts mode.

## `category` (type: `string`):

Chart category. A few categories exist in only one store; the run says so and reads the other.

## `maxResults` (type: `integer`):

Most apps per search, chart, developer or similar-apps list, per store and country (1 to 200). Google Play shows about 30 results per search.

## `fullDetails` (type: `boolean`):

Google Play search, chart, developer and similar lists show a short card per app. On, each app's own page is read too, which adds ratings count, version, update date and developer id. Off is faster. App Store rows are always full.

## `reviewSort` (type: `string`):

Newest first, or most helpful first.

## `reviewRatings` (type: `array`):

Leave empty for all ratings. Pick 1 and 2 to collect complaints only.

## `maxReviewsPerApp` (type: `integer`):

Per app and country. The App Store's public feed holds at most 500 reviews per app, country and order; Google Play has no such limit. Default 100.

## `reviewsSince` (type: `string`):

Optional. Only reviews from this date on, like 2026-09-01, or a period back from today like 30 days. With newest-first order the run stops reading an app at the first older review, so it reads only the pages it needs. Older reviews are not charged.

## `reviewKeywords` (type: `array`):

Optional. Only reviews whose title or text contains one of these words or phrases, ignoring case, e.g. crash, refund, subscription. Other reviews are left out and not charged.

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

Optional. Only reviews written on these app versions, as the store shows them. 5.2 matches 5.2 and 5.2.1. Reviews that show no version are left out. Not charged when left out.

## `includeReviewerNames` (type: `boolean`):

Off by default. On adds the public display name the store shows. Emails, account ids and profile pictures are never collected.

## `onlyNew` (type: `boolean`):

Skip apps and reviews this same input already returned in an earlier run. Turn on for scheduled review monitoring or to catch new chart entries. You pay only for new rows.

## `maxItems` (type: `integer`):

Stop after this many charged rows in total. 0 means no limit.

## Actor input object example

```json
{
  "mode": "reviews",
  "apps": [
    "com.duolingo",
    "570060128"
  ],
  "stores": [
    "apple",
    "google"
  ],
  "countries": [
    "us"
  ],
  "language": "en",
  "chartTypes": [
    "top-free"
  ],
  "category": "all",
  "maxResults": 50,
  "fullDetails": true,
  "reviewSort": "newest",
  "maxReviewsPerApp": 5,
  "reviewKeywords": [
    "crash",
    "refund"
  ],
  "appVersions": [
    "5.2"
  ],
  "includeReviewerNames": false,
  "onlyNew": false,
  "maxItems": 0
}
```

# Actor output Schema

## `apps` (type: `string`):

One row per app: store, title, developer, rating, ratings, installs, price, version, rank.

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

One row per review: rating, title, text, date, app version, helpful count, developer reply.

## `full` (type: `string`):

Every field of every row, including free not-found rows.

## `summary` (type: `string`):

Counts, free rows by reason, anything that failed, and cost.

# 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 = {
    "mode": "reviews",
    "apps": [
        "com.duolingo",
        "570060128"
    ],
    "maxReviewsPerApp": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("locaihost/app-stores").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 = {
    "mode": "reviews",
    "apps": [
        "com.duolingo",
        "570060128",
    ],
    "maxReviewsPerApp": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("locaihost/app-stores").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 '{
  "mode": "reviews",
  "apps": [
    "com.duolingo",
    "570060128"
  ],
  "maxReviewsPerApp": 5
}' |
apify call locaihost/app-stores --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,locaihost/app-stores"
        }
    }
}
```

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/NLJUMnQ9mHXjIVsnc/builds/DYYy28eP6YrdsiGDV/openapi.json
