Skip to main content

Spotify GraphQL Connector for Podcast Data

Project description

Spotify GraphQL Connector

PyPI

An unofficial Python connector for the Spotify Creators GraphQL API - the backend that powers the Spotify Creators dashboard (formerly Anchor).

Disclaimer: This connector uses an undocumented, internal API that may change at any time without notice. Use at your own risk.


Does it work for Anchor? For Spotify?

**Anchor (primary use case): Supported **

Anchor was rebranded to Spotify for Podcasters and then Spotify Creators. The dashboard at creators.spotify.com is now the only interface for managing Anchor-hosted podcasts. This connector talks directly to the GraphQL API behind that dashboard - it is the direct replacement for the anchor-connector, which stopped working when Spotify migrated its backend to GraphQL.

Shows hosted on Anchor/Spotify for Podcasters appear as hostingProvider: "S4P" and have full analytics access across all endpoints.

Non-Anchor Spotify shows: Partial Support

Shows hosted elsewhere (Apple, Megaphone, RSS feeds, etc.) appear as NonHostedShow with hostingProvider: "OTHER_THIRD_PARTY" or "MEGAPHONE". These shows are visible in the dashboard and return data from some endpoints (metadata, impressions, geo stats), but deep analytics like performance curves and consumption data are only available for S4P-hosted shows.

In short: if you were using anchor-connector, replace it with this connector.


Features

  • Single credential - only sp_dc and sp_key session cookies are required. Show URI and station ID are resolved automatically from your account.
  • Auto-authentication - performs the full PKCE OAuth 2.0 flow used by the Spotify Creators web app and transparently refreshes the bearer token before expiry.
  • Auto-pagination - get_all_episodes() fetches every page automatically.
  • Retry logic - exponential back-off on transient errors (429, 502, 503, 504) and automatic token refresh on 401.
  • Type-safe - fully annotated with a recursive JsonDict type alias; zero Any.
  • Native response shape - responses are returned exactly as the API sends them so consumers can adapt to the real data without a lossy mapping layer.
  • uv-powered - dependency management and packaging via uv.
  • 24 operations covering the full Spotify Creators analytics surface.

Requirements

  • Python 3.11+
  • uv

Installation

# As a library in your own project
uv add spotifygraphqlconnector

# Clone for development
git clone https://github.com/openpodcast/spotify-connector-graphql
cd spotify-connector-graphql/spotifygraphqlconnector
uv sync --all-groups

Credentials

You need two cookies from an active Spotify session: sp_dc and sp_key.

How to obtain them

  1. Open https://creators.spotify.com in your browser and log in.
  2. Open DevTools (F12 / ⌘ ⌥ I) → ApplicationCookieshttps://accounts.spotify.com.
  3. Copy the values of the sp_dc and sp_key cookies.

These cookies are typically valid for several months. When they expire you will see a CredentialsExpired exception - just grab fresh cookie values from your browser.


Configuration

All configuration is via environment variables:

Variable Required Default Description
SPOTIFY_SP_DC Yes - sp_dc cookie from a Spotify session
SPOTIFY_SP_KEY Yes - sp_key cookie from a Spotify session
SPOTIFY_SHOW_URI No auto Spotify show URI, e.g. spotify:show:1HaFboRBVORs2VCpNACYLn. Auto-resolved from the first S4P-hosted show on your account.
SPOTIFY_STATION_ID No auto Numeric Anchor/Spotify station ID. Auto-resolved from show metadata.
SPOTIFY_EPISODE_URI No auto Episode URI for per-episode analytics in the CLI. Auto-resolved from the first episode.
SPOTIFY_COUNTRY_CODE No US ISO 3166-1 alpha-2 country code for the registration endpoint.
cp .env.sample .env
# edit .env and fill in SPOTIFY_SP_DC and SPOTIFY_SP_KEY
source .env

Usage

CLI

source .env && uv run spotifygraphqlconnector

Runs every supported endpoint in sequence and logs the full JSON responses via loguru.

Library

from spotifygraphqlconnector import SpotifyGraphQLConnector

connector = SpotifyGraphQLConnector(
    sp_dc="your_sp_dc_value",
    sp_key="your_sp_key_value",
    # Optional - resolved automatically when omitted:
    # show_uri="spotify:show:1HaFboRBVORs2VCpNACYLn",
    # station_id="6248789",
)

