# App Store Scraper: iOS Apps, Ratings & Pricing (`arman-bd/itunes-app-store-scraper`) Actor

Scrape the iOS App Store through Apple's official Search API: name, developer, rating, review count, price, category, screenshots, version and release notes.

- **URL**: https://apify.com/arman-bd/itunes-app-store-scraper.md
- **Developed by:** [Arman Hossain](https://apify.com/arman-bd) (community)
- **Categories:** E-commerce, SEO tools, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 app scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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.

- **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 Scraper: iOS Apps, Ratings & Pricing

![App Store Lookup: Full app metadata by ID or search: seller, rating, price and version](https://api.apify.com/v2/key-value-stores/ZQOcNAOHrIgTacAmy/records/itunes-app-store-scraper.jpg)

Pulls iOS, iPad and Mac app metadata straight from Apple's own Search API. You get the name, developer, rating, review count, price, category, screenshots, version, release notes, file size and minimum OS.

This is Apple's own documented data, the same source iTunes affiliate tools have used for years. A 200-app keyword sweep is a single request.

**Agent skill: [SKILL.md](https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/itunes-app-store-scraper.md)**

```
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/itunes-app-store-scraper.md
```

### What you get

| Field | What it holds |
|---|---|
| `trackId`, `trackName`, `bundleId` | Apple's numeric app ID, the store name and the reverse-DNS bundle ID |
| `sellerName`, `artistName`, `artistId` | Legal seller name, display developer name and developer ID |
| `price`, `formattedPrice`, `currency` | Numeric price, the localised string ("Free", "£5.99") and the storefront currency |
| `averageUserRating`, `userRatingCount` | Lifetime rating and rating count |
| `averageUserRatingForCurrentVersion`, `userRatingCountForCurrentVersion` | The same two, scoped to the shipping version |
| `primaryGenre`, `genres` | Primary category and the full category list |
| `version`, `releaseDate`, `currentVersionReleaseDate` | Shipping version, first release, and when this version shipped |
| `releaseNotes`, `description` | Full "What's New" text and the full store description |
| `minimumOsVersion`, `fileSizeBytes`, `contentAdvisoryRating`, `languages` | Requirements, download size in bytes, age rating and supported languages |
| `screenshotUrls`, `ipadScreenshotUrls`, `artworkUrl512` | iPhone and iPad screenshots, plus the 512px icon |
| `trackViewUrl`, `sellerUrl` | Store listing URL and the developer's own site |
| `country`, `source`, `scrapedAt` | Storefront used, which input produced the row, and when the run happened |

`RUN_SUMMARY` in the key-value store holds per-run counts, the filters you used, and any target that failed.

### What people use it for

- **ASO research.** See exactly which apps rank for a keyword, and how their ratings compare.
- **Release tracking.** Poll `version` and `currentVersionReleaseDate` daily to spot a competitor's ship cadence.
- **Cross-storefront pricing.** Run the same app IDs against US, GB, DE and JP to compare price and rating.
- **App enrichment.** Turn a list of bundle IDs from an MDM or analytics export into full store records.
- **Category benchmarking.** Pull the top 200 for a category keyword and chart the rating distribution.

### Quick start

One keyword, top 50 US apps:

```json
{
 "searchTerms": ["habit tracker"],
 "maxResultsPerTerm": 50
}
```

Specific apps in the UK storefront, with mixed ID formats:

```json
{
 "appIds": [
 "618783545",
 "https://apps.apple.com/us/app/slack/id618783545",
 "com.burbn.instagram"
 ],
 "country": "GB"
}
```

Mac apps, two keywords, capped:

```json
{
 "searchTerms": ["markdown editor", "screenshot tool"],
 "entity": "macSoftware",
 "country": "US",
 "maxResultsPerTerm": 25
}
```

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `searchTerms` | array | `[]` | Keywords, one search pass each. Ranked as the store ranks them. |
| `appIds` | array | `[]` | Numeric IDs, `apps.apple.com` URLs or bundle IDs. Numeric IDs are batched 50 per request, and bundle IDs cost one request each. |
| `country` | string | `US` | Two-letter storefront code. Changes price, currency, availability and localised text. |
| `entity` | string | `software` | `software` (iPhone), `iPadSoftware` or `macSoftware`. |
| `maxResultsPerTerm` | integer | `50` | Cap per search term, clamped to Apple's hard limit of 200. Ignored for `appIds` lookups. |

At least one of `searchTerms` or `appIds` has to be non-empty. They combine freely: results are deduplicated on `trackId`, so an app that appears in both a search and a lookup is saved once.

### Output example

```json
{
 "trackId": 618783545,
 "trackName": "Slack",
 "bundleId": "com.tinyspeck.chatlyio",
 "sellerName": "SLACK TECHNOLOGIES L.L.C.",
 "artistName": "Slack Technologies, Inc.",
 "artistId": 453420243,
 "price": 0,
 "formattedPrice": "Free",
 "currency": "USD",
 "averageUserRating": 4.10675,
 "userRatingCount": 49068,
 "averageUserRatingForCurrentVersion": 4.10675,
 "userRatingCountForCurrentVersion": 49068,
 "primaryGenre": "Business",
 "genres": ["Business", "Productivity"],
 "version": "26.08.10",
 "releaseDate": "2013-03-20T19:23:34Z",
 "currentVersionReleaseDate": "2026-08-05T19:26:20Z",
 "releaseNotes": "Bug Fixes\n• Photoshop files pulled a disappearing act when shared .",
 "description": "Companies in every industry around the world grow their business in Slack .",
 "minimumOsVersion": "17.0",
 "fileSizeBytes": 345516032,
 "contentAdvisoryRating": "17+",
 "languages": ["EN", "FR", "DE", "IT", "JA", "KO", "PT", "ZH", "ES"],
 "screenshotUrls": ["https://is1-ssl.mzstatic.com/image/thumb/./392x696bb.png"],
 "ipadScreenshotUrls": ["https://is1-ssl.mzstatic.com/image/thumb/./552x414bb.jpg"],
 "artworkUrl512": "https://is1-ssl.mzstatic.com/image/thumb/./512x512bb.jpg",
 "trackViewUrl": "https://apps.apple.com/us/app/slack/id618783545?uo=4",
 "sellerUrl": "https://slack.com/is",
 "country": "US",
 "source": "appIds",
 "scrapedAt": "2026-08-06T11:37:21.807Z"
}
```

### Finding an app ID

Open the app's store page and read the URL.

| URL you see | What to paste |
|---|---|
| `apps.apple.com/us/app/slack/id618783545` | The whole URL, or just `618783545` |
| `apps.apple.com/gb/app/instagram/id389801252?l=en` | The whole URL. Query strings are ignored |

If all you have is a bundle ID from an MDM inventory or a crash report, such as `com.tinyspeck.chatlyio`, paste that instead. Anything containing a dot and no leading `id` is treated as a bundle ID and resolved through Apple's `bundleId` lookup.

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/arman-bd~itunes-app-store-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
 -H "Content-Type: application/json" \
 -d '{
 "searchTerms": ["habit tracker"],
 "country": "US",
 "maxResultsPerTerm": 50
 }'
```

### JavaScript example

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

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/itunes-app-store-scraper').call({
 appIds: ['618783545', 'com.burbn.instagram'],
 country: 'GB',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const app of items) {
 console.log(`${app.trackName} - ${app.averageUserRating} (${app.userRatingCount} ratings) ${app.formattedPrice}`);
}
```

### Notes

- Search returns at most 200 apps per term, and there is no page two. Apple accepts an `offset` parameter and then ignores it, which was verified directly. If you need more than 200 results, use more specific terms rather than deeper paging.
- The storefront changes the data, not just the currency. Ratings, availability and release-note translations are all per-country, so run the same IDs against several `country` values to compare.
- The endpoint answers with `content-type: text/javascript`. The body is valid JSON, and the Actor parses it as text rather than trusting the header.
- The rate limit is roughly 20 requests per minute per IP. It is undocumented but consistent. Because keyword sweeps are one request per term, normal runs sit far below it.
- A bad target won't kill the run. An invalid storefront returns HTTP 400 and is recorded in `RUN_SUMMARY.failures`. The Actor only errors out if every target fails.

### FAQ

**Do I need an Apple developer account or API key?** No. You supply no credentials.

**Do I need a proxy?** No. Proxy configuration is not required to run this Actor.

**Can I get user reviews?** Not from this Actor. The Search API returns aggregate ratings only. Individual review text lives in a separate RSS feed and is not part of this dataset.

**Why does an app return no results?** Either it is not available in that storefront, or the ID is wrong. A lookup that finds nothing returns zero results with HTTP 200, so check `RUN_SUMMARY`. The listed-versus-saved counts tell the two apart.

**Can I get ranking positions?** Search results come back in Apple's own relevance order, so row order is the ranking for that keyword. Chart positions (Top Free, Top Paid) are a different feed and are not included.

**Can I plug it into something else?** Yes. Apify API, the client libraries, webhooks, scheduled runs, dataset exports to JSON, CSV or Excel, or MCP. The output is structured JSON.

# Actor input Schema

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

Keywords to search the store with, one pass per term. Matches app names, developers and keyword metadata, in the same ranking a shopper sees. Leave empty if you only want the apps listed in App IDs.

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

Specific apps to fetch. Accepts numeric App Store IDs (618783545), full store URLs (https://apps.apple.com/us/app/slack/id618783545) or bundle IDs (com.tinyspeck.chatlyio). Leave empty to rely on search alone.

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

Two-letter storefront code. Price, currency, availability, ratings and localised text all change with it: GB returns GBP, and DE returns EUR and German release notes.

## `entity` (type: `string`):

Which catalogue to search. iPad and Mac software are separate indexes on Apple's side, so switching this changes the result set, not just a flag on it.

## `maxResultsPerTerm` (type: `integer`):

How many apps to take for each search term. Apple caps a search response at 200 and offers no pagination, so values above 200 are clamped. Ignored for App ID lookups, which always return every match.

## Actor input object example

```json
{
  "searchTerms": [
    "habit tracker",
    "budget app"
  ],
  "appIds": [
    "618783545",
    "https://apps.apple.com/us/app/slack/id618783545",
    "com.burbn.instagram"
  ],
  "country": "GB",
  "entity": "software",
  "maxResultsPerTerm": 50
}
```

# Actor output Schema

## `items` (type: `string`):

Every record the run produced.

## `runsummary` (type: `string`):

The RUN\_SUMMARY record from the run's key-value store.

# 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 = {
    "searchTerms": [
        "habit tracker"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arman-bd/itunes-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 = { "searchTerms": ["habit tracker"] }

# Run the Actor and wait for it to finish
run = client.actor("arman-bd/itunes-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 '{
  "searchTerms": [
    "habit tracker"
  ]
}' |
apify call arman-bd/itunes-app-store-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arman-bd/itunes-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/06dKYyy9kn0doLZ4u/builds/lFkrUqVolXMHCrgL8/openapi.json
