# Spotify Monthly Listeners & Followers Tracker - Exact Counts (`neverempty/spotify-monthly-listeners-tracker`) Actor

Monthly listeners and followers for any Spotify artist as the exact integers on the public artist page, plus the top tracks with play counts and the latest release. Turn monitoring on and later runs return an artist only when a count has moved.

- **URL**: https://apify.com/neverempty/spotify-monthly-listeners-tracker.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Social media, Automation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.60 / 1,000 artist returneds

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 Monthly Listeners & Followers Tracker

Monthly listeners and followers for any Spotify artist, as the **exact integers in the public artist page** (104,890,232 - not "104.9M"), plus the artist's top tracks with play counts and the latest release. With monitoring on, **an artist comes back only when its monthly listeners or followers have moved**, with the previous figure and the difference.

Paste artists as page URLs, `spotify:artist:` URIs or 22-character artist IDs, mixed in one list.

### What you get

One row per artist:

| Column | Meaning |
|---|---|
| `artistName`, `artistId`, `artistUrl` | The name Spotify returned for that ID, the ID and the page that was read |
| `monthlyListeners` | Monthly listeners, as an integer |
| `followers` | Followers, as an integer |
| `topTracks` | The top tracks listed in the page data, in page order: `rank`, `trackName`, `trackId`, `trackUrl`, `playCount`, `albumName`, `albumId`, `artistNames` |
| `topTrackName`, `topTrackPlayCount` | The first of those, as flat columns |
| `latestRelease` | `name`, `type` (ALBUM, SINGLE, ...), `year`, `albumId`, `url` |
| `externalLinks` | The artist's own links from the profile (Instagram, Facebook, ...) |
| `avatarUrl` | The largest avatar image in the page data |
| `pageCountry` | The country Spotify served the page for (see "Limits") |
| `input`, `scrapedAt`, `status` | What you typed, when it was read, `ok` for an artist row |

Monitoring columns (filled only in monitoring mode): `change` (`first-check` or `changed`), `isFirstCheck`, `changedFields`, `previousMonthlyListeners`, `monthlyListenersChange`, `previousFollowers`, `followersChange`, `previousCheckedAt`.

A value that is not in the page is `null`, never 0.

Measured on 2026-10-04 (the same figures came back from a home connection in Japan and from an Apify run in the US, minutes apart):

| Artist | monthlyListeners | followers | First top track | playCount |
|---|---|---|---|---|
| Taylor Swift | 104890232 | 165027667 | The Fate of Ophelia | 1705547569 |
| Drake | 94087456 | 117620422 | - | - |

### Why every row names the artist it read

The figures are taken only from the block of page data whose key is the artist ID you asked for. If the page does not contain that ID, no number is taken from it and you get an `unreadable` row instead. `artistName` is what Spotify returned for the ID, and `input` is what you typed, so a mix-up is visible in the row itself.

### Input

- **artists** - `https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02` (with or without `intl-xx/`, `?si=...` or the scheme), `spotify:artist:06HL4z0CvFAxyc27GXpf02`, or `06HL4z0CvFAxyc27GXpf02`. Get the link from **Share > Copy link to artist** in Spotify. Artist names are not searched. Track, album, playlist and embed links are rejected with an `invalid-input` row.
- **maxArtists** - with monitoring off, stop after this many artist rows.
- **monitoringMode**, **monitorMode**, **resetMonitoringState** - see below.
- **useProxy** - requests go directly to Spotify; a residential proxy is tried once only when Spotify answers HTTP 403 or 429.

### Monitoring mode

Turn **monitoringMode** on and schedule the Actor. It remembers each artist's two counts and, on later runs:

- an artist whose counts have not moved is **not returned as a row**; it still costs one check (see "What is charged"), and if no artist moved you get one free `no-change` row saying how many were compared;
- an artist whose counts moved comes back with the previous figures, the differences and `changedFields`;
- an artist it has never seen is returned once (`first-check`).

**monitorMode** chooses what counts as a change: `any-change` (monthly listeners or followers), `listeners-change`, or `followers-change`. Top-track play counts are reported in every returned row but do not trigger a return on their own.

Counts are remembered **per artist, not per list**, in a key-value store named `spotify-listeners-monitoring` in your own account, so adding an artist to the list does not return the others again. The remembered figure for an artist is updated only when a row for it was delivered, so each difference is measured against the last row you received. **resetMonitoringState** clears everything remembered.

Do not put the same artist in two schedules that run at the same moment: Apify's key-value store has no atomic update, so two runs finishing together can overwrite each other's record and an artist may be returned once more as `first-check`.

How often Spotify refreshes the monthly listener figure has not been measured by this Actor. If you schedule it more often than Spotify updates the page, the extra runs return `no-change`.

### What is charged

- **artist-returned** - one per artist row with `status: ok`.
- **artist-checked** - monitoring mode only: one per artist that was read and compared, whether or not it changed. Checks are charged together after the last artist was read, so a run that is aborted or times out while reading charges nothing. An artist that changed is charged one check and one row.
- Not charged: `no-such-artist` (Spotify answers 404 for the ID), `invalid-input`, `duplicate-input`, `unreadable`, `blocked`, `no-change`, `not-read` and `budget-reached` rows. There is no start fee and no monthly fee.

