npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bzenky/spoti

v1.9.0

Published

A local-first command-line client for controlling Spotify

Readme

spoti

A local-first command-line client for controlling Spotify through Spotify Connect.

Website · npm · Releases

spoti is an independent project and is not affiliated with, endorsed by, or sponsored by Spotify AB.

spoti controls playback on an existing Spotify client or Connect device; it does not stream audio itself.

Requirements

  • Node.js 22 or newer
  • A Spotify developer application and client ID
  • Spotify Premium for playback-control commands
  • A Spotify client or Connect device available for playback

Spotify application setup

Create an application in the Spotify Developer Dashboard and register this exact redirect URI:

http://127.0.0.1:43821/callback

After installing spoti, save the application's client ID once:

spoti setup
spoti login

When developing from source, use:

npm run dev -- setup
npm run dev -- login

The setup command stores the public client ID in your local spoti configuration. For temporary sessions, CI, or an explicit override, you can still use:

export SPOTIFY_CLIENT_ID="your-client-id"

PowerShell:

$env:SPOTIFY_CLIENT_ID = "your-client-id"

The environment variable takes precedence over the stored value. To use a different local callback, register it in the same Spotify application and set:

export SPOTIFY_REDIRECT_URI="http://127.0.0.1:5000/callback"

PowerShell:

$env:SPOTIFY_REDIRECT_URI = "http://127.0.0.1:5000/callback"

The redirect URI must use HTTPS except for local development, where an explicit http://127.0.0.1 URI is allowed. Do not use localhost or wildcard redirect URIs. No client secret is needed or accepted by spoti; authentication uses Authorization Code with PKCE.

Installation

Install the latest published release from npm:

npm install --global @bzenky/spoti
spoti --help

Install for development

npm install
npm run build
npm link

Then verify the executable:

spoti --help

You can also run commands without linking:

npm run dev -- --help
npm run dev -- status

Usage

Run spoti with no command, or use spoti --help, to see the complete command overview:

spoti
spoti --help

Open the full interactive TUI explicitly:

spoti interactive
# alias: spoti i

The TUI opens on current playback, updates progress locally every second, and refreshes Spotify state every ten seconds while Player or Lyrics is active. The refreshIntervalMs setting controls CLI watch mode, not TUI polling.

The Player displays Spotify album artwork when the terminal supports Kitty graphics, iTerm2 inline images, or Sixel and the window is at least 64 columns wide and 18 rows tall. Examples include Kitty, Ghostty, iTerm2, Konsole, Rio, and XTerm. Windows Terminal requires a version with Sixel support. WezTerm, Warp, and VS Code have protocol limitations that can affect rendering; in VS Code, enable terminal.integrated.enableImages and set terminal.integrated.gpuAcceleration to on.

GNOME Terminal, macOS Terminal.app, and the legacy Windows console keep the text-only playback view. Smaller windows also hide artwork. Compatibility depends on the terminal app and version, rather than the operating system; see the image renderer's compatibility table for protocol details.

Use these keyboard controls:

1       Player
/       Search
q       Queue
d       Devices
l       Library
y       Lyrics
?       Help

Space   play or pause (Player)
n       next track (Player)
p       previous track (Player)
← / →   seek backward or forward 10 seconds (Player)
- / +   lower or raise volume by 5% (Player)
s       toggle shuffle (Player)
r       cycle repeat off, track, and context (Player)
a       add the current track to a playlist (Player)
Ctrl+R  refresh now (Player)

Esc     back one level, or exit from Player
x       exit from Player or Help
Ctrl+X  exit from Search, Queue, Devices, Library, Lyrics, or the playlist picker
Ctrl+C  exit from any screen

On Search, type a query and press Enter. Use up/down to select a result, then Enter to play it. For a selected track, press a to choose a playlist and add the track without starting playback. Tab or left/right switches between tracks, albums, artists, and playlists. Search results are cached for the active TUI session, stale requests are cancelled when the query changes, and leaving Search cancels an in-flight search or playback request.

Queue displays the current item and Spotify's upcoming items. Press a to search for a track, use up/down to select it, and press Enter to add it. Press r to refresh. Spotify does not expose arbitrary queue removal or position jumping, so the TUI does not offer those actions.

Devices lists all Spotify Connect devices with active status, type, volume, and the saved default. The active device is selected automatically. Use up/down and Enter to transfer playback; pressing Enter on the active device is a safe no-op. Press s to set or clear the selected default device, i to show or hide device IDs when names are duplicated, and r to refresh. Restricted devices or entries without a usable ID remain visible with an explanation but cannot be selected for transfer.

On Devices, press o to open the local Spotify app without leaving the TUI. spoti refreshes the device list after requesting the launch. If your device has not appeared yet, wait for Spotify to open and press r to refresh again. Spotify must be installed and registered to handle spotify: links. To use a remote device, open Spotify on that device and refresh the list.

