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": {} }typemust be"command"; anything else is ignored (no ack).protocolmust be3. A mismatch is rejected witherror: "protocol", so an out-of-date client can show an "update me" state.actionmust be one of the actions below; unknown actions geterror: "unknown_action".argsis 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
action | What it does | Fail error |
|---|---|---|
play_pause | Apple Music play/pause | unavailable / music |
skip | Skip to the next track | unavailable / music |
hold_queue | Hold the song-request queue | — |
resume_queue | Resume the song-request queue | — |
approve_next | Approve the first pending request | empty |
clear_queue | Clear the request queue | — |
block_current | Add the current song to the blocklist | empty |
overlay_toggle | Hide/show the overlay cards (connection stays alive) | — |
announce_song | Post the current track to Twitch chat | twitch / empty |
reject_current | Drop the playing request and announce it | unavailable / empty |
block_requester | Blocklist whoever requested the playing song | unavailable / empty |
cycle_audience | Advance the request audience, wrapping | unavailable |
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:8765Paste:
{"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
- Stream Deck — install and set up the official plugin.
- OBS Widget architecture — the overlay side of the same socket, including the now-playing message contract.
- Security — the token handshake.
OBS Widget
How WolfWave's now-playing OBS overlay is built. A Tailwind + TypeScript workspace that compiles into a single self-contained widget.html with smooth play/stop transitions.
Security
How WolfWave protects Twitch and local WebSocket credentials with macOS Keychain, App Sandbox, OAuth Device Code flow, and signed updates.