A Spotify player that runs in a single browser tab, built around radio as the default verb. Play any track and Needle grows an endless queue from it. You tune how that queue is built with sliders instead of trusting a black box.
It's one self-contained index.html: no build step, no backend, no dependencies beyond Spotify's Web Playback SDK.
- Search and play tracks, albums, artists and your playlists, with Spotify streaming in the tab via the Web Playback SDK.
- Radio from anything. Playing a track starts a radio. Its candidates come from the seed artist, similar artists, their Spotify tracks and your liked songs. When the queue runs low it fetches more, and it drifts toward artists you actually let play.
- A shuffle you can see and tune. Needle keeps its own play/skip history, and seven sliders shape every queue:
- Order: artist spread, freshness (push back recent plays), skip memory, liked boost, unheard boost
- Radio: reach (how far from the seed), underground (from household names to bands with a handful of listeners)
- Genre trailheads. Pick "punk", "drum and bass", "city pop" (or type any genre). Needle finds a good entry track for that genre and starts a station that stays in it.
- Playlist stations. Open a readable playlist and choose START PLAYLIST RADIO. Needle snapshots all loaded tracks and uses artists across the playlist, weighted by their share of distinct songs. The playlist mix slider targets originals versus related discoveries: 0% is discovery-only, 100% is originals-only, and intermediate values fill shortages from the available side.
- Change the mix in the source playlist or queue to rebuild upcoming station tracks. The current song, manually queued songs, and tracks explicitly moved to next stay in place.
Pmarks source originals andDmarks discoveries. Originals can recur in later batches; discoveries exclude every source song, including alternate versions. The snapshot and station mix survive reloads. - Discover. Seed artists in, unfamiliar related artists out, with an "adventure" control and a "not for me" ban list.
- Recently played merges Needle's own instant play log with Spotify's history from your other devices.
- Two-color theme, regenerated each session (◐ for a new one). Keyboard:
spaceplay/pause,/search,shift+←/→prev/next,←/→seek,sshuffle,llike,rradio.
You need Spotify Premium (Family plan members count). The Web Playback SDK refuses free accounts.
- Serve the folder over HTTP. Spotify only allows
https://redirect URIs or the loopback IP, so use127.0.0.1rather thanlocalhost:Or hostnpx http-server -a 127.0.0.1 -p 8888 -c-1
index.htmlon any static host with https. - Create an app at developer.spotify.com/dashboard:
- Redirect URI: the exact URL you open, e.g.
http://127.0.0.1:8888/. The setup screen shows it. - APIs used: Web API and Web Playback SDK.
- Redirect URI: the exact URL you open, e.g.
- Open the page, paste your app's Client ID, and log in.
- Optional: install it as an app (Chrome: ⋮ → Cast, save, and share → Install page as app; Edge: ⋯ → Apps → Install Needle) so it gets its own window and taskbar icon. In Chrome, adding the site under
chrome://settings/performance→ Always keep these sites active stops Memory Saver from unloading it while paused.
Login uses PKCE, so there's no client secret and no server. The Client ID, tokens, history and settings stay in your browser's localStorage. Nothing is sent anywhere except the services listed below.
Spotify's 2026 Web API changes for development-mode apps removed recommendations, related artists, popularity and follower counts. Needle uses open data instead:
| Source | Used for |
|---|---|
| Spotify Web API + Web Playback SDK | playback, search, library, playlists |
| ListenBrainz | similar artists, genre tag radio, artist listener counts (popularity) |
| MusicBrainz | resolving artist names to IDs (rate limited to 1 req/s) |
| Deezer API (JSONP) | related artists and fan counts for artists ListenBrainz doesn't know. Used only after a shared track title confirms it's the same artist |
- Playlists you don't own: Spotify only lets development-mode apps read the contents of playlists you own or collaborate on. Followed playlists (marked ▫) still play, but through Spotify's own queue and shuffle. Save a copy to get Needle's shuffle and radio.
- Five users per app: Spotify caps a development-mode app at five users. Each person should register their own Client ID.
- Queue changes: editing upcoming tracks does not resend playback mid-song. Needle hands off to the updated next track at the current track's end.
- Tiny artists: the smallest artists may not be on Spotify at all. Needle skips them, falling back to the seed artist's catalogue or your liked songs.
- Limited discovery supply: endpoints never substitute the other side. Intermediate mixes are targets rather than guarantees when eligible tracks run short. Playlist stations stay anchored to their source artists and neighbours; they do not fill from unrelated liked songs or refetch later playlist edits.
Run the synthetic playlist-radio regression suite with Node:
node --test tests/playlist-radio.test.cjsThe tests execute the application's inline script with inert browser/player boundaries. They cover mix selection, playlist snapshots, queue handoff, generation races, manual-track protection, persistence, and ordinary radio behavior without Spotify credentials or audio.