WebSockets
Astro is StreamElements’ dedicated websocket gateway. It employs a publish-subscribe (pubsub) pattern to facilitate real-time data updates. Subscribe to topics such as channel activities, session updates, and overlay events to build tools that react to live stream events the moment they happen.
Connection
Section titled “Connection”Connect to the WebSocket endpoint:
wss://astro.streamelements.com/If reconnecting after a graceful shutdown, include the reconnect token as a query parameter:
wss://astro.streamelements.com/?reconnect_token=eyJhbGciOiJIUzI1NiIs...If the server is draining, it rejects new connections with 502 Bad Gateway.
If the connection rate limit is exceeded, it responds with 429 Too Many Requests and a Retry-After: 2 header.
Authentication
Section titled “Authentication”Subscribing to a topic requires a token, passed as data.token together with its data.token_type:
token_type |
What it is | Where to get it |
|---|---|---|
jwt |
A StreamElements JWT for your channel. | StreamElements dashboard: click your avatar in the top-right corner, select your channel name, choose the correct channel, then copy the token. |
apikey |
A StreamElements Overlay Token for your channel. | Same place as the JWT, on the StreamElements dashboard. |
oauth2 |
An OAuth2 access token, used in place of a JWT. | Supplied by your OAuth2 integration. |
Welcome Message
Section titled “Welcome Message”Immediately after connecting, the server sends a welcome message:
{ "id": "01J5KXYZ...", "ts": "2026-03-19T12:00:00Z", "type": "welcome", "data": { "message": "You are in a maze of dank memes, all alike.", "client_id": "01J5KXYZ..." }}Heartbeat
Section titled “Heartbeat”The server sends WebSocket PING frames every 30 seconds. The client must respond with PONG. If the server receives no pong within 70 seconds, it closes the connection.
These are WebSocket control frames, not application-level JSON messages. Most WebSocket libraries handle pong responses automatically.
Connection Lifecycle
Section titled “Connection Lifecycle”sequenceDiagram
participant Client
participant Edge as Edge Server
Client->>Edge: WebSocket Upgrade
Edge-->>Client: 101 Switching Protocols
Edge-->>Client: welcome message
Client->>Edge: subscribe {topic, token}
Note over Edge: Auth check
Edge-->>Client: response {success/error}
loop Every 30s
Edge-->>Client: PING
Client->>Edge: PONG
end
Edge-->>Client: message {topic, room, data}
Edge-->>Client: message {topic, room, data}
Client->>Edge: unsubscribe {topic, room}
Edge-->>Client: response {success}
rect rgba(43, 108, 255, 0.12)
Note over Client,Edge: Graceful Shutdown
Edge-->>Client: reconnect {token}
Client->>Edge: New connection + reconnect_token
Edge-->>Client: welcome (subscriptions restored)
end
Client-to-Server Request
Section titled “Client-to-Server Request”The following parameters are used in a client-to-server request:
| Parameter | Type | Required | Description |
|---|---|---|---|
type |
string |
Yes | Defines the type of request. Valid options are subscribe and unsubscribe. |
nonce |
string |
No | A unique identifier for the request. Echoed back in the response. |
data.topic |
string |
Yes | The topic to subscribe to. |
data.room |
string |
No | The room/channel to subscribe to. Defaults to "" (global). For unsubscribe, if omitted or empty, unsubscribes from all rooms for the topic. |
data.token |
string |
For subscribe |
The token used to authenticate the request. |
data.token_type |
string |
For subscribe |
Specifies the type of token. Valid options are jwt, oauth2, and apikey. |
Only text frames are accepted. Binary frames are ignored.
Here is an example of a subscribe request:
{ "type": "subscribe", "nonce": "req-001", "data": { "topic": "channel.activities", "room": "603abc123", "token": "eyJhbGc...", "token_type": "jwt" }}Here is an example of an unsubscribe request:
{ "type": "unsubscribe", "nonce": "req-002", "data": { "topic": "channel.activities", "room": "603abc123" }}To unsubscribe from all rooms for a topic, omit or send an empty room:
{ "type": "unsubscribe", "nonce": "req-003", "data": { "topic": "channel.activities" }}Rate Limits
Section titled “Rate Limits”| Scope | Limit | When exceeded |
|---|---|---|
| Connections | Connection rate limit per client. | The server responds with 429 Too Many Requests and a Retry-After: 2 header. |
Commands (subscribe/unsubscribe) |
1 command per 100 ms, burst of 100 per 10 seconds. | A response with error rate_limit_exceeded. Rate limit responses do not include a nonce. |
Server-to-Client Messages
Section titled “Server-to-Client Messages”| Parameter | Type | Present on | Description |
|---|---|---|---|
id |
string |
All messages | Unique message identifier (ULID). |
ts |
string |
All messages | Timestamp in RFC 3339 format. |
type |
string |
All messages | Message type: welcome, response, message, or reconnect. |
topic |
string |
message |
The topic the message was published to. |
room |
string |
message |
The room the message was published to. |
nonce |
string |
response |
Echoes the nonce from the original request. |
error |
string |
response (errors only) |
The error code when an error occurred. |
data |
object |
All messages | The message payload. |
Here is an example of a successful subscribe response:
{ "id": "01J5KXYZ...", "ts": "2026-03-19T12:00:01Z", "type": "response", "nonce": "req-001", "data": { "message": "successfully subscribed to topic", "topic": "channel.activities", "room": "603abc123" }}Receiving Messages
Section titled “Receiving Messages”When a message is published to a topic the client is subscribed to:
{ "id": "01J5M2AB...", "ts": "2026-03-19T12:05:00Z", "type": "message", "topic": "channel.activities", "room": "603abc123", "data": { "type": "follow", "provider": "twitch", "channel": "603abc123" }}The data field contains the payload from the publisher. See individual topic pages for payload details.
Error Codes
Section titled “Error Codes”All errors are returned as response messages:
{ "id": "01J5KXYZ...", "ts": "2026-03-19T12:00:01Z", "type": "response", "nonce": "req-001", "error": "err_bad_request", "data": { "message": "human readable description" }}| Error | Description |
|---|---|
err_internal_error |
Server-side failure. |
err_bad_request |
Malformed request, missing fields, limit exceeded, or invalid topic. |
err_unauthorized |
Authentication failed or permission denied. |
err_deadline_exceeded |
Authorization timed out. Retry the request. |
rate_limit_exceeded |
Command rate limit exceeded. |
invalid_message_type |
Unknown command type (not subscribe or unsubscribe). |
Reconnection
Section titled “Reconnection”Astro supports zero-downtime reconnection during graceful server shutdown.
-
The server sends a
reconnectmessage to each client:{"type": "reconnect","data": {"message": "The server is shutting down.","reconnect_token": "eyJhbGciOiJIUzI1NiIs..."}} -
The client saves the
reconnect_tokenand opens a new connection:wss://astro.streamelements.com/?reconnect_token=eyJhbGciOiJIUzI1NiIs... -
The new server verifies the token and restores all subscriptions automatically — no need to re-subscribe.
-
The client receives a
welcomemessage and resumes normal operation.
Invalid, expired, or tampered reconnect tokens cause the new connection to be closed immediately.
Troubleshooting
Section titled “Troubleshooting”Why are the messages not coming through? I received the message “successfully subscribed to topic”
Section titled “Why are the messages not coming through? I received the message “successfully subscribed to topic””Make sure you’re using the token for the specific platform from which you want to receive activities. If you have multiple accounts linked (Twitch, YouTube, Kick, etc.), switch to the correct account on the StreamElements dashboard (click your avatar in the top-right corner) and copy the token again.
I’m not receiving YouTube activities, and I’m using the correct token
Section titled “I’m not receiving YouTube activities, and I’m using the correct token”If your stream is set to private or unlisted, StreamElements cannot access it. Only public YouTube livestreams are supported.
How can I make sure I copied the correct token?
Section titled “How can I make sure I copied the correct token?”If you are using either a JWT or an Overlay Token (apikey), go to the StreamElements dashboard, click your avatar in the top-right corner > select your channel name, and choose the correct channel. After that, you can copy the correct token.