# --- User / account ---
user        = connector.get_user_metadata()
shows       = connector.get_user_shows()           # basic: uri, name, stationId
shows_rich  = connector.get_shows_for_user()       # + authorName, category, description
user_shows  = connector.get_user_and_shows()
reg         = connector.get_user_registration(country_code="DE")

# --- Show metadata (show_uri auto-resolved) ---
show_type   = connector.get_show_type()
overview    = connector.get_show_overview_stats()
clips       = connector.get_show_clips()

# --- Show analytics ---
plays       = connector.get_show_spotify_stats(date_range_window="WINDOW_LAST_THIRTY_DAYS")
geo         = connector.get_show_geo_stats()                   # country breakdown
geo_city    = connector.get_show_geo_stats(result_geo="GEO_CITY")
demo        = connector.get_show_demographics_stats()          # age + gender
platform    = connector.get_show_platform_stats()              # app + device
impressions = connector.get_show_impressions_trend()           # daily + total
sources     = connector.get_show_impressions_sources()         # by source
discovery   = connector.get_show_audience_discovery()          # funnel + audience size
top_ep      = connector.get_show_top_episodes()                # all-time plays per episode

# --- Episode list (station_id auto-resolved) ---
page        = connector.get_episode_list(current_page=1, page_size=25)
all_eps     = connector.get_all_episodes()                     # auto-paginates

# --- Episode analytics ---
ep_uri = "spotify:episode:4fndadZdKayBwmsRQJ8rNR"
meta        = connector.get_episode_metadata_for_analytics(ep_uri)
perf        = connector.get_episode_performance_all_time(ep_uri)
streams     = connector.get_episode_streams_and_downloads(ep_uri)
plays_daily = connector.get_episode_plays_daily(ep_uri)
impressions = connector.get_episode_impressions_faceted(ep_uri)
consumption = connector.get_episode_consumption_all_time(ep_uri)
audience    = connector.get_episode_audience_size_all_time(ep_uri)

All methods return dict[str, JsonValue] in the native Spotify API response shape.


Supported Endpoints (24)

User / Account

Method Operation Description
get_user_metadata() getUserMetadata Authenticated user name and avatar
get_user_shows() WebGetUserShows All shows: uri, name, stationId, permissions
get_shows_for_user() getShowsForUser All shows with rich metadata: authorName, category, description, hostingProvider
get_user_and_shows() WebGetUserAndShows User profile + shows combined
get_user_registration() WebGetUserRegistration TOS / onboarding state
get_external_partner_id() WebGetExternalPartnerId External partner ID (e.g. for mParticle/Braze)

Show Metadata

Method Operation Description
get_show_type() WebGetShowTypeByUri Show type: PODCAST, AUDIOBOOK, ...
get_show_overview_stats() getShowOverviewStatsNRT Near-real-time aggregate streams/downloads total
get_show_clips() getShowClips Short-form video clips for a show
get_monetization_lifecycle_state() WebGetMonetizationLifecycleState Monetisation state (S4P shows only)

Show Analytics

All analytics methods accept date_range_window: "WINDOW_LAST_SEVEN_DAYS" · "WINDOW_LAST_THIRTY_DAYS" · "WINDOW_LAST_NINETY_DAYS" · "WINDOW_ALL_TIME"

Method Operation Replaces (anchor-connector)
get_show_spotify_stats() getShowOnSpotifyStats plays(), total_plays()
get_show_geo_stats() getShowAudienceAllPlatformsGeoStats plays_by_geo(), plays_by_geo_city()
get_show_demographics_stats() getShowAudienceDemographicsStats plays_by_age_range(), plays_by_gender()
get_show_platform_stats() getShowAudienceAllPlatformsStats plays_by_app(), plays_by_device()
get_show_impressions_trend() getShowImpressionsTrendStats impressions()
get_show_impressions_sources() getShowImpressionsSourcesStats n/a
get_show_audience_discovery() getShowAudienceDiscoveryStats audience_size(), unique_listeners()
get_show_top_episodes() getShowTopEpisodes total_plays_by_episode() ¹

¹ All-time only - Spotify does not expose a time-range parameter for this endpoint. Per-episode plays within a window: call get_episode_plays_daily(episode_uri) per episode.

