Spotify Soloist Basic Integration

This guide shows how to observe and control Spotify Soloist from another local process. Use this pattern for local displays, buttons, automations, and dashboards that run on the same device. The Spotify Soloist WebSocket API is a local integration surface and does not provide browser-facing or network exposure security controls.

Warning:The WebSocket API has no built-in client authentication, authorization, TLS, Origin validation, CSRF protection, browser-facing security controls, or network exposure policy.

Start Spotify Soloist with WebSocket enabled

Start Spotify Soloist with --ws. For same-device integrations, bind to loopback:


_10
soloist \
_10
--device-name "Kitchen speaker" \
_10
--api-key "$SOLOIST_API_KEY" \
_10
--ws 127.0.0.1:0

The port value 0 lets the operating system choose a free port. For endpoint discovery, see WebSocket API.

Check status from a script

Use soloist ctl when a shell command is enough:


_10
soloist ctl status
_10
soloist ctl now
_10
soloist ctl queue
_10
soloist ctl pause
_10
soloist ctl play

For machine-readable now-playing state:


_10
soloist ctl now --json

For machine-readable queue state:


_10
soloist ctl queue --json

To connect to a known endpoint:


_10
soloist ctl -w 127.0.0.1:9090 now --json

Subscribe to playback events

Use soloist ctl trace to inspect the event stream before building your own client:


_10
soloist ctl trace

On connect, Spotify Soloist sends an auth_state event. If a user is already logged in, it also sends a playback_state snapshot.

When soloist ctl is not enough, a local process can connect to the WebSocket endpoint and exchange JSON text frames. See WebSocket API for endpoint discovery and WebSocket API reference for the complete event and command schema.

Send a control command

Control messages use type: "command" and a command name:


_10
socket.send(JSON.stringify({ type: 'command', command: 'pause' }));
_10
socket.send(JSON.stringify({ type: 'command', command: 'play' }));
_10
socket.send(JSON.stringify({
_10
type: 'command',
_10
command: 'set_volume',
_10
volume: 50,
_10
}));

Spotify Soloist acknowledges accepted control commands with a command_result event. Playback changes arrive asynchronously as events such as playback_changed, volume_changed, and position_sync.

Query commands return their own event types instead of command_result. For example, get_state returns playback_state, and get_queue returns queue_changed.

Track playback position

Use position_sync as a position anchor. It includes the server timestamp and position speed:


_10
{
_10
"type": "position_sync",
_10
"position": {
_10
"position_ms": 45000,
_10
"timestamp_ms": 1747654321000,
_10
"speed": 1.0
_10
}
_10
}

Between sync events, estimate the current position:


_10
function estimatePosition(sync) {
_10
const elapsed = Date.now() - sync.position.timestamp_ms;
_10
return sync.position.position_ms + elapsed * sync.position.speed;
_10
}

When playback is paused or stopped, position.speed is 0.0.

Security model

The Spotify Soloist WebSocket API is a local integration surface. It has no built-in client authentication, authorization, TLS, Origin validation, CSRF protection, browser-facing security controls, or network exposure policy.

The Spotify Soloist API key is only used to start the Spotify Soloist daemon.