PubSub

Twitch PubSub is a system that allows back-end services to broadcast realtime messages to clients. Example applications include:

  • An instant messaging service sending a instant messages between friends.
  • A back-end video system pushing real-time viewer count updates to video players.
  • A presence system broadcasting a user’s online status to all her friends.

These example applications share a common pattern: on application load, the application fetches a complete snapshot of its state and uses a PubSub connection to receive updates to this state. The updates act as “diffs” to the initial state.

Clients establish a WebSocket connection to our server, listen on topics they care about, and get messages on those topics in real time. Each command or message sent between the client and server is a JSON string encapsulated in one WebSocket frame.

(WebSocket is a communications protocol, providing full-duplex communication channels over a single TCP connection. For more information, see the WebSocket Wikipedia entry.

The JSON messages differ, depending on the type of message or command, but typically they have this form:

1
2
3
4
{ 
   "type": "<type string>",
   "data": "<JSON blob>"
}

Terminology

Term Definition
Client An end-user session of the Twitch application or a third-party application’s integration point.
Command An action that a client issues to the server, which modifies the state of the client connection.
Message A piece of data which back-end services broadcast to interested clients via PubSub. PubSub never inspects or mutates messages.
Server A Twitch machine that clients connect to for PubSub service.
Topic Aka event. A logical partition of messages that clients may subscribe to, to get messages.

Connection Management

Clients establish a secure WebSocket connection to:

wss://pubsub-edge.twitch.tv

To keep the server from closing the connection, clients must send a PING command at least once every 5 minutes. If a client does not receive a PONG message within 10 seconds of issuing a PING command, it should reconnect to the server. See details in Handling Connection Failures.

Clients must LISTEN on at least one topic within 15 seconds of establishing the connection, or they will be disconnected by the server.

Clients may receive a RECONNECT message at any time. This indicates that the server is about to restart (typically for maintenance) and will disconnect the client within 30 seconds. During this time, we recommend that clients reconnect to the server; otherwise, the client will be forcibly disconnected.

Example: PING Connection Message

1
2
3
4
// Sent from client to server
{
  "type": "PING"
}

Example: PONG Connection Message

1
2
3
4
// Sent from server to client in response to a PING
{
  "type": "PONG"
}

Example: RECONNECT Connection Message

1
2
3
4
// Sent from server to client
{
  "type": "RECONNECT"
}

Handling Connection Failures

When a client encounters a situation where it must reconnect to the server, it should first establish a new successful WebSocket connection and then issue a LISTEN command that contains the set of topics that the application expects to receive messages on.

If a client fails to connect to the server or is disconnected from the server, it should reconnect to the server using an exponential backoff. Our official client implementation initially waits one second (plus a small random jitter: see the next paragraph) to retry a failed connection and doubles the backoff period on subsequent failures, up to a maximum backoff threshold of 2 minutes. This prevents some “stampeding herd” situations where many clients simultaneously connect to the server.

If a client uses timers to issue PING commands, it should add a small random jitter to the timer. This prevents some situations where many clients issue PING commands simultaneously.

After a client reconnects to the server, some applications should fetch fresh state, to compensate for any missed messages while the connection was broken. For instance, our Whispers application fetches new messages on reconnect (as it does on initial page load), in case the user received any new messages while the connection was down.

API Limits

  • Clients can listen on up to 50 topics per connection. Trying to listen on more topics will result in an error message.
  • We recommend that a single client IP address establishes no more than 10 simultaneous connections.

The two limits above are likely to be relaxed for approved third-party applications, as we start to better understand third-party requirements.

  • Malicious or careless applications that result in abnormally high server load may be blacklisted from establishing connections.
  • If clients are slow to read messages from their connection and the server is simultaneous buffering more than 30 messages to an individual client, the client will be disconnected.

Subscribing to Topics

Once a client establishes a connection, it can LISTEN on topics it cares about. Clients can LISTEN on many topics at once and add new topics at any time by issuing new LISTEN commands.

Once a client no longer cares about a particular set of topics, it can issue UNLISTEN commands to stop receiving messages on those topics.

Authentication

Some topics can be LISTENed to by any clients while others require OAuth tokens. The topics that require an OAuth token typically have a required scope and, in some cases, a whitelisted set of client IDs that may LISTEN to them.

Available Topics

Feature Topic and Example Required Scope You are notified when …
Bits channel-bits-events-v1.<channel ID>

Example:
channel-bits-events-v1.44322889
Any scope Anyone cheers on a specified channel.
Channel Subscriptions channel-subscribe-events-v1.<channel ID>

Example:
channel-subscribe-events-v1.44322889
channel_subscriptions Anyone subscribes (first month) or resubscribes (subsequent months) to a channel.
Whispers whispers.<user ID>

Example:
whispers.44322889
chat_login `Anyone whispers the specified user.

Note: channel-bitsevents is deprecated. For bits events, use channel-bits-events-v1 instead.

Requests

This is an example request for bits events. It listens to bits events on channel 44322889. The authorization scope is specified when you generate the OAuth token using our authorization flow; see the Authentication guide.

1
2
3
4
5
6
7
8
9
// Request from client to server
{
  "type": "LISTEN",
  "nonce": "44h1k13746815ab1r2",
  "data": {
    "topics": ["channel-bits-events-v1.44322889"],
    "auth_token": "cfabdegwdoklmawdzdo98xt2fo512y"
  }
}
Request Parameter Type Description
type string Valid values: LISTEN, UNLISTEN.
nonce string (Optional) Random string to identify the response associated with this request.
data JSON Wraps the topics and auth_token fields.
     topics array of strings List of topics to listen on. Valid values:

- Bits:
channel-bits-events-v1.<channel ID>
where <channel ID> is the _id field returned by the Twitch API Get Channel endpoint.

- Whispers:
whispers.<user ID>
where <user ID> is the _id field returned by the Twitch API Get User endpoint.
     auth_token string OAuth token required to listen on some topics. The token is linked to either:
- The specified <channel user ID> (for bits events).
- The specified <user ID> (for whispers events).

Responses

Here is a sample response:

1
2
3
4
5
6
// Response from server to client
{
  "type": "RESPONSE",
  "nonce": "44h1k13746815ab1r2",
  "error": ""
}
Response Parameter Type Description
type string Valid value: RESPONSE.
nonce string The nonce that was passed in the request, if one was provided there.
error string The error message associated with the request, or an empty string if there is no error.

For bits and whispers events requests, error responses can be: ERR_BADMESSAGE, ERR_BADAUTH, ERR_SERVER, ERR_BADTOPIC.

Receiving Messages

When a message for your subscription is published, you will receive a message containing the applicable data.

Message Parameters: All Messages

Parameter Type Description
type string Valid value: MESSAGE
data JSON Wraps the topics and message fields.
     topic string The topic that the message pertains to.
     message string The body of the message. Depending on the type of message, the message body contains different fields; see below.

Example: Bits Event Message

1
2
3
4
5
6
7
{
   "type": "MESSAGE",
   "data": {
      "topic": "channel-bits-events-v1.44322889",
      "message": "{\"data\":{\"user_name\":\"dallasnchains\",\"channel_name\":\"dallas\",\"user_id\":\"129454141\",\"channel_id\":\"44322889\",\"time\":\"2017-02-09T13:23:58.168Z\",\"chat_message\":\"cheer10000 New badge hype!\",\"bits_used\":10000,\"total_bits_used\":25000,\"context\":\"cheer\",\"badge_entitlement\":{\"new_version\":25000,\"previous_version\":10000}},\"version\":\"1.0\",\"message_type\":\"bits_event\",\"message_id\":\"8145728a4-35f0-4cf7-9dc0-f2ef24de1eb6\"}"
   }
}
Field Type Description
badge_entitlement Object Information about the user’s new badge level, if the user reached a new badge level with this cheer; otherwise. null.
bits_used integer Number of bits used.
channel_id string User ID of the channel on which bits were used.
channel_name string Name of the channel on which bits were used.
chat_message string Chat message sent with the cheer.
context string Event type associated with this use of bits (for example, cheer).
message_id string Message ID
message_type string Message type (that is, the type of object contained in the data field)
time string Time when the bits were used. RFC 3339 format.
total_bits_used integer All-time total number of bits used on this channel by the specified user.
user_id string User ID of the person who used the bits.
user_name string Login name of the person who used the bits.
version string Message version

Example: Channel Subscriptions Event Message

The data and message fields are JSON strings and will need to be escaped.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
   "type": "MESSAGE",
   "data": {
      "topic": "channel-subscribe-events-v1.44322889",
      "message": {
         "user_name": "dallas",
         "display_name": "dallas", 
         "channel_name": "twitch",
         "user_id": "44322889",
         "channel_id": "12826",
         "time": "2015-12-19T16:39:57-08:00",
         "sub_plan": "Prime"/"1000"/"2000"/"3000",
         "sub_plan_name": "Mr_Woodchuck - Channel Subscription (mr_woodchuck)",
         "months": 9,
         "context": "sub"/"resub",
         "sub_message": {
            "message": "A Twitch baby is born! KappaHD",
            "emotes": [
            {
               "start": 23,
               "end": 7,
               "id": 2867
            }]
         }
     }
   }
}

Example: Whispers Event Message

The data and message fields are JSON strings and will need to be escaped.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
{
   "type":"MESSAGE",
   "data":{
      "topic":"whispers.44322889",
      "message":{
         "type":"whisper_received",
         "data":{
            "id":41
         },
         "thread_id":"129454141_44322889",
         "body":"hello",
         "sent_ts":1479160009,
         "from_id":39141793,
         "tags":{
            "login":"dallas",
            "display_name":"dallas",
            "color":"#8A2BE2",
            "emotes":[

            ],
            "badges":[
               {
                  "id":"staff",
                  "version":"1"
               }
            ]
         },
         "recipient":{
            "id":129454141,
            "username":"dallasnchains",
            "display_name":"dallasnchains",
            "color":"",
            "badges":[]
         },
         "nonce":"6GVBTfBXNj7d71BULYKjpiKapegDI1"
      },
      "data_object":{
         "id":41,
         "thread_id":"129454141_44322889",
         "body":"hello",
         "sent_ts":1479160009,
         "from_id":44322889,
         "tags":{
            "login":"dallas",
            "display_name":"dallas",
            "color":"#8A2BE2",
            "emotes":[],
            "badges":[
               {
                  "id":"staff",
                  "version":"1"
               }
            ]
         },
         "recipient":{
            "id":129454141,
            "username":"dallasnchains",
            "display_name":"dallasnchains",
            "color":"",
            "badges":[]
         },
         "nonce":"6GVBTfBXNj7d71BULYKjpiKapegDI1"
      }
   }
}

The fields in this message are similar to IRC fields. See the Chat and IRC guide.