If you set a maximum total charge for a run, monitoring mode reads only as many artists as fit a check plus a row each, and lists the rest in a `not-read` row.

### Rows that explain instead of failing

| status | When |
|---|---|
| `no-such-artist` | Spotify answered 404 (Page not found) for the ID |
| `invalid-input` | The line is not an artist URL, URI or ID - or no artist was given |
| `duplicate-input` | The same artist appeared earlier in the list |
| `unreadable` | The page came back without the artist data, or its format changed. No figure is guessed |
| `blocked` | Spotify refused the request (403/429), or answered with a verification or login page |
| `not-read` | Lines that were not requested: after a `blocked` row or three unreadable pages in a row the run stops asking Spotify; also when `maxArtists` or the charge limit was reached |
| `no-change` | Monitoring: every artist was compared and none had moved |
| `budget-reached` | The run's maximum total charge was reached before every ready row could be delivered |

### Limits

- **Top tracks**: only the tracks listed in the artist page data are returned (5 on the pages measured on 2026-10-04). This is not a full discography or a play count for every track.
- **Country**: Spotify builds the page for the country of the connection (`pageCountry`). Monthly listeners and followers were identical from Japan and the US on 2026-10-04; the order of top tracks may differ by country.
- **Latest release** carries the year only, because that is all the page data holds, and is `null` for artists whose page data has no latest release (2 of the 5 artists measured on 2026-10-04).
- Only the public artist page (`open.spotify.com/artist/<id>`) is requested, one page per artist, about one request per second, with a User-Agent that identifies this Actor. No login, no Spotify API token, no embed pages. If Spotify stops serving the data in that page, rows become `unreadable` rather than wrong.
- This Actor is not affiliated with, endorsed by or sponsored by Spotify. Spotify's terms of use restrict automated collection from its service; decide for yourself whether your use is permitted before you run it.

# Actor input Schema

## `artists` (type: `array`):

Artist page URLs (https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02), spotify:artist: URIs, or the 22-character artist IDs. Only open.spotify.com/artist/<id> pages are requested. A track, album or playlist link is rejected rather than guessed, and an ID Spotify has no page for comes back as a "no-such-artist" row that is not charged. Artist names are not searched: use the link from the Share menu in Spotify.

## `maxArtists` (type: `integer`):

With monitoring off, the run stops after this many artist rows and lists the lines it did not read in a row that is not charged. Monitoring mode ignores this and checks every artist you listed.

## `monitoringMode` (type: `boolean`):

Off = return every artist you listed, charged per artist row. On = the counts are remembered and later runs return an artist only when its monthly listeners or followers differ from the remembered figure, together with the previous figure and the difference. In monitoring mode each artist that was read is charged as one check (artist-checked), and an artist that is returned is also charged as one artist row (artist-returned). The first monitoring run returns every artist once. Counts are remembered per artist, not per list, so adding an artist does not return the others again. Do not put the same artist in two schedules that run at the same moment.

## `monitorMode` (type: `string`):

Any change = the artist is returned when monthly listeners or followers differ from the remembered figure. The other two options watch only one of the two numbers. Top-track play counts are reported in every returned row but do not trigger a return on their own.

## `resetMonitoringState` (type: `boolean`):

Clears every remembered count for this Actor on your account, so the next monitoring run returns each artist once again. This affects all your monitoring runs, because counts are remembered per artist rather than per list.

## `useProxy` (type: `boolean`):

Requests go directly to Spotify. If Spotify answers HTTP 403 or 429, the page is requested one more time through an Apify residential proxy and, if it is refused again, the run stops asking and lists what it did not read. Turn this off to never use a proxy.

## Actor input object example

```json
{
  "artists": [
    "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
    "3TVXtAsR1Inumwj472S9r4"
  ],
  "maxArtists": 100,
  "monitoringMode": false,
  "monitorMode": "any-change",
  "resetMonitoringState": false,
  "useProxy": true
}
```

# Actor output Schema

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

One row per Spotify artist: name, artist ID and URL, monthly listeners and followers as the integers in the artist page data, the top tracks on the page with play counts, the latest release, external links and, in monitoring mode, the previous figures and the difference. Artist IDs Spotify has no page for, lines that are not artist links, pages that could not be read and runs where nothing changed come back as their own rows and are not charged.

# 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 = {
    "artists": [
        "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
        "3TVXtAsR1Inumwj472S9r4"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/spotify-monthly-listeners-tracker").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 = { "artists": [
        "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
        "3TVXtAsR1Inumwj472S9r4",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("neverempty/spotify-monthly-listeners-tracker").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 '{
  "artists": [
    "https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02",
    "3TVXtAsR1Inumwj472S9r4"
  ]
}' |
apify call neverempty/spotify-monthly-listeners-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/spotify-monthly-listeners-tracker"
        }
    }
}
```

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/UMPzYYlrrYevkwly5/builds/Zi60ScaeAVkTRKnI2/openapi.json
