Summary
We created EventSub to be a transport-neutral solution for delivering real-time event notifications. Last fall, we released EventSub with support for sending notifications over webhooks. We are now planning to add support for sending notifications over WebSockets.
Motivation
Many developers build applications that run on computers and devices they don’t control. For example, a browser application to manage Channel Points rewards or a game that triggers a boss fight when there’s a Hype Train.
These applications need to create subscriptions and receive notifications from EventSub, but don’t always have a server available that can receive notifications over webhooks.
Proposed Solution
Applications will be able to receive EventSub notifications over WebSockets.
A developer creates a new WebSocket by connecting to wss://eventsub.wss.twitch.tv. Once connected, the first WebSocket message from Twitch to the client will include the WebSocket’s id, which will be used when creating EventSub subscriptions.
Creating, viewing, and deleting EventSub subscriptions for WebSockets will use the same EventSub APIs as webhooks, except the transport field will be different. To create a subscription for WebSockets, a developer specifies “method”: “websocket” and uses the id value they received earlier.
This flow is summarized in the following diagram:
If a WebSocket disconnects, all subscriptions associated with that WebSocket will be automatically disabled. If the developer recreates the WebSocket connection, they must recreate the subscriptions for that WebSocket.
Detailed Changes
Authorization
EventSub allows developers to create subscriptions using an application access token. With the introduction of WebSockets, EventSub will add support for creating WebSocket subscriptions with user access tokens.
Subscriptions created for an application (using an application access token) are separate from subscriptions created for users (using a user access token). They cannot create/view/delete subscriptions for one another. For example, a bad actor can’t use their user access token to delete subscriptions for another user.
WebSockets
The number of allowed WebSocket connections depends on the type of authorization token used. When using an application access token, the developer may create up to 100 WebSocket connections. When using a user access token, the developer may create up to 3 WebSocket connections per user.
Once a developer successfully connects, Twitch will send a welcome message over the WebSocket connection:
{
"metadata": {
"message_id": "befa7b53-d79d-478f-86b9-120f112b044e",
"message_type": "websocket_welcome",
"message_timestamp": "2019-11-16T10:11:12.123Z"
},
"payload": {
"websocket": {
"id": "34dc753d-2173-4645-8d76-39636b9c6d32",
"status": "connected",
"minimum_message_frequency_seconds": 10,
"connected_at": "2019-11-16T10:11:12.123Z"
}
}
}
This welcome message contains the WebSocket’s id
, which is used when creating EventSub subscriptions (described later). If no EventSub subscriptions are created for this WebSocket within 10 seconds, the WebSocket will be disconnected.
Every healthy WebSocket will receive a message at least every minimum_message_frequency_seconds
. Before this time limit, if no notifications have been delivered Twitch will fill the silence by sending a keepalive message:
{
"metadata": {
"message_id": "84c1e79a-2a4b-4c13-ba0b-4312293e9308",
"message_type": "websocket_keepalive",
"message_timestamp": "2019-11-16T10:11:12.123Z"
},
"payload": {
"websocket": {
"id": "34dc753d-2173-4645-8d76-39636b9c6d32",
"status": "connected",
"minimum_message_frequency_seconds": 10,
"connected_at": "2019-11-16T10:11:12.123Z"
}
}
}
If a WebSocket doesn’t receive any messages for longer than minimum_message_frequency_seconds
, the developer should assume the connection has died and create a new WebSocket.
The Twitch server that manages a WebSocket connection may need to go down, such as during maintenance. 30 seconds before this happens a message will be sent that contains a new url
, which the developer should immediately use to create a new WebSocket connection. All existing subscriptions will already exist at the new URL. After 10 seconds, the developer can disconnect from the old WebSocket.
{
"metadata": {
"message_id": "84c1e79a-2a4b-4c13-ba0b-4312293e9308",
"message_type": "websocket_reconnect",
"message_timestamp": "2019-11-18T09:10:11.234Z"
},
"payload": {
"websocket": {
"id": "34dc753d-2173-4645-8d76-39636b9c6d32",
"status": "reconnecting",
"minimum_message_frequency_seconds": 10,
"url": "wss://eventsub.wss.twitch.tv?...",
"connected_at": "2019-11-16T10:11:12.123Z",
"reconnecting_at": "2019-11-18T09:10:11.234Z"
}
}
}
Note that EventSub WebSockets only supports outgoing messages. If a developer sends data to Twitch over the WebSocket, they will be disconnected.
{
"metadata": {
"message_id": "84c1e79a-2a4b-4c13-ba0b-4312293e9308",
"message_type": "websocket_disconnect",
"message_timestamp": "2019-11-18T09:10:11.234Z"
},
"payload": {
"websocket": {
"id": "34dc753d-2173-4645-8d76-39636b9c6d32",
"status": "disconnected",
"disconnect_reason": "client_sent_inbound_traffic",
"minimum_message_frequency_seconds": 10,
"connected_at": "2019-11-16T10:11:12.123Z",
"disconnected_at": "2019-11-18T09:10:11.234Z"
}
}
}
EventSub
Creating a subscription for WebSockets uses the same API as for webhooks, except the transport
field describes the WebSocket connection that will receive notifications. Additionally, a WebSocket connection is limited to 100 subscriptions.
POST https://api.twitch.tv/helix/eventsub/subscriptions
-- Headers --
Client-ID: crq72vsaoijkc83xx42hz6i37
Authorization: Bearer C0BIYxs4JvnBWqvAmBvjfFc
Content-Type: application/json
-- Request Body --
{
"type": "channel.follow",
"version": "1",
"condition": {
"broadcaster_user_id": "12826"
},
"transport": {
"method": "websocket",
"id": "5dc6c6b3-ae73-4757-b029-c0b00017e8e3"
}
}
When a subscription is triggered, a notification is sent on the WebSocket connection:
{
"metadata": {
"message_id": "befa7b53-d79d-478f-86b9-120f112b044e",
"message_type": "notification",
"message_timestamp": "2019-11-16T10:11:12.123Z",
"subscription_type": "channel.follow",
"subscription_version": "1"
},
"payload": {
"subscription": {
"id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4",
"status": "enabled",
"type": "channel.follow",
"version": "1",
"cost": 1,
"condition": {
"broadcaster_user_id": "12826"
},
"transport": {
"method": "websocket",
"id": "5dc6c6b3-ae73-4757-b029-c0b00017e8e3"
},
"created_at": "2019-11-16T10:11:12.123Z"
},
"event": {
"user_id": "1337",
"user_login": "awesome_user",
"user_name": "Awesome_User",
"broadcaster_user_id": "12826",
"broadcaster_user_login": "twitch",
"broadcaster_user_name": "Twitch"
}
}
}
Note that the above is similar to the structure of a webhook HTTP request, where HTTP headers map to the metadata
section and the body is the payload
section.
If a subscription is revoked, a revocation message is sent on the WebSocket connection:
{
"metadata": {
"message_id": "84c1e79a-2a4b-4c13-ba0b-4312293e9308",
"message_type": "revocation",
"message_timestamp": "2019-11-16T10:11:12.123Z",
"subscription_type": "channel.follow",
"subscription_version": "1"
},
"payload": {
"subscription": {
"id": "f1c2a387-161a-49f9-a165-0f21d7a4e1c4",
"status": "authorization_revoked",
"type": "channel.follow",
"version": "1",
"cost": 1,
"condition": {
"broadcaster_user_id": "12826"
},
"transport": {
"method": "websocket",
"id": "5dc6c6b3-ae73-4757-b029-c0b00017e8e3"
},
"created_at": "2019-11-16T10:11:12.123Z"
}
}
}
There will also be an endpoint to view existing WebSocket connections.
GET https://api.twitch.tv/helix/eventsub/websockets
-- Headers --
Client-ID: crq72vsaoijkc83xx42hz6i37
Authorization: Bearer C0BIYxs4JvnBWqvAmBvjfFc
Content-Type: application/json
-- Response Body --
{
"data": [
{
"id": "5dc6c6b3-ae73-4757-b029-c0b00017e8e3",
"status": "connected",
"connected_at": "2019-11-16T10:11:12.123Z"
},
{
"id": "71728a2b-9ea9-4f91-ad31-3b104a9297f1",
"status": "client_disconnected",
"created_at": "2019-11-17T11:12:13.456Z",
"disconnected_at": "2019-11-17T12:13:14.567Z"
}
]
}
FAQ
Will there be support for creating multiple subscriptions in a single request?
Support for subscription batching is considered a separate feature from this RFC and thus would be implemented separately. It may appear before or after the release of WebSockets.
Can I create subscriptions over the WebSocket rather than the EventSub API?
No. Subscriptions are created using the EventSub API that exists today. In the future we may consider adding support for creating subscriptions over the WebSocket, but that feature won’t be available at launch.
How will subscription costs work with WebSockets?
In regards to EventSub Subscription Limit Changes, the logic for determining a subscription’s cost will be the same regardless of whether the transport is webhooks or WebSockets. However when using a user access token, the default value of max_total_cost will be 10 rather than the default of 10,000 for an application access token.