Episode List

Method Operation Description
get_episode_list() WebGetIndexedEpisodeList Paginated, searchable episode list with sort/filter
get_all_episodes() WebGetIndexedEpisodeList All episodes auto-paginated

Episode Analytics

Method Operation Replaces (anchor-connector)
get_episode_metadata_for_analytics() getEpisodeMetadataForAnalytics episode_metadata()
get_episode_performance_all_time() getEpisodePerformanceAllTime episode_performance(), episode_aggregated_performance()
get_episode_streams_and_downloads() getEpisodeStreamsAndDownloads episode_plays()
get_episode_plays_daily() getEpisodePlaysDaily episode_plays()
get_episode_impressions_faceted() getEpisodeImpressionsFaceted n/a
get_episode_consumption_all_time() getEpisodeConsumptionAllTime n/a
get_episode_audience_size_all_time() getEpisodeAudienceSizeAllTime audience_size() (episode level)

Error Handling

from spotifygraphqlconnector import (
    SpotifyGraphQLConnector,
    CredentialsExpired,
    AuthenticationError,
    MaxRetriesException,
)

try:
    data = connector.get_show_spotify_stats()
except CredentialsExpired:
    # sp_dc / sp_key have expired - get fresh values from your browser
    print("Please update SPOTIFY_SP_DC and SPOTIFY_SP_KEY.")
except AuthenticationError as e:
    # Unexpected auth page structure - Spotify may have changed their flow
    print(f"Auth error: {e}")
except MaxRetriesException as e:
    # All retry attempts exhausted (network issues, persistent 5xx)
    print(f"Request failed after all retries: {e}")

Development

make install     # uv sync --all-groups
make check       # lint + typecheck + test (all at once)
make lint        # ruff check
make typecheck   # pyright
make test        # pytest
make fmt         # ruff format + ruff check --fix
make run         # run the CLI (requires .env sourced)

Adding a new operation

  1. Find the operationName and sha256Hash in your browser DevTools: DevTools → Network → filter by graph-pq → click a request → Payload tab.
  2. Add the entry to OPERATION_HASHES in types.py.
  3. Add a method in connector.py calling self._query("YourOperationName", ...).
  4. Add a call in __main__.py and a test in tests/test_connector.py.

Relationship to other connectors

This connector is part of the OpenPodcast project:

Connector API Auth Status
spotify-connector Spotify REST (generic.wg.spotify.com) PKCE OAuth (sp_dc + sp_key) Active
anchor-connector Anchor REST (podcasters.spotify.com) Session cookie (anchorpw_s) ⚠️ Deprecated - Spotify migrated to GraphQL
spotify-connector-graphql (this) Spotify Creators GraphQL (creators-graph.spotify.com) PKCE OAuth (sp_dc + sp_key) ✅ Active - Anchor replacement

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spotifygraphqlconnector-0.4.0.tar.gz (23.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spotifygraphqlconnector-0.4.0-py3-none-any.whl (26.7 kB view details)

Uploaded Python 3

File details

Details for the file spotifygraphqlconnector-0.4.0.tar.gz.

File metadata

  • Download URL: spotifygraphqlconnector-0.4.0.tar.gz
  • Upload date:
  • Size: 23.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.4 {"installer":{"name":"uv","version":"0.11.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for spotifygraphqlconnector-0.4.0.tar.gz
Algorithm Hash digest
SHA256 8b50591fca638e4180eefb8a74c44e82f0a128575a8fcbbd772d15c2af5c5b26
MD5 d162653e7e93eb33c2c9adb965d46a71
BLAKE2b-256 054f0ab844b236f5849234822b399e7a54448002c7f6a054b3ea67b1dc5d2fd4

See more details on using hashes here.

File details

Details for the file spotifygraphqlconnector-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: spotifygraphqlconnector-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 26.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.4 {"installer":{"name":"uv","version":"0.11.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for spotifygraphqlconnector-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d80d6b1e5d95f76c300c7a14d61594b0c5514837e8d79a6ad775558a2d335cd4
MD5 908cc47b8b641d2d972a9bc31419a9d0
BLAKE2b-256 8990f7207be14434f0e54edf352c22ec8d7557f87368ecc4be219d539af458ce

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page