# App Store Top Charts & Search (`grit-77/apple-top-charts`) Actor

App Store top charts scraper for storefront and genre research. Export chart rows, catalog search matches and Apple ID lookups as JSON with source links.

- **URL**: https://apify.com/grit-77/apple-top-charts.md
- **Developed by:** [Grit](https://apify.com/grit-77) (community)
- **Categories:** Marketing, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.05 / 1,000 chart or search rows

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

## App Store Top Charts & Search

App Store charts scraper returns Apple app, podcast, and book chart rows by storefront and genre. App Store search API returns catalog matches or Apple ID lookups with source links and retrieval times.

**Delivery status:** Draft implementation. Required Python execution is blocked by local process permissions. The saved sample is an explicitly labeled projection of real Apple responses, not a verified actor run. See REPORT.md and evidence/sample-origin.json before publishing.

### What it returns

Each row represents one item in one country/chart/query. The same Apple ID can appear in several contexts. Missing metadata is null rather than inferred.

| Field | Type | Example value |
|---|---|---|
| `source` | string | `"marketing_rss"` |
| `sourceUrl` | string | `"https://rss.marketingtools.apple.com/api/v2/us/apps/top-free/10/apps.json"` |
| `mode` | string | `"charts"` |
| `country` | string | `"us"` |
| `chart` | string | `"top_free_apps"` |
| `requestedGenreId` | null | `null` |
| `query` | null | `null` |
| `requestedId` | null | `null` |
| `rank` | integer | `1` |
| `id` | string | `"6760173601"` |
| `name` | string | `"Muse from Meta"` |
| `artistName` | string | `"Meta Platforms, Inc."` |
| `artistId` | string | `"1014725770"` |
| `bundleId` | null | `null` |
| `kind` | string | `"software"` |
| `url` | string | `"https://apps.apple.com/us/app/muse-from-meta/id6760173601"` |
| `artworkUrl` | string | `"https://is1-ssl.mzstatic.com/image/thumb/Purple211/v4/14/f4/82/14f482a9-e97f-ae33-f898-253dea69396b/HatchAppIconPublic-0-0-1x_U007ephone-0-1-0-sRGB-0-85-220.png/100x100bb.png"` |
| `genres` | array | `[]` |
| `genreIds` | array | `[]` |
| `releaseDate` | string | `"2026-09-08T00:00:00Z"` |
| `price` | null | `null` |
| `currency` | null | `null` |
| `rating` | null | `null` |
| `ratingCount` | null | `null` |
| `description` | null | `null` |
| `feedUpdatedAt` | string | `"2026-10-05T13:31:00Z"` |
| `fetchedAt` | string | `"2026-10-05T13:37:17.913Z"` |
| `status` | string | `"ok"` |
| `errors` | array | `[]` |

Marketing RSS often omits price, rating, bundle ID and descriptions. Search and Lookup provide those fields when present; this actor does not automatically enrich chart rows.

### Input example

```json
{
  "mode": "charts",
  "countries": [
    "us"
  ],
  "charts": [
    "top_free_apps"
  ],
  "maxItems": 10
}
```

Use the input schema for the remaining filters and defaults.

### Output example

This is a selected-field excerpt of the first object in [sample_output.json](sample_output.json). That file is a documented projection from captured Apple responses, not a verified actor run.

```json
{
  "source": "marketing_rss",
  "sourceUrl": "https://rss.marketingtools.apple.com/api/v2/us/apps/top-free/10/apps.json",
  "mode": "charts",
  "country": "us",
  "chart": "top_free_apps",
  "requestedGenreId": null,
  "query": null,
  "requestedId": null,
  "rank": 1,
  "id": "6760173601",
  "name": "Muse from Meta",
  "artistName": "Meta Platforms, Inc.",
  "artistId": null,
  "bundleId": null
}
```

### Pricing

Proposed item event: **$0.00005 per successfully stored row ($0.05 per 1,000)**. Diagnostic rows have no proposed item charge. No proposed startup or per-request fee.

The Store API snapshot from 2026-10-05 identifies [epctex/appstore-scraper](https://apify.com/epctex/appstore-scraper) as the most used comparable app metadata/search actor by totalUsers. Its primary dataset-item event is $0.0001, with separate query events. This proposal is below that result fee. See PRICING.md for the full comparison scope, receipts and Console configuration notes.

Pricing is a proposal for owner publication. Platform usage treatment and operating margin remain unverified.

### Limits and failure handling

- resultsPerQuery: 1–100 for charts; 1–200 for search. Search has no pagination.
- maxItems: 1–10,000 total new dataset rows, including diagnostics. Requests follow country, chart/query/ID and genre input order.
- At most 10 countries, 5 charts, 10 genres, 50 search terms or 100 lookup IDs; at most 500 request combinations.
- Concurrency: 1–10 in-flight jobs. Within one run, iTunes requests start at least 3.1 seconds apart. Apple's archived Search API documentation lists approximately 20 calls per minute, subject to change; several simultaneous actor runs share no rate gate.
- Network failures, HTTP 429/5xx and invalid JSON retry with exponential backoff. Retry-After delays are bounded at 60 seconds; permanent HTTP 4xx becomes a diagnostic.
- Country, chart and genre availability are controlled by Apple. Genre charts use legacy RSS; overall charts use marketing RSS, whose update cycles can differ. Genre feeds may return child categories.
- Invalid configuration fails with a field-specific message. Malformed items and failed requests produce diagnostic rows so remaining requests can continue.
- Results are contextual snapshots. Cross-run deduplication and migration recovery are outside this implementation; repeating a run can produce and charge repeated observations.
- No local performance benchmark or paid-platform billing validation has completed.

### FAQ

**What limits the output?** The maxItems input caps output rows; its schema maximum is 10,000. Source availability and errors may yield fewer rows.

**Does it need a proxy, login, or API key?** The actor calls public Apple feeds and iTunes endpoints without an Apple login. No proxy input is defined.

**How is it priced?** PRICING.md proposes $0.00005 per successful item row. Diagnostic rows do not trigger the custom item event; the price is not yet configured in the Store.

**What happens on rate limits?** Requests retry transient failures and honor Retry-After where returned. Upstream throttling can still produce an error row.

**How fresh is the data?** Rows reflect the Apple response at retrieval; compare feedUpdatedAt and fetchedAt before treating a chart as current.

**Can a chart row have missing metadata?** Yes. Marketing feeds can omit ratings, prices, descriptions, and bundle IDs; lookup may supply metadata when Apple has it.

### Use with AI agents / MCP

An AI agent can call a published actor through the Apify MCP server or Apify API, pass the JSON input, then read the run’s default dataset. Check the actor’s published identifier and permissions in your Apify account.

After owner publication, add this actor to an [Apify MCP server](https://docs.apify.com/integrations/mcp) configuration and give your agent a bounded input. MCP integration has not been exercised for this draft.

Suggested instruction: “Fetch the first three US top free apps, keeping Apple IDs, ranks and source timestamps.”

```json
{"mode": "charts", "countries": ["us"], "charts": ["top_free_apps"], "resultsPerQuery": 3, "maxItems": 3}
```

Use the dataset link from the actor output to inspect rows. Check status and source freshness before using a result in analysis; do not treat a search position as a chart position.

### Development and verification

Uses the existing earn virtual environment; no packages were installed into it. Runtime requirements are apify and httpx.

From this actor directory in PowerShell:

```powershell
& 'C:/GritWork/earn/.venv/Scripts/python' -m pytest -q -m 'not live'
& 'C:/GritWork/earn/.venv/Scripts/python' -m pytest -q -m live
apify validate-schema
$env:APIFY_LOCAL_STORAGE_DIR = (Join-Path (Get-Location) 'storage')
$env:CRAWLEE_STORAGE_DIR = $env:APIFY_LOCAL_STORAGE_DIR
$env:ACTOR_TEST_PAY_PER_EVENT = 'true'
& 'C:/GritWork/earn/.venv/Scripts/python' -m src
```

The provided storage/key_value_stores/default/INPUT.json requests three rows from each of the five charts. The simulated charging log uses local test prices rather than the proposed Store price.

scripts/verify.py combines tests, schema CLI and a fresh local-run sample check. It preserves existing datasets and refuses to replace them. Run it with the same required Python interpreter after process execution is restored. A pass must be followed by the remaining behavior-contract probes before publication.

### Official sources

- [Apple RSS Builder](https://rss.marketingtools.apple.com/)
- [Apple iTunes Search API parameters and rate guidance](https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/iTuneSearchAPI/Searching.html)
- [Apple iTunes response fields](https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/iTuneSearchAPI/UnderstandingSearchResults.html)
- [Apify Python pay-per-event documentation](https://docs.apify.com/sdk/python/docs/concepts/pay-per-event)

Authentic response fixtures and their URLs are in tests/fixtures/SOURCES.json. Research receipts, schema checks and blocked execution evidence are in evidence/.

# Actor input Schema

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

Choose country charts, catalog keyword search, or lookup by Apple ID.

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

Two-letter storefront codes. Requests are repeated for each country. Examples: us, gb, de, tr. At most 10.

## `charts` (type: `array`):

Used in charts mode; repeated for each country and genre.

## `genreIds` (type: `array`):

Optional numeric Apple genre IDs, at most 10. Uses legacy official RSS. IDs depend on media: apps 6007 = Productivity; podcasts 1318 = Technology; books 9003 = Romance. Leave empty for overall marketing charts.

## `terms` (type: `array`):

Required in search mode. At most 50 non-empty terms, each at most 300 characters. Exact duplicates are removed.

## `ids` (type: `array`):

Required in lookup mode. Up to 100 numeric Apple IDs as strings, e.g. 284882215. Each ID produces an independent lookup for each country.

## `media` (type: `string`):

Used in search mode; lookup returns the kind of the requested ID.

## `resultsPerQuery` (type: `integer`):

At most 100 in charts mode, 200 in search mode. Apple may return fewer; no search pagination. Lookup retrieves one requested record.

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

Global cap including diagnostics. Input order determines which requests fit. Maximum 10,000.

## `concurrency` (type: `integer`):

Maximum in-flight jobs. iTunes request starts, including retries, are paced at least 3.1 seconds apart within this run.

## `maxRetries` (type: `integer`):

Retries network failures, 429, 5xx and invalid JSON with exponential backoff and bounded Retry-After. Permanent 4xx becomes a diagnostic.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each Apple HTTP attempt.

## Actor input object example

```json
{
  "mode": "charts",
  "countries": [
    "us"
  ],
  "charts": [
    "top_free_apps"
  ],
  "genreIds": [],
  "terms": [
    "notion"
  ],
  "ids": [
    "284882215"
  ],
  "media": "software",
  "resultsPerQuery": 100,
  "maxItems": 1000,
  "concurrency": 3,
  "maxRetries": 3,
  "requestTimeoutSecs": 30
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset of normalized Apple records and uncharged diagnostic rows.

# 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 = {
    "terms": [
        "notion"
    ],
    "ids": [
        "284882215"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("grit-77/apple-top-charts").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 = {
    "terms": ["notion"],
    "ids": ["284882215"],
}

# Run the Actor and wait for it to finish
run = client.actor("grit-77/apple-top-charts").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 '{
  "terms": [
    "notion"
  ],
  "ids": [
    "284882215"
  ]
}' |
apify call grit-77/apple-top-charts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,grit-77/apple-top-charts"
        }
    }
}
```

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/GdYJaiahoHee5nhb8/builds/5Os0ys4lx46piRiSE/openapi.json