Library uses Tab or left/right to switch among Playlists, Liked, Recent, Top tracks, and Top artists. Use up/down and Enter to open a playlist or play the selected track or artist; n and p navigate lazily loaded pages. In Top tracks or Top artists, press t to cycle between the last 4 weeks, about 6 months, and about 1 year. In a playlist you own, press e to edit its details or move the selected track to a one-based position. Previously visited pages remain cached for the TUI session, and Esc returns from playlist tracks to the playlist list before returning to Player.

Press y from Player to open lyrics for the current track. When synchronized lyrics are available, the TUI follows and highlights the current line; use up/down to scroll manually and f to resume following. The Player playback shortcuts also work in Lyrics: Space to play/pause, n/p to change tracks, left/right to seek, -/+ for volume, s for shuffle, r for repeat, and Ctrl+R to refresh playback. Press Enter to retry a lyrics loading error. Lyrics are loaded live from LRCLIB and are not stored persistently.

All command-driven usage remains available. The interactive command requires an interactive stdin and stdout; outside a TTY it prints its command help instead of starting Ink.

Authenticate once through Spotify's browser authorization page:

spoti login
spoti status

Control playback. Quotes are optional for ordinary multi-word queries because spoti combines the remaining command arguments. Use quotes when a query contains shell-special characters such as &, *, ?, or parentheses.

spoti now
spoti now --short
spoti now --watch
spoti open
spoti play
spoti play Numb
spoti play Fear of the Dark
spoti play Numb --first
spoti play Numb --watch
spoti play Numb --no-watch
spoti pause
spoti resume
spoti next
spoti previous
spoti volume
spoti volume 50
spoti volume +10
spoti volume -10
spoti shuffle
spoti shuffle on
spoti shuffle off
spoti repeat
spoti repeat off
spoti repeat track
spoti repeat context
spoti lyrics
spoti lyrics Numb Linkin Park
spoti lyrics Numb --first

Manage playback devices:

spoti launch # alias: spoti app
spoti device
spoti device 2
spoti device "My Computer"
spoti device "My Computer" --default

spoti device with no selector lists available Spotify Connect devices and prints how to switch to one. Pass a displayed one-based number, exact device name, or Spotify device ID to transfer playback. If no devices are listed, open Spotify on a device (or run spoti launch on this computer), then run spoti device again. spoti launch asks your operating system to open the locally installed Spotify app through its spotify: URI handler. It cannot wake Spotify on remote devices, but can make your current computer available to Spotify Connect before you run spoti device or spoti interactive.

Add --default to save the selected device as the fallback when no device is active. You can also manage it directly with spoti config set defaultDevice "My Computer" and spoti config unset defaultDevice. An already-active device always takes precedence over the saved default.

When playback reports no active device, spoti play and spoti resume retry the one active controllable device if Spotify reports one, or the only controllable device when exactly one is available. If several inactive devices are available, spoti asks you to select one explicitly.

Seek within the current track:

spoti seek 1:30
spoti seek +30
spoti seek -10
spoti restart # alias: spoti rst

View the queue or search for a track to add. When Spotify represents an otherwise empty queue by repeating only the current track, spoti reports the queue as empty instead of printing duplicate entries:

spoti queue
spoti queue "Faint"
spoti queue "Faint" --first

Search without starting playback:

spoti search "Breaking the Habit"
spoti search "Breaking the Habit" --limit 5

Search, inspect, and play Spotify contexts:

spoti album "Meteora"
spoti artist "Linkin Park"
spoti playlists
spoti playlist 1
spoti playlist "Workout"
spoti playlist-create "Road trip"
spoti playlist-create "Release radar" --public
spoti playlist-edit "Road trip" --name "Road trip 2026"
spoti playlist-edit "Road trip" --description "Songs for the drive" --private
spoti playlist-move "Road trip" 12 3
spoti add
spoti add 1
spoti add "Workout" --search "Numb"
spoti add "Workout" --search "Numb" --first
spoti add "Workout" --first
spoti play track "Numb"
spoti play album "Meteora"
spoti play artist "Linkin Park"
spoti play playlist "Workout"
spoti play playlist 1

spoti playlist-create <name> creates a private playlist by default; pass --public to create a public one. spoti playlist-edit <playlist> updates a playlist you own: provide --name, --description, --public, or --private (the visibility options cannot be combined). spoti playlist-move <playlist> <from> <to> moves an item between one-based positions in a playlist you own; quote playlist names containing spaces. The TUI offers the same operation from Library: open a playlist, select a track, press e, then m, and enter its destination position. spoti add adds the currently playing track to an existing playlist. Pass --search <query> to select a searched track instead; --first chooses the first track and matching playlist without prompting. In an interactive terminal, omit the playlist to browse lazily loaded pages; otherwise pass a displayed number or playlist name. The TUI offers the same flow with a from Player or for a selected track in Search. These features require Spotify playlist-modification scopes. If your saved credentials lack those permissions, run spoti login again when prompted.

