# Spotify Global & Regional Charts Monitor (`fanndev/spotify-charts-monitor`) Actor

Scrape Spotify's Top 50 daily charts for 49 countries and Top Songs weekly charts for 14, plus the global weekly track, album and ARTIST charts. Reports rank movement between runs - climbers, fallers, new entries and drop-outs - because Spotify's chart playlists publish only today's order.

- **URL**: https://apify.com/fanndev/spotify-charts-monitor.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Stats:** 1 total users, 1 monthly users, 100.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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Spotify Global & Regional Charts Monitor

Scrape Spotify's **Top 50** daily charts across **49 countries**, the **Top
Songs** weekly charts across 14, and the global weekly **track, album and
artist** charts — and, because Spotify's chart playlists publish only today's
order, find out what actually *moved*.

Built for label analysts, radio programmers, music journalists and digital
marketers who need chart history rather than a single snapshot: schedule it and
every run reports climbers, fallers, new entries and drop-outs per territory.

No Spotify account, no API key, no browser.

***

### What you get

Per **`CHART_ENTRY`** row:

| Field | Notes |
| --- | --- |
| **`rank`**, `previousRank`, **`rankChange`**, **`entryStatus`** | `MOVED_UP` / `MOVED_DOWN` / `NO_CHANGE` / `NEW_ENTRY` |
| `trackName`, `artistName`, `artistNames`, `albumName` | The charting recording and everyone credited |
| **`playcount`** | Lifetime streams — **not in Spotify's official API** |
| `chartName`, `country`, `recurrence`, `chartLastUpdated` | Which chart, and when Spotify last recalculated it |
| `trackUrl`, `artistUrl`, `albumUrl`, `coverArt` | Links and artwork |

Plus a **`CHART_EXIT`** row for every track that was on the chart last run and
is not now, and one **`CHART_SUMMARY`** per chart — entry count, followers, how
many are new, how many climbed or fell, and the biggest climber.

From the public charts service you additionally get **album** and **artist**
charts, with Spotify's own `peakRank`, `appearancesOnChart` (weeks on chart) and
`consecutiveAppearances`.

***

### Quick start

```json
{
  "countries": ["GLOBAL", "US", "GB", "ID", "BR"],
  "recurrence": "daily",
  "includeGlobalWeeklyCharts": true,
  "trackRankMovement": true,
  "exportFormats": ["csv"]
}
```

***

### Two very different chart surfaces

**Country charts** come from Spotify's editorial chart playlists. They cover
around fifty territories and both cadences — but they are just ordered track
lists. Spotify tells you there are "3 new entries" and never which three.

**The public charts service** needs no credential whatsoever, and returns real
chart records: `previousRank`, `peakRank`, `entryStatus`, weeks on chart, for
tracks **and albums and artists**. Its limitation is coverage: global weekly
only. Per-country and historical charts there sit behind a login.

This actor reads both, and fills the gap in the first with its own memory.

***

### How movement tracking works

Each run writes the order it saw into a **named key-value store**
(`trackingStoreName`) and compares the next run against it.

- The **first run** is the baseline — entries are marked `entryStatus:
  "BASELINE"`, deliberately *not* `NEW_ENTRY`, because a real 50-track turnover
  should not look identical to a first run.
- Matching is on `trackUri`, so a re-release under a different id counts as a
  new entry — which is also how Spotify treats it.
- Use a **named** store, not the run's own: a run-scoped store is deleted with
  its run and every run would report `BASELINE`.

Daily charts recalculate once a day, so scheduling more often than daily
produces `NO_CHANGE` rows. Weekly charts update Thursdays.

***

### Cost

**One request per country chart**, one for the whole public charts service, plus
one to pick up an anonymous token. Ten countries plus the global charts is
twelve requests.

***

### Limits worth knowing

- **Viral 50 no longer exists.** Spotify retired it. Its old ids still answer
  HTTP 200 with an empty body, so the actor recognises them by name and says so
  in the error row rather than reporting an empty chart.
- **Weekly charts cover far fewer countries than daily ones** — 14 against 49.
  Asking for an unavailable country stops the run with the full list instead of
  silently returning nothing.
- **Chart playlists are invisible to search.** Spotify excludes them from every
  search surface, so they can only be reached by id. The catalogue in
  `src/catalog.py` was verified entry by entry; anything outside it can be
  passed as a `playlistUrls` entry.
