Skip to content
WolfWave
Developers

Stream Deck Control API

Control WolfWave from a same-Mac Stream Deck client. Protocol v3 command envelope, 12 actions, acks, and live queue and health broadcasts.

WolfWave exposes a command-capable WebSocket role only to clients on the same Mac. The official Stream Deck plugin, a Loupedeck profile, or your own local script can send commands and receive live state, so physical keys can skip tracks, hold the queue, or flip toggles without touching the app.

Just want to use a Stream Deck? Install the Stream Deck plugin instead — this page is the wire protocol for anyone building their own client. Announce actions and volume dials are planned follow-ups and not documented here.

Connect

Commands use the same listener as the overlay, but a separate role and secret:

  • URL: ws://127.0.0.1:8765 (port configurable in Settings → Stream Widgets).
  • Auth: present the Stream Deck Control Token as the WebSocket subprotocol wolfwave.control.<hex>. The server accepts this role only from a literal loopback peer and revalidates the selected handshake subprotocol.
  • Read-only separation: wolfwave.overlay.<hex> clients may receive state over the LAN but cannot run commands.

Copy Stream Deck Control Token from Settings → Stream Deck. There is no per-command token. See WebSocket security.

Send a command

Text frame, JSON:

{ "type": "command", "action": "skip", "protocol": 3, "args": {} }
  • type must be "command"; anything else is ignored (no ack).
  • protocol must be 3. A mismatch is rejected with error: "protocol", so an out-of-date client can show an "update me" state.
  • action must be one of the actions below; unknown actions get error: "unknown_action".
  • args is optional and unused by v3 actions (reserved for future parameters).

Every command gets an ack on the same connection:

{ "type": "ack", "action": "skip", "ok": true }
{ "type": "ack", "action": "skip", "ok": false, "error": "music" }

Actions

actionWhat it doesFail error
play_pauseApple Music play/pauseunavailable / music
skipSkip to the next trackunavailable / music
hold_queueHold the song-request queue
resume_queueResume the song-request queue
approve_nextApprove the first pending requestempty
clear_queueClear the request queue
block_currentAdd the current song to the blocklistempty
overlay_toggleHide/show the overlay cards (connection stays alive)
announce_songPost the current track to Twitch chattwitch / empty
reject_currentDrop the playing request and announce itunavailable / empty
block_requesterBlocklist whoever requested the playing songunavailable / empty
cycle_audienceAdvance the request audience, wrappingunavailable

discord_toggle, music_sync_toggle, and cycle_theme were removed in protocol v3. They flipped set-once preferences that never earned a key. A client still sending one gets error: "unknown_action" — and a v2 client gets error: "protocol" before that, since the version is checked first.

The plugin refuses to send clear_queue or block_requester unless the key is held. That is a plugin behaviour, not a protocol rule: the app runs either command whenever it arrives.

Live state broadcasts

WolfWave pushes two broadcast frames to every connected client, so counter and health keys render without polling:

{ "type": "queue_state", "data": { "count": 3, "pending": 1, "held": false, "audience": "everyone" } }
{ "type": "health", "data": { "music": true, "twitch": true, "discord": false, "overlay": true } }

They fire when the request queue changes, when Twitch connects or disconnects, when a new client connects, and after any successful command.

Try it from a terminal

With the server on and Music playing, connect from the same Mac with the control subprotocol and send a command. Using websocat:

websocat --protocol "wolfwave.control.<your-control-token>" ws://127.0.0.1:8765

Paste:

{"type":"command","action":"skip","protocol":3}

You should see the ack frame and hear the track skip. Leave the connection open to watch queue_state and health frames arrive as things change.

See also

On this page