# App Store & Google Play Reviews — Multi-Country (`tidynest/app-reviews-multi-country`) Actor

Reviews and metadata from BOTH stores in one run. Sweeps multiple App Store countries, because the storefronts that serve reviews differ per app — single-country scrapers return zero for many apps.

- **URL**: https://apify.com/tidynest/app-reviews-multi-country.md
- **Developed by:** [TidyNest Studio](https://apify.com/tidynest) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 60.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

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

## App Store & Google Play Reviews — Multi-Country

Get **reviews and app metadata from both mobile stores in a single run**.

### Why this actor exists

Apple's public review feed serves up to **500 reviews per storefront** (10 pages of 50, no overlap

- measured, page 11 errors out). Most scrapers read the first page of a single country and call it
  a day.

The problem: **the storefronts that actually serve reviews differ from app to app.**

| App | Storefronts that returned reviews |
|---|---|
| WhatsApp | `us`, `jp`, `au`, `mx` |
| Todoist | `de`, `es`, `ru` — and **zero from `us`** |

And a storefront that works today can serve an empty feed tomorrow: measured 20 minutes apart,
one show's US feed went from 49 reviews to zero while GB and DE were unaffected (HTTP 200 both
times). Sweeping storefronts is what makes the output reproducible.

A US-only scraper returns **nothing** for Todoist. This actor sweeps a list of storefronts and
de-duplicates by review ID, so you get what actually exists instead of what one country happens to
expose.

### What you get

**Reviews** — rating, title, text, author, app version, date, publisher reply (Google Play), country.
**Metadata** (optional, one row per app) — average rating, rating count, current version, publisher,
price, release date.

### Input

| Field | Meaning |
|---|---|
| `stores` | `app_store`, `google_play`, or both |
| `appStoreIds` | numeric Apple IDs (e.g. `572688855`) |
| `googlePlayIds` | package names (e.g. `com.todoist`) |
| `searchTerm` | resolve the top App Store match by name instead of passing an ID |
| `countries` | storefronts to sweep — leave empty for a 20-country default |
| `maxReviewsPerApp` | upper bound per app and per store |
| `sort` | Google Play ordering: newest / most relevant / rating |

### Typical uses

- Track what users say after each release (`app_version` is on every review)
- Watch competitors' ratings and complaints
- Feed review text into sentiment or topic analysis
- Measure how support replies land (Google Play replies are included)

### Reliability

This actor uses **official and public endpoints only** — Apple's RSS review feed, the iTunes
Search/Lookup API, and Google Play's own web data endpoint. No anti-bot circumvention, no residential
proxies. That is a deliberate design choice: scrapers built on hostile targets break constantly, and
it shows in their ratings.

# Actor input Schema

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

Which stores to scrape.

## `appStoreIds` (type: `array`):

Numeric Apple app IDs, e.g. 572688855 for Todoist. Find them with the search field below.

## `googlePlayIds` (type: `array`):

Package names, e.g. com.todoist.

## `searchTerm` (type: `string`):

If set, the actor resolves the top matching app on each selected store instead of using the ID lists.

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

Apple serves reviews from a SUBSET of storefronts that varies per app — sweeping several is what makes the difference. Leave empty for a sensible default list of 20.

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

Upper bound per app and per store.

## `sort` (type: `string`):

Ordering for Google Play reviews. The App Store feed is always most-recent.

## `includeMetadata` (type: `boolean`):

Adds one row per app with rating, rating count, version, publisher.

## Actor input object example

```json
{
  "stores": [
    "app_store",
    "google_play"
  ],
  "appStoreIds": [
    "572688855"
  ],
  "googlePlayIds": [
    "com.todoist"
  ],
  "countries": [
    "us",
    "gb",
    "au",
    "ca",
    "de"
  ],
  "maxReviewsPerApp": 200,
  "sort": "newest",
  "includeMetadata": true
}
```

# Actor output Schema

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

One row per review, plus one metadata row per app when enabled.

## `reviewsCsv` (type: `string`):

Same dataset, ready for a spreadsheet.

## `consoleUrl` (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 = {
    "appStoreIds": [
        "572688855"
    ],
    "googlePlayIds": [
        "com.todoist"
    ],
    "countries": [
        "us",
        "gb",
        "au",
        "ca",
        "de"
    ],
    "maxReviewsPerApp": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidynest/app-reviews-multi-country").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 = {
    "appStoreIds": ["572688855"],
    "googlePlayIds": ["com.todoist"],
    "countries": [
        "us",
        "gb",
        "au",
        "ca",
        "de",
    ],
    "maxReviewsPerApp": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("tidynest/app-reviews-multi-country").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 '{
  "appStoreIds": [
    "572688855"
  ],
  "googlePlayIds": [
    "com.todoist"
  ],
  "countries": [
    "us",
    "gb",
    "au",
    "ca",
    "de"
  ],
  "maxReviewsPerApp": 200
}' |
apify call tidynest/app-reviews-multi-country --silent --output-dataset

```

## MCP server setup

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

```

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/xKctrsNQLfeH4EwWP/builds/oGXw1bW4CvsXZqi9V/openapi.json