User playlists preserve Spotify’s order so their global displayed numbers remain stable across pages. A displayed number can be reused with spoti playlist <number> or spoti play playlist <number>, including numbers beyond the first page.

In an interactive terminal, spoti album can play the entire album or a selected track after showing its details. spoti artist can play the artist context or let you browse the artist’s albums lazily, with each fetched page ordered from newest to oldest by release date. From an album selected through an artist, choose Back to albums to reuse that list and select another release; pressing Enter in the album browser returns to the artist actions. spoti playlist can start the selected playlist or browse its tracks across all available pages and play one directly. Non-interactive runs remain display-only and never start playback implicitly.

spoti play without a query resumes playback, or reports that playback is already running. Watch flags and the saved watch preference apply to this form too.

spoti play <query> remains shorthand for track playback. The words track, album, artist, and playlist are treated as explicit types when followed by another argument. For a track query that starts with one of those reserved words, use spoti play track <query> (or quote the complete query as one shell argument). Context commands support --first to skip interactive selection.

Manage and inspect your Spotify library:

spoti liked
spoti liked --limit 10
spoti like
spoti unlike
spoti recent
spoti recent --limit 10
spoti top tracks
spoti top artists --range short

spoti like and spoti unlike operate on the currently playing track. Episodes, advertisements, local files, and unavailable items are ignored safely. spoti top tracks|artists browses Spotify's affinity rankings, which estimate your top items over a time window rather than report exact play counts. Use --range short|medium|long (default medium): short covers about 4 weeks, medium about 6 months, and long about 1 year. The CLI page title shows the selected range. Artist albums, spoti playlists, spoti liked, spoti recent, and spoti top use paginated browsers: enter a displayed number to select it, n for the next page, p for the previous page, or press Enter to go back or leave playback unchanged. Pages are requested only when needed, and previously visited pages are cached for the duration of the command. Short Spotify rate limits are retried automatically with bounded backoff; when Retry-After exceeds five seconds, spoti exits immediately with a human-readable retry time instead of holding the terminal on a spinner. For collection commands, --limit controls the page size from 1 to 50; artist album pages use Spotify’s maximum of 10. Non-interactive runs display only the first page and never start playback implicitly.

Check for updates or install the latest npm release:

spoti update --check
spoti update

spoti now --short prints a single line such as ▶ Linkin Park — Numb and exits, making it suitable for prompts and status bars. spoti open opens the current track's Spotify page in the system browser or registered Spotify handler.

spoti update asks for confirmation before installing the exact version returned by the update check. It never installs an update silently. Normal commands use a cached update result and refresh it in a detached process at most once every 24 hours, so npm availability does not delay or break Spotify controls.

Remove local credentials:

spoti logout

When attached to an interactive terminal, spoti play <query> asks you to select a result. In non-interactive usage it chooses the first result automatically; --first makes that behavior explicit.

Watch mode continuously refreshes the current track and progress until Ctrl+C is pressed. --watch enables it for one command, while --no-watch overrides a saved preference. Run spoti volume, spoti shuffle, or spoti repeat without a value to inspect the current state. Pass a volume value or use spoti shuffle on|off or spoti repeat off|track|context to change it.

Command aliases

Common aliases include:

i     interactive  p     play       pa    pause
ly    lyrics       r     resume       np    now        q     queue      s     search
vol   volume       sk    seek        rst  restart     alb   album
art   artist       dev   device     app   launch
pl    playlist     pls   playlists   rep   repeat
rec   recent       n     next        prev  previous
tt    top tracks   ta    top artists

devices and devs also remain aliases for device.

Shell completions

Generate a static completion script without invoking Spotify or making network requests:

spoti completion bash
spoti completion zsh
spoti completion fish

For the current shell session:

source <(spoti completion bash) # Bash
source <(spoti completion zsh)  # Zsh
spoti completion fish | source  # Fish

Interactive network operations display a spinner on stderr. Indicators remain disabled outside a TTY.

Terminal formatting

Interactive terminals use restrained styling for names, metadata, headings, and playback progress. Redirected output remains plain text. Set the standard NO_COLOR environment variable to disable decorative styling:

NO_COLOR=1 spoti now

PowerShell:

$env:NO_COLOR = "1"
spoti now

Spotify-provided names and descriptions are normalized to safe single-line terminal text before display.

Lyrics and LRCLIB

