Realtime Events

StreamerSonglist publishes realtime events over a WebSocket transport powered by Centrifugo. Subscribe to a streamer's channel(s) to receive push updates whenever the queue, songlist, play history, or saved queue changes — no polling required.

Endpoint

wss://events.streamersonglist.com/connection/websocket

Anonymous connections are accepted: you do not need to obtain a token to connect or subscribe.

Clients

You can integrate with any tool that speaks the Centrifugo client protocol:

  • An official centrifuge-* SDK in your language. See the SDK list — available SDKs include centrifuge-js, centrifuge-go, centrifuge-python, centrifuge-java, centrifuge-swift, and centrifuge-dart.
  • A native WebSocket client in your language, speaking the Centrifugo JSON framing directly. See the WebSocket transport and client protocol references.

Channels

Every event is published to a category-specific channel and the streamer's base channel. Subscribe to the base channel for a firehose of every event for a streamer; subscribe to a category channel to receive only the events you care about.

Channel PatternScopeVisibility
streamer:{streamerId}All public events for the streamerPublic
streamer:{streamerId}-{category}One category of public events for the streamerPublic
streamer-admin:{streamerId}All admin events for the streamerAdmin
streamer-admin:{streamerId}-{category}One category of admin events for the streamerAdmin

The {category} segment is one of: queue, play_history, saved-queue, song, action_log.

Event Envelope

Every publication has the following shape:

{
  "type": "<event_type>",
  "data": <payload or null>
}

When data is null, treat the event as a signal to refetch the relevant resource via the REST API.

Event Reference

Queue

Channels: streamer:{streamerId}, streamer:{streamerId}-queue

TypePayloadWhen it fires
queue_addQueueDetailsA song was added to the queue
queue_remove{ "id": number }A queue entry was removed or marked played
queue_updatenullThe queue order changed or an entry was edited

Play History

Channels: streamer:{streamerId}, streamer:{streamerId}-play_history

TypePayloadWhen it fires
play_history_addnullA new play history entry was created

Saved Queue

Channels: streamer:{streamerId}, streamer:{streamerId}-saved-queue

TypePayloadWhen it fires
saved_queue_updatenullThe saved queue was modified

Song

Channels: streamer:{streamerId}, streamer:{streamerId}-song

TypePayloadWhen it fires
song_addnullA new song was added to the songlist
song_updatenullA song's metadata was edited

Action Log

Channels: streamer-admin:{streamerId}, streamer-admin:{streamerId}-action_log

TypePayloadWhen it fires
action_log_addnullA new action log entry was created

Payload Types

QueueDetails

{
  id: number;
  note: string | null;
  createdAt: string; // ISO-8601
  songId: number | null;
  nonlistSong: string | null;
  streamerId: number;
  position: number;
  song: {
    title: string;
    artist: string;
    lastPlayed: string | null; // ISO-8601
    lastPlayedFrom: string;
    timesPlayed: number;
    comment: string | null;
    capo: string | null;
    attributes: { name: string; image: string | null }[];
  };
  requests: {
    id: number;
    name: string;
    amount: number;
    requestText: string;
    source: string;
    createdAt: string; // ISO-8601
    user: { username: string; platform: string } | null;
  }[];
}

Example: centrifuge-js

import { Centrifuge } from 'centrifuge';

const client = new Centrifuge('wss://events.streamersonglist.com/connection/websocket');

const sub = client.newSubscription(`streamer:${streamerId}-queue`);

sub.on('publication', (ctx) => {
  const event = ctx.data as { type: string; data: unknown };
  switch (event.type) {
    case 'queue_add':
      // event.data is QueueDetails
      break;
    case 'queue_remove':
      // event.data is { id: number }
      break;
    case 'queue_update':
      // refetch the queue from the REST API
      break;
  }
});

sub.subscribe();
client.connect();

To receive every event for a streamer in a single subscription, subscribe to streamer:${streamerId} instead and switch on event.type.

Example: native WebSocket

If you'd rather not pull in a Centrifugo SDK, you can speak the protocol directly over a plain WebSocket. The framing is documented in the Centrifugo client protocol reference — at minimum you'll need to send a connect command on open and a subscribe command for each channel, then read publication frames as they arrive.