- **`peakRank` and weeks-on-chart are only published on the public service**,
  and even there Spotify leaves them unset on many entries. Unset arrives as
  `0`, which is normalised to `null` so it cannot read as "peaked at 0".

***

### Output

Every run writes to the Apify dataset. Set `exportFormats` to also drop a
ready-made `spotify-charts.csv`, `.xlsx`, `.json` or `.ndjson` into the run's
key-value store.

See [CRAWLING_METHOD.md](CRAWLING_METHOD.md) for how the data is obtained.

# Actor input Schema

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

Two-letter country codes, or GLOBAL. Daily charts are published for GLOBAL, AE, AR, AT, AU, BE, BR, CA, CH, CL, CO, CZ, DE, DK, ES, FI, FR, GB, GR, HK, HU, ID, IE, IL, IN, IT, JP, KR, MA, MX, MY, NG, NL, NO, NZ, PE, PH, PL, PT, RO, SA, SE, SG, TH, TR, TW, US, VN and ZA. Weekly charts cover fewer territories: GLOBAL, AR, AU, BR, CA, DE, ES, GB, IN, IT, JP, KR, MX and US. An unavailable code stops the run with the full list rather than returning an empty chart.

## `recurrence` (type: `string`):

daily reads the Top 50 charts, recalculated every day. weekly reads the Top Songs charts, recalculated every Thursday and covering fewer countries.

## `includeGlobalWeeklyCharts` (type: `boolean`):

Read Spotify's public charts service as well. It needs no credential at all and is the only surface that publishes an ALBUM chart and an ARTIST chart, and the only one whose entries carry Spotify's own previousRank, peakRank, entryStatus and weeks-on-chart counters. It is limited to the three global weekly charts - per-country and historical charts there require a logged-in session.

## `playlistUrls` (type: `array`):

Any additional Spotify playlist to treat as a chart, for territories or editorial lists not in the built-in catalogue. Entries are ranked by playlist position.

## `maxEntriesPerChart` (type: `integer`):

Charts hold 50 entries. Lower this to capture only the top of each chart.

## `trackRankMovement` (type: `boolean`):

Spotify's chart playlists publish only today's order - nothing about climbing, falling or entering. Turn this on to remember each run's order and report previousRank, rankChange and entryStatus (MOVED_UP, MOVED_DOWN, NO_CHANGE, NEW_ENTRY) next time, plus a CHART_EXIT row for every track that fell off. The first run has nothing to compare against and marks its entries BASELINE.

## `trackingStoreName` (type: `string`):

Named key-value store holding the previous run's chart order. Scheduled runs pointed at the same name build one history; use different names to keep separate schedules apart.

## `emitChartSummary` (type: `boolean`):

One CHART_SUMMARY record per chart: entry count, follower count, when Spotify last recalculated it, how many entries are new, how many climbed or fell, and the biggest climber.

## `exportFormats` (type: `array`):

Besides the dataset, write ready-made files into this run's key-value store.

## `proxyConfiguration` (type: `object`):

Off by default and genuinely optional: neither endpoint this actor reads has a WAF or an IP block. Chart contents are the same from any exit IP, since the country comes from the chart id rather than from your address.

## Actor input object example

```json
{
  "countries": [
    "GLOBAL",
    "US",
    "ID"
  ],
  "recurrence": "daily",
  "includeGlobalWeeklyCharts": true,
  "maxEntriesPerChart": 50,
  "trackRankMovement": true,
  "trackingStoreName": "spotify-charts-monitor",
  "emitChartSummary": true,
  "exportFormats": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Every chart entry, drop-out, per-chart summary and any error records from this run.

# 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 = {
    "countries": [
        "GLOBAL",
        "US",
        "ID"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/spotify-charts-monitor").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 = { "countries": [
        "GLOBAL",
        "US",
        "ID",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fanndev/spotify-charts-monitor").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 '{
  "countries": [
    "GLOBAL",
    "US",
    "ID"
  ]
}' |
apify call fanndev/spotify-charts-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fanndev/spotify-charts-monitor"
        }
    }
}
```

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/gGEQOTs0OtLMZkpZn/builds/MMmauspBtHmfEB9os/openapi.json
