Config
Config is TOML. OAuth credentials live in private auth files under the app config directory, not in an OS keyring. On Unix, spotuify writes its config file with mode 0600, the auth directory with mode 0700, and auth files with mode 0600.
spotuify config pathSPOTUIFY_CONFIG=/tmp/spotuify.toml spotuify config pathManaged keys
Section titled “Managed keys”These keys are accepted by spotuify config get and spotuify config set.
| Key | Type | Default | Notes |
|---|---|---|---|
client_id | string | required | Spotify Developer app client id for the default PKCE flow |
client_secret | string | none | optional for PKCE; config get redacts it unless --reveal-secret is passed |
redirect_uri | string | http://127.0.0.1:8888/callback | must match the Spotify app settings |
player.backend | enum | embedded | only embedded (in-process librespot); Spotifyd/Connect-only backends were removed |
player.bitrate | number | 320 | 96, 160, or 320 |
player.device_name | string | none | preferred embedded/connect device name |
player.audio_output_device | string | system default | local audio output the embedded player renders to; match a name from spotuify audio-outputs |
player.normalization | bool | false | player normalization |
player.audio_cache_mib | number | 0 | embedded playback cache size |
player.pulse_props | bool | true | Linux Pulse/PipeWire app props |
player.event_hook | string | none | legacy alias for analytics.hook_command |
analytics.hook_command | string | none | shell hook command for qualified listens |
analytics.hook_timeout_ms | number | 5000 | hard timeout for the hook command |
cache.cover_cache_mb | number | 200 | cover-art cache cap |
cache.cover_cache_ttl_days | number | 30 | cover-art TTL |
notifications.enabled | bool | false | master switch for desktop notifications (needs the notifications build feature) |
notifications.summary | string | {track} | summary template ({track} {artist} {album} tokens) |
notifications.body | string | {artist} - {album} | body template |
notifications.on_track_change | bool | true | notify when the playing track changes |
notifications.on_pause | bool | false | notify on pause |
notifications.on_resume | bool | false | notify on resume |
notifications.on_skip | bool | false | notify on next/previous skips |
notifications.on_error | bool | true | notify on auth errors (deduped) |
discord.enabled | bool | false | Discord Rich Presence (needs the discord-rpc build feature + Discord running) |
discord.application_id | string | none | Discord application id for Rich Presence |
spotuify config get player.bitratespotuify config set player.bitrate 320spotuify config get client_secretspotuify config get client_secret --reveal-secretThe notifications.summary / notifications.body templates expand these
tokens from the current track: {track}, {artist}, {album},
{duration} (m:ss), and {progress} (m:ss). Defaults are
{track} / {artist} - {album}.
File-only sections
Section titled “File-only sections”Some config is loaded from TOML but not yet wired through config set.
[analytics]store_raw_queries = trueretention_progress_days = 90retention_events_days = 365retention_operations_days = 90daily_rollup_hour = 3hook_command = "/Users/me/bin/spotuify-listen-hook"hook_timeout_ms = 5000allow_file_credentials = falselastfm_api_key = "lastfm-api-key"lastfm_user = "your-lastfm-user"
[viz]enabled = truesource = "auto"target_fps = 30smoothing = 0.5noise_gate = 0.005color_scheme = "spotify-green"The visualizer ships on by default. Set enabled = false to opt out.
It animates from the embedded librespot sink tap; when no audio is
playing the spectrum draws a flat baseline. Toggle it off if you want
the player to use that vertical space for queue items instead.
analytics.lastfm_api_key and analytics.lastfm_user are defaults for
historical Last.fm import. CLI flags override them:
spotuify analytics import lastfm --user your-lastfm-user --from 2024-01-01Environment variables
Section titled “Environment variables”The default auth path is dev-app PKCE. Put client_id in config or set
SPOTUIFY_CLIENT_ID before login. First-party/keymaster auth is opt-in
for experiments with SPOTUIFY_USE_FIRST_PARTY=1.
SPOTUIFY_CLIENT_ID=... spotuify loginSPOTUIFY_CLIENT_SECRET=... spotuify loginSPOTUIFY_REDIRECT_URI=http://127.0.0.1:8888/callback spotuify loginSPOTUIFY_USE_FIRST_PARTY=1 spotuify loginLast.fm historical import also reads environment defaults:
SPOTUIFY_LASTFM_API_KEY=lastfm-api-key \SPOTUIFY_LASTFM_USER=your-lastfm-user \spotuify analytics import lastfm --from 2024-01-01 --format jsonFor local development and tests:
# Run the whole stack against fake Spotify data; never touches live# Spotify auth. Honored by the CLI, daemon, and TUI uniformly.SPOTUIFY_FAKE_SPOTIFY=1 spotuifyThe old proactive scope-drift credential read no longer runs at daemon startup. Scope checks now reuse the first real token read from the auth file.
Media controls (MPRIS on Linux, Now Playing on macOS, SMTC on Windows)
are on by default. Set SPOTUIFY_NO_MEDIA_CONTROLS=1 before starting the
daemon to turn them off entirely; on Windows this also skips the
hidden-window driver.
SPOTUIFY_NO_MEDIA_CONTROLS=1 spotuify daemon restartOne-shot overrides
Section titled “One-shot overrides”spotuify -o player.bitrate=160 play "ambient"spotuify -o player.normalization=true play "ambient"Overrides apply only to that command.