# Apple Podcasts Top Charts Scraper (All Countries & Genres) (`echolab/apple-podcasts-charts`) Actor

Scrape Apple Podcasts top charts for any country and genre, plus podcast search and lookup. Get rank, publisher, RSS feed URL, episode count, latest episode date and recent episodes. Official Apple data, no login.

- **URL**: https://apify.com/echolab/apple-podcasts-charts.md
- **Developed by:** [Echo Lab](https://apify.com/echolab) (community)
- **Categories:** Marketing, For creators, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 podcast 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?

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 Podcasts Top Charts Scraper (All Countries & Genres)

### What it does

An easy Apple Podcasts API alternative: scrape the **Apple Podcasts top charts** (iTunes podcast rankings) for any country and genre, search for shows, or look up known podcast IDs. Get each show's chart rank, publisher, **RSS feed URL**, episode count, latest episode date and recent episodes, exported to JSON, CSV or Excel. Built by Echo Lab for repeatable daily podcast chart tracking; each dataset item represents one podcast result.

- Country-specific overall and genre charts, up to 200 entries per chart.
- Batch iTunes lookup enrichment (up to 100 IDs per request).
- Public publisher, feed URL, artwork, genre, episode count and latest release metadata.
- Optional latest episode summaries and audio URLs without fetching podcast feeds.
- Search and lookup modes; no login or proxy required.

### Use cases

Podcast PR agencies can measure campaign chart movement. Networks and ad buyers can discover shows by market and category. Researchers can schedule daily snapshots and compare rank by `podcastId`, `chartCountry`, `chartGenreId` and `scrapedAt`. This Actor outputs snapshots, not computed historical rank changes.

### Input

| Field | Default | Description |
|---|---|---|
| mode | charts | charts, search or lookup |
| countries | \["us"] | Explicit ISO-2 codes for charts; UI prefill us and gb. No "all" country shortcut. |
| genres | \["all"] | Genre IDs or case-insensitive names; all means overall (26). Subgenre IDs are also accepted. |
| limit | 100 | 1–200 results per chart or search term |
| country | us | Storefront for search / lookup |
| searchTerms | \[] | Non-empty string array required in search mode |
| podcastIds | \[] | Non-empty array of numeric IDs or podcasts.apple.com URLs required in lookup mode |
| includeLatestEpisodes | 0 | 0–20 episodes attached to each result |
| requestDelayMs | 2500 | Global minimum request interval, 2500–60000 ms; includes retries and chart calls |

```json
{"mode":"charts","countries":["us","gb"],"genres":["all","Technology"],"limit":10,"includeLatestEpisodes":2}
```

Search example: `{"mode":"search","searchTerms":["science"],"country":"us","limit":5}`.
Lookup example: `{"mode":"lookup","podcastIds":["https://podcasts.apple.com/us/podcast/the-joe-budden-podcast/id1535809341"],"country":"us"}`.

#### Verified main Apple Podcasts genre IDs

Verified against [Apple's genre service](https://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres?id=26).

| ID | Genre |
|---|---|
| 26 | Podcasts (all / overall) |
| 1301 | Arts |
| 1321 | Business |
| 1303 | Comedy |
| 1304 | Education |
| 1483 | Fiction |
| 1511 | Government |
| 1512 | Health & Fitness |
| 1487 | History |
| 1305 | Kids & Family |
| 1502 | Leisure |
| 1310 | Music |
| 1489 | News |
| 1314 | Religion & Spirituality |
| 1533 | Science |
| 1324 | Society & Culture |
| 1545 | Sports |
| 1309 | TV & Film |
| 1318 | Technology |
| 1488 | True Crime |

### Output

```json
{"mode":"lookup","chartCountry":"us","chartGenreId":null,"chartGenreName":null,"chartRank":null,"scrapedAt":"2026-11-04T00:00:00Z","podcastId":"1535809341","name":"The Joe Budden Podcast","publisher":"The Joe Budden Network","appleUrl":"https://podcasts.apple.com/us/podcast/the-joe-budden-podcast/id1535809341","feedUrl":"https://rss.libsyn.com/shows/128607/destinations/2422538.xml","primaryGenre":"Music","genres":["Music","Podcasts"],"episodeCount":775,"latestEpisodeDate":"2026-10-28T09:00:00Z","contentAdvisoryRating":"Explicit","artworkUrl":"https://is1-ssl.mzstatic.com/image/thumb/Podcasts113/v4/f2/21/fa/f221fabd-017f-5125-633b-f1fe4f39802a/mza_182995249085044287.jpg/600x600bb.jpg"}
```

Illustrative lookup item; `tests/sample_output.json` holds a live chart result.

| Fields | Meaning |
|---|---|
| mode, scrapedAt | Mode and UTC collection timestamp |
| chartCountry | Requested ISO-2 storefront (not Apple's ISO-3 metadata country) |
| chartGenreId, chartGenreName | Chart category; null for search / lookup |
| chartRank | 1-based chart / search position; null for lookup |
| searchTerm | Present only for search |
| podcastId | Apple collection ID as a string |
| name, publisher | Show title and publicly listed publisher / brand |
| appleUrl, feedUrl, artworkUrl | Apple page, feed address (not fetched) and 600px artwork when available |
| primaryGenre, genres | Apple genre labels |
| episodeCount, latestEpisodeDate | Apple's track count and releaseDate; may be stale |
| contentAdvisoryRating | Apple's public rating |
| latestEpisodes | Only when requested: trackName, releaseDate, durationSeconds, episodeUrl, shortDescription (max 300 characters) |
| error, errorMessage | Only per-podcast failures: not_found, lookup_failed or episodes_failed |

Unavailable fields are null. A show appearing in multiple chart combinations creates separate items with independent ranks. Lookup inputs are deduplicated. Enrichment is always batched; optional episodes are cached per storefront / podcast within a run.

### Pricing

**Pay per result.** You pay only for podcasts saved to the dataset, plus a tiny per-run start fee; Apify platform usage is included in the price. The current price per 1,000 podcasts is shown on the Pricing tab of this page.

One podcast chart entry, search result or lookup result is one billed item. Attached episodes do not create extra items or charges. Per-podcast error items are also results and are billed. The Actor stops normally when the dataset event charge limit is reached. No synthetic error items are billed for failed charts or failed search queries without an identified podcast; these are logged.

### Tips / limits

- Apple's iTunes API is approximately limited to 20 requests/minute per shared IP. Default global spacing is 2.5 seconds; increase requestDelayMs to 3000 or higher if needed. Maximum three retries on 403/429/5xx/timeouts, with backoff and Retry-After support.
- Country codes are validated as ISO-2, but not every ISO country has an Apple storefront or charts. An unsupported country/chart may return no results or fail; check run logs. "All Countries" means explicit selection of available countries, not a bulk shortcut.
- The legacy [RSS chart endpoint](https://itunes.apple.com/us/rss/toppodcasts/limit=200/genre=1318/json) was verified to return 200 genre-specific entries and 200 overall entries. The [marketing RSS v2 endpoint](https://rss.marketingtools.apple.com/api/v2/us/podcasts/top/10/podcasts.json) works for overall charts but has no genre selector. It is used only as an overall fallback; it may support fewer entries. Genre chart failures never fall back to an incorrectly labelled overall chart.
- The descriptive Echo Lab User-Agent worked in live verification; no browser impersonation was required.
- Charts may contain fewer results than requested. Apple's Search API may reorder or cap results. Storefront lookup availability and latest-episode metadata can differ from the current chart. Empty charts/searches yield no dataset rows.
- Optional episodes can significantly increase runtime. Public publisher labels are returned as listed by Apple; no private identity inference is performed.

### Compliance & data source

Uses only official public Apple RSS, iTunes Search and Lookup endpoints. No login, cookies, browser, proxy, CAPTCHA solving or anti-bot bypass. Does not fetch or parse podcast feeds and does not output owner emails, phone numbers or private contact records. Episode descriptions are allowlisted, truncated and have email / phone patterns redacted. Publisher strings may be the public professional name of a creator, as displayed by Apple; no private individual data is gathered. Users are responsible for complying with Apple's terms and applicable laws.

### Support

Open an issue on the Actor's Issues tab.

### Local development

Install `requirements-dev.txt`, then run `python -m pytest -q`. Supply `storage/key_value_stores/default/INPUT.json` and run `APIFY_LOCAL_STORAGE_DIR=./storage python -m src`. Local storage is gitignored and excluded from the Docker build. Tests use small recorded Apple responses and never call the network.

More real output, worked pricing examples and a comparison with alternatives: https://echolab-tools.pages.dev/apple-podcasts-charts-api/

# Actor input Schema

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

Choose charts, search or lookup.

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

Explicit ISO-2 storefront codes. No all shortcut. Availability depends on Apple.

## `genres` (type: `array`):

Apple genre IDs or names; all means overall. Verified main IDs: 26 Podcasts; 1301 Arts; 1321 Business; 1303 Comedy; 1304 Education; 1483 Fiction; 1511 Government; 1512 Health & Fitness; 1487 History; 1305 Kids & Family; 1502 Leisure; 1310 Music; 1489 News; 1314 Religion & Spirituality; 1533 Science; 1324 Society & Culture; 1545 Sports; 1309 TV & Film; 1318 Technology; 1488 True Crime

## `limit` (type: `integer`):

Maximum entries per chart or search term (Apple may return fewer).

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

ISO-2 storefront for search and lookup.

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

Required non-empty list in search mode.

## `podcastIds` (type: `array`):

Required in lookup mode; numeric IDs or podcasts.apple.com URLs.

## `includeLatestEpisodes` (type: `integer`):

Attach up to this many episodes from Apple lookup; never fetches the RSS feed.

## `requestDelayMs` (type: `integer`):

Global spacing for all Apple requests, including retries. Minimum 2500 ms protects the shared IP rate limit.

## Actor input object example

```json
{
  "mode": "charts",
  "countries": [
    "us",
    "gb"
  ],
  "genres": [
    "all"
  ],
  "limit": 100,
  "country": "us",
  "searchTerms": [
    "technology"
  ],
  "podcastIds": [
    "1535809341"
  ],
  "includeLatestEpisodes": 0,
  "requestDelayMs": 2500
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items, one per result row.

# 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": "charts",
    "countries": [
        "us",
        "gb"
    ],
    "genres": [
        "all"
    ],
    "limit": 100,
    "country": "us",
    "searchTerms": [
        "technology"
    ],
    "podcastIds": [
        "1535809341"
    ],
    "includeLatestEpisodes": 0,
    "requestDelayMs": 2500
};

// Run the Actor and wait for it to finish
const run = await client.actor("echolab/apple-podcasts-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 = {
    "mode": "charts",
    "countries": [
        "us",
        "gb",
    ],
    "genres": ["all"],
    "limit": 100,
    "country": "us",
    "searchTerms": ["technology"],
    "podcastIds": ["1535809341"],
    "includeLatestEpisodes": 0,
    "requestDelayMs": 2500,
}

# Run the Actor and wait for it to finish
run = client.actor("echolab/apple-podcasts-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 '{
  "mode": "charts",
  "countries": [
    "us",
    "gb"
  ],
  "genres": [
    "all"
  ],
  "limit": 100,
  "country": "us",
  "searchTerms": [
    "technology"
  ],
  "podcastIds": [
    "1535809341"
  ],
  "includeLatestEpisodes": 0,
  "requestDelayMs": 2500
}' |
apify call echolab/apple-podcasts-charts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,echolab/apple-podcasts-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/QJRqyogOpUmNzNsSN/builds/PLsSIhdII84ViIPgz/openapi.json
