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.3.0.tar.gz (23.8 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.3.0-py3-none-any.whl (26.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: spotifygraphqlconnector-0.3.0.tar.gz
  • Upload date:
  • Size: 23.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","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.3.0.tar.gz
Algorithm Hash digest
SHA256 31de7792ace920f74ee591a38e2400da96ae635496012c7d7342a0eadeb6ba85
MD5 318ffea97a76b7ef0c6617a458fd6b87
BLAKE2b-256 edaf3674ea95099926b927a547fe9fc19fbbfeae305e9b2eafd87501e6673d14

See more details on using hashes here.

File details

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

File metadata

  • Download URL: spotifygraphqlconnector-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 26.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.3 {"installer":{"name":"uv","version":"0.11.3","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.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d00df86c3f1a73ba5bcb2adea964d8ae61d0c3f2077572779e10bf71a4b59632
MD5 5c412e2790654d2022c838f8602ccc1d
BLAKE2b-256 7bbe85a40363fae21065ba12fbd5b13ce1f1dd95b29176462d6d1d888d65d146

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