Spotify's Web API does not provide lyrics. spoti lyrics and the TUI Lyrics screen therefore query the community-operated LRCLIB service using the selected track's title, artists, album, and duration. This metadata is sent to LRCLIB only when lyrics are requested. spoti identifies itself through the required User-Agent and performs bounded retries for short 429 and 503 responses. Lyrics and missing-result lookups are cached in memory for the running process, with up to 50 entries; they are never written to disk.

Lyrics are displayed for personal, immediate use with visible LRCLIB attribution. LRCLIB's software license does not grant redistribution rights to copyrighted song lyrics; do not treat displayed lyrics as freely licensed content. Availability and synchronization depend on LRCLIB's community data, and some tracks may be missing, instrumental, or incorrectly matched.

Configuration

View all settings:

spoti config

Read, update, or reset settings:

spoti config get spotifyClientId
spoti config set spotifyClientId "your-client-id"
spoti config get watchAfterPlay
spoti config set watchAfterPlay true
spoti config set refreshIntervalMs 2000
spoti config unset spotifyClientId
spoti config path
spoti config reset

Available settings:

| Setting | Default | Description | | --- | ---: | --- | | spotifyClientId | null | Public Spotify application client ID saved by spoti setup. | | defaultDevice | null | Exact Spotify Connect device name or ID used when no device is active. | | watchAfterPlay | false | Keep spoti play open in watch mode after playback starts. | | refreshIntervalMs | 1000 | Watch refresh interval from 1000 to 30000 milliseconds. |

Command flags take precedence over saved configuration. Application preferences are stored in $XDG_CONFIG_HOME/spoti/config.json, or ~/.config/spoti/config.json when XDG_CONFIG_HOME is not set. This path convention is currently used on Linux, macOS, and Windows; run spoti config path to print the exact path for the current system.

Credentials

Credentials are stored locally in:

$XDG_CONFIG_HOME/spoti/credentials.json

or, when XDG_CONFIG_HOME is not set:

~/.config/spoti/credentials.json

On POSIX systems, the credentials file is created with user-only permissions (0600). Access tokens refresh automatically using the environment client ID when present, otherwise the client ID saved by spoti setup. New installs request the minimum scopes for supported features; when a feature adds a new scope, existing installations are asked to run spoti login again to authorize it. Top tracks and artists require Spotify's user-top-read scope. Never provide or store a Spotify client secret in spoti.

Spotify API policy

spoti uses Spotify data only for immediate command output and playback control. It does not persist Spotify catalog content, use Spotify data for machine-learning training, or download audio. Spotify content and links remain attributed to Spotify.

Endpoint work must be checked against Spotify's official OpenAPI specification and Developer Terms.

Spotify quota and rate limits

Spotify can return HTTP 429 for two related situations:

  • a normal short-term rate limit, which can usually be retried after the response's Retry-After delay
  • development quota exhaustion, reported by Spotify as QUOTA_EXCEEDED, which may have a much longer delay

spoti automatically retries only bounded waits of five seconds or less. Longer waits exit immediately and show when to try again. Development quota cannot be manually cleared from spoti.

Spotify development mode currently supports a small allowlist of users and requires the app owner to have Premium. Quota may be shared by development-mode applications owned by the same Spotify developer account, so creating another application under that account is not a reliable way to obtain fresh quota. Extended quota access is subject to Spotify's eligibility and application requirements.

Each user should create their own Spotify developer application and save its public client ID:

spoti setup
spoti login

This avoids putting all public spoti users on one developer application's quota. A client ID is public configuration; never provide a client secret to spoti.

See Spotify's official documentation for current details:

Development

npm run typecheck
npm run lint
npm test
npm run build

Releases

GitHub Releases are created automatically when a version tag is pushed. Maintainers release in this order so npm publication and the GitHub Release cannot drift:

1. Update package.json, package-lock.json, and CHANGELOG.md.
2. Run npm run verify and npm run smoke:package.
3. Commit, push main, and wait for cross-platform CI.
4. Run npm publish --access public and verify the registry version.
5. Create and push the matching vX.Y.Z tag.
6. Verify the GitHub Release workflow and attached checksums.

The tag must exactly match the package version. Never push a release tag before npm publication succeeds. The release workflow independently verifies the project, installs the packed artifact, attaches the npm tarball and a SHA256SUMS file, and generates release notes from Git history.

Current scope

spoti provides a command-driven CLI and an interactive TUI for Spotify Connect controls, search, paginated library browsing, Top rankings, playlist creation and editing, track insertion and reordering, and LRCLIB lyrics. It also includes local Spotify launch, album artwork in supported terminals, PKCE authentication, quota-aware requests, update checks, shell completions, a configurable default device, and compact status output. Cross-platform CI checks both the source and packed installation. See CHANGELOG.md for release history.