№ thread
← Threads
v1.3.0
Proven
ProvenNext.js + React (class components on the upload path, a headless listbox on the Artist Pick picker). Two backends: a same-origin JSON proxy at /c/api/*, and generic.wg.spotify.com which needs a Bearer token and serves the deep analytics.◉ claimed

artists.spotify.com

Spotify for Artists: read the label, upload Canvas, pitch to editors, set the Artist Pick

Authored by Webloom. License: proprietary. Last verified 8/21/2026.

Thread by Webloom — pricing TBD
№ 01 — what's inside

What's inside.

A summary of the workflows this Thread automates. The full recipe and the under-the-hood mechanics ship in the .thread.json file you install after purchase.

15 proven actions

Composable building blocks the engine can chain. No full end-to-end recipe yet.

why this Thread exists
  • 01READS, SURFACE ONE: the same-origin proxy. Call it from inside the page with fetch(..., {credentials:'include'}). /c/api/s4x-me/me is who is logged in. /c/api/s4x-home-service/<artistId> is followers, listeners, streams, which playlists drive traffic and per-track numbers. /c/api/release-moment-view/checklist-v2-proxy/<artistId> is the full catalog plus every action the panel considers unfinished. /c/api/side-nav/bff/<artistId> returns the roster as data, which beats scraping a[href*='/c/artist/'] out of the sidebar.
  • 02READS, SURFACE TWO: the deep analytics. They do NOT go through /c/api. The page calls generic.wg.spotify.com directly with a Bearer token it keeps in localStorage under the key 'auth-token'. Read that key, send it as Authorization: Bearer <token>, and the analytics answer 200 from inside the page. Without the header the same request dies as an opaque CORS failure, which is what makes this look impossible from the outside. A 400 saying 'Time filter not supported' means the token is FINE and you only forgot the query parameter.
  • 03DEEP ANALYTICS ROUTES, all under https://generic.wg.spotify.com and all taking <artistId>: /audience-engagement-view/v1/artist/<id>/stats?from_date=YYYY-MM-DD&to_date=YYYY-MM-DD (the time series), /gender?time_filter=28day, /gender-by-age?time_filter=28day, /locations?time_filter=28day, /top-cities?time_filter=28day, /active-audience-headlines, /info, /v2/artist/<id>/annotations?from=&to=. Also /fanatic-audience-segments/v2/artist/<id>/segments (the listener segments) and /fanatic-release-engagement/v2/artist/<id>/releases (engagement per release). The time filter is 7day, 28day or 12months, written with an underscore: time_filter, not time-filter. Do NOT guess route names, they 404 cleanly: open the matching tab once and read the real URLs off performance.getEntriesByType('resource').
  • 04THE READS DO NOT NEED A BROWSER AT ALL. Once you have the session cookie, every read above works from plain Python or curl, which means a cron can report on the label with no Chrome running. Grab the cookies once from the live browser over CDP using **Storage.getCookies**: Network.getAllCookies returns an empty list here and that reads exactly like 'the browser will not give them up'. You need sp_dc (httpOnly, so JavaScript alone cannot see it) plus sp_key. Send a normal browser User-Agent or Cloudflare rejects you before the cookie is even considered, and the rejection looks like a bad credential. The browser is still required for the three writes and for refreshing the analytics Bearer, which lives about an hour.
№ 02 — what installs

After purchase.

  • One artists.spotify.com.thread.json file in ~/.webloom/threads/
  • 15 proven actions the engine can run on demand
  • 0 preflight checks that halt execution if the site drifts
  • Free updates forever — the engine pulls newer versions from webloom.run every 6h
  • Refund window — 14 days through Polar, standard for digital goods