# Apple App Store Scraper: Apps, Reviews & Keyword Rankings (`fetchsmith-labs/app-store-scraper`) Actor

Extract Apple App Store app details, search results, customer reviews and keyword rankings with top competitors. Official Apple APIs only, no login, no proxy. Ideal for ASO and app market research.

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

## Pricing

from $2.00 / 1,000 app 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/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

## Apple App Store Scraper: Apps, Reviews & Keyword Rankings

Extract app details, search results, customer reviews and keyword rankings from the Apple App Store. This Apple App Store scraper is built for app developers, ASO (App Store Optimization) specialists, market researchers and product teams who need structured iOS app data without writing code. It uses only Apple's public iTunes Search API, Lookup API and customer review feed, so there is no login, no cookies and no proxy to configure.

### What data you get

The actor has four modes. Pick one with the `mode` input.

| Mode | What it does | Output |
| --- | --- | --- |
| `apps` | Details for app IDs, App Store URLs, bundle IDs or whole developer pages | One record per app and country |
| `search` | Apps that match one or more search terms | One record per app, with the search term and position |
| `reviews` | Public customer reviews for apps | One record per review |
| `keywordRanks` | Where your apps rank in the top 200 search results for each keyword and country, plus the top 10 competitors | One record per keyword, country and app |

#### App fields (modes `apps` and `search`)

| Field | Description |
| --- | --- |
| `appId`, `bundleId` | App Store ID and bundle identifier |
| `title`, `url` | App name and App Store link |
| `developer`, `developerId` | Seller name and developer ID |
| `price`, `currency` | Price in the storefront currency |
| `rating`, `ratingCount` | Average user rating and number of ratings |
| `genres`, `primaryGenre` | Categories |
| `version`, `releaseDate`, `currentVersionReleaseDate` | Version and ISO dates |
| `size` | Download size in bytes |
| `contentRating` | Age rating, for example `4+` |
| `description`, `releaseNotes` | Store texts |
| `screenshotUrls`, `iconUrl` | Image links |
| `country`, `scrapedAt` | Storefront and scrape time |
| `searchTerm`, `searchRank` | Only in `search` mode |

#### Review fields (mode `reviews`)

`appId`, `country`, `reviewId`, `title`, `text`, `rating`, `author`, `version`, `date`, `voteSum`, `voteCount`, `scrapedAt`.

#### Keyword rank fields (mode `keywordRanks`)

| Field | Description |
| --- | --- |
| `keyword`, `country` | The checked keyword and storefront |
| `appId` | The tracked app (null if you gave no apps) |
| `rank` | Position in the search results, `null` if not found in the top 200 |
| `totalResults` | Number of results Apple returned for the keyword (maximum 200) |
| `topCompetitors` | The first 10 results that are not your tracked apps: `rank`, `appId`, `title`, `developer`, `rating`, `ratingCount` |
| `scrapedAt` | Check time |

### How to use

1. Choose a **Mode**.
2. Fill the matching input: **Apps** (`appIds`) for `apps`, `reviews` and `keywordRanks`, **Search terms** for `search`, **Keywords** for `keywordRanks`.
3. Pick one or more **Countries** (two-letter App Store codes such as `us`, `gb`, `de`).
4. Set **Max items** and start the run.
5. Download the dataset as JSON, CSV, Excel or via API.

Apps can be given as numeric IDs (`570060128`), App Store URLs (`https://apps.apple.com/us/app/duolingo-language-lessons/id570060128`) or bundle IDs (`com.duolingo.DuolingoMobile`). In `apps` mode a developer page URL such as `https://apps.apple.com/us/developer/duolingo/id570060151` returns all apps of that developer.

Meaning of `maxItems`: in `apps` mode it is the total number of app records, in `search` mode it is per search term and country (Apple returns at most 200), in `reviews` mode it is per app and country (Apple exposes at most 500), and `keywordRanks` always checks the top 200 results.

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `apps` | `apps`, `search`, `reviews` or `keywordRanks` |
| `appIds` | string\[] | Duolingo URL | App IDs, App Store URLs, bundle IDs or developer page URLs. Used by `apps`, `reviews` and `keywordRanks` |
| `searchTerms` | string\[] | none | Search terms for `search` mode |
| `keywords` | string\[] | none | Keywords to check in `keywordRanks` mode |
| `countries` | string\[] | `["us"]` | Two-letter App Store country codes |
| `maxItems` | integer | `20` | Result limit (1 to 1000), see the note above for what it counts in each mode |
| `reviewSort` | string | `mostrecent` | `mostrecent` or `mosthelpful` (reviews mode) |

### Input example

```json
{
    "mode": "keywordRanks",
    "keywords": ["language learning", "learn spanish"],
    "appIds": ["570060128"],
    "countries": ["us", "de"]
}
```

Default input (runs in a few seconds):

```json
{
    "mode": "apps",
    "appIds": ["https://apps.apple.com/us/app/duolingo-language-lessons/id570060128"]
}
```

### Output example

Keyword rank record:

```json
{
    "keyword": "language learning",
    "country": "us",
    "appId": "570060128",
    "rank": 1,
    "totalResults": 195,
    "topCompetitors": [
        { "rank": 2, "appId": "829587759", "title": "Babbel - Language Learning", "developer": "Babbel GmbH", "rating": 4.72185, "ratingCount": 755621 }
    ],
    "scrapedAt": "2026-10-11T06:48:44.163Z"
}
```

Review record:

```json
{
    "appId": "284882215",
    "country": "us",
    "reviewId": "14645741666",
    "title": "Satisfaction",
    "text": "Encore plus",
    "rating": 4,
    "author": "Yassoo5",
    "version": "582.0.0",
    "date": "2026-10-09T12:54:00.000Z",
    "voteSum": 0,
    "voteCount": 0,
    "scrapedAt": "2026-10-11T06:49:19.837Z"
}
```

### Use the App Store scraper from your code (API)

Every run can be started over the Apify API, so you can plug App Store data into your own scripts, dashboards or ASO tools.

Node.js with the `apify-client` package:

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('fetchsmith-labs/app-store-scraper').call({
    mode: 'reviews',
    appIds: ['570060128'],
    countries: ['us', 'gb'],
    maxItems: 200,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'reviews');
```

Python with the `apify-client` package:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("fetchsmith-labs/app-store-scraper").call(run_input={
    "mode": "keywordRanks",
    "keywords": ["language learning"],
    "appIds": ["570060128"],
    "countries": ["us"],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

cURL, synchronous run that returns the dataset items directly:

```bash
curl -X POST "https://api.apify.com/v2/acts/fetchsmith-labs~app-store-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "search", "searchTerms": ["habit tracker"], "countries": ["us"], "maxItems": 50}'
```

Results can also go straight to Google Sheets, Make, Zapier, n8n, Slack or a webhook through the Apify integrations on the Actor page.

### Pricing

Pay per event. You only pay for results you receive.

| Event | Price | Charged for |
| --- | --- | --- |
| `app` | $0.002 | Each app record (modes `apps` and `search`) |
| `review` | $0.0004 | Each review |
| `keyword-rank` | $0.003 | Each keyword and country check (several tracked apps in the same check are not charged again) |

Example cost for 1,000 results: 1,000 app records cost $2.00, 1,000 reviews cost $0.40, and 1,000 keyword and country checks cost $3.00. The run stops cleanly when your maximum charge limit is reached.

### Use cases

- ASO keyword tracking: check your app's rank for target keywords in several countries and see who ranks above you.
- Competitor research: compare ratings, rating counts, versions, release notes and screenshots.
- Review analysis: collect user feedback for sentiment analysis, bug detection or feature requests.
- Market research: list the top apps for a search term or all apps of a developer.
- Monitoring: schedule runs with the Apify platform to watch version changes and rank movements.

### FAQ

**Do I need a proxy or login?** No. The actor reads Apple's public endpoints only.

**Is it legal?** The actor only collects publicly available App Store data (app listings, public ratings and public customer reviews) through Apple's documented public interfaces. You are responsible for using the data in line with applicable laws and Apple's terms. Reviews contain public usernames chosen by the reviewers, so handle them according to data protection rules such as GDPR.

**How fast is it?** Apple limits the Search and Lookup API to roughly 20 calls per minute per IP, so the actor spaces those calls about 3 seconds apart (concurrency 2) and backs off on 403 or 429 responses. A keyword check takes one call, so about 20 keyword and country checks per minute.

**How many reviews can I get?** Apple's review feed exposes at most 10 pages of 50 reviews (500 reviews) per app and country, newest first. Some apps and storefronts return no reviews at all.

**Why are fewer reviews returned than requested?** Apple's public review feed is inconsistent. Individual pages are sometimes empty while later pages hold data, and the `mosthelpful` sort order is often empty. The actor scans all 10 pages and skips empty ones, but it cannot return reviews Apple does not serve. Try `mostrecent` or another country.

**Why is the rank `null`?** The app was not in the top 200 results Apple returns for that keyword in that country. For some keywords Apple returns fewer than 200 results.

**Can I export App Store reviews to CSV or Excel?** Yes. Every run stores its results in a dataset that you can download as JSON, CSV, Excel, XML or HTML, or read through the API.

**Can I track keyword rankings over time?** Each `keywordRanks` run is a snapshot. To build a rank history, start the run on a schedule you create in your Apify account (for example daily) and compare the datasets, or send them to Google Sheets.

**Are ratings per country?** Yes. Ratings and prices come from the storefront you select.

### Support

Found a bug or missing a field? Open an issue on the actor page and we will take a look.

# Actor input Schema

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

What to scrape. apps: details for app IDs, App Store URLs or bundle IDs. search: apps matching search terms. reviews: customer reviews for apps. keywordRanks: position of your apps in the top 200 search results per keyword and country, plus the top 10 competitors.

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

Used by modes apps, reviews and keywordRanks. Numeric App Store IDs (570060128), App Store URLs (https://apps.apple.com/us/app/duolingo-language-lessons/id570060128) or bundle IDs (com.duolingo.DuolingoMobile). In mode apps, a developer page URL (apps.apple.com/us/developer/duolingo/id570060151) returns all apps of that developer. The default is only used by the default apps run; provide your own apps for the other modes.

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

Used by mode search. Each term is searched in every selected country.

## `keywords` (type: `array`):

Used by mode keywordRanks. Each keyword is checked in every selected country (one billable check per keyword and country).

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

Two-letter App Store storefront codes, for example us, gb, de, fr, jp. Every country is processed separately.

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

Apps mode: maximum number of app records in total. Search mode: maximum results per search term and country (Apple returns at most 200). Reviews mode: maximum reviews per app and country (Apple exposes at most 500). Keyword ranks mode ignores this value (always checks the top 200).

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

Used by mode reviews.

## Actor input object example

```json
{
  "mode": "apps",
  "appIds": [
    "https://apps.apple.com/us/app/duolingo-language-lessons/id570060128"
  ],
  "countries": [
    "us"
  ],
  "maxItems": 20,
  "reviewSort": "mostrecent"
}
```

# Actor output Schema

## `results` (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 = {
    "mode": "apps",
    "appIds": [
        "https://apps.apple.com/us/app/duolingo-language-lessons/id570060128"
    ],
    "countries": [
        "us"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetchsmith-labs/app-store-scraper").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": "apps",
    "appIds": ["https://apps.apple.com/us/app/duolingo-language-lessons/id570060128"],
    "countries": ["us"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("fetchsmith-labs/app-store-scraper").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": "apps",
  "appIds": [
    "https://apps.apple.com/us/app/duolingo-language-lessons/id570060128"
  ],
  "countries": [
    "us"
  ],
  "maxItems": 20
}' |
apify call fetchsmith-labs/app-store-scraper --silent --output-dataset

```

## MCP server setup

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

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/31nfUPh80yKbPCUF2/builds/3YOUevEO1KVCuQcTC/openapi.json
