Pusher Channels Protocol
Describes the JSON based protocol used by clients to communicate with Pusher Channels, mainly over a WebSocket connection.
Changes to this protocol are handled by incrementing an integer version number. The current protocol, version 7, is documented here.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Clients should make a WebSocket connection to
1
[scheme]://ws-[cluster_name].pusher.com:[port]/app/[key]
- scheme
ws
- for a normal WebSocket connectionwss
- for a secure WebSocket connection- cluster_name
- The name of the cluster that you're using
- port
- Default WebSocket ports:
80
(ws
) or443
(wss
) - For Silverlight clients ports
4502
(ws
) and4503
(wss
) may be used. - key
- The app key for the application connecting to Pusher Channels
The following query parameters should be supplied:
- protocol [integer]
- The protocol version to use. If this is not supplied the protocol version to use is inferred from the version parameter (to support old javascript clients which relied on this behaviour). Failing that protocol 1 is used (this behaviour is deprecated and will in future be replaced by a 4008 error code)
- client [string]
- Identifies the client which is connecting. This string should be of the form
platform-library
- for example the iOS library identifies itself asiOS-libPusher
. - version [string]
- The version of the library which is connecting, for example
1.9.3
.
For example
1
ws://ws-ap1.pusher.com:80/app/APP_KEY?client=js&version=7.0&protocol=5
Data is sent bidirectionally over a WebSocket as text data containing UTF8 encoded JSON.
Every JSON message contains a single event and has an event
property which is known as the event name. See events below for a description of the event types.
If the WebSocket connection supports ping & pong (i.e. advertises itself as draft 01 or above), Pusher Channels will send ping messages to the client in order to verify that it is active.
In protocol versions 5 and above, when using an old version of the WebSocket protocol, Pusher Channels will send pusher:ping
event (see events to the client). The client should respond with a pusher:pong
event.
Both Pusher Channels and clients require a mechanism for establishing that the connection is alive.
The basic design pattern is described in the ZeroMQ Wiki and is symmetric for the client and Pusher Channels.
Essentially any messages received from the other party are considered to mean that the connection is alive. In the absence of any messages either party may check that the other side is responding by sending a ping message, to which the other party should respond with a pong.
In recent WebSocket drafts ping & pong are supported as part of the protocol. Unfortunately this was not the case in earlier drafts, and unfortunately it is still not possible to trigger sending a ping, or binding to a pong from JavaScript using the W3C API. For both these reasons, Pusher Channels supports both protocol level ping-pong, and an emulated one. This means that Pusher Channels will respond to a WebSocket protocol ping message with a pong message, and also it will respond to apusher:ping
event with a pusher:pong
event (both have empty data).
If the WebSocket draft supports protocol level ping-pong, then on receipt of a ping message, the client MUST respond with a pong message.
If the client does not support protocol level pings and advertises (on connect) that it implements a protocol version >= 5 then the client MUST respond to a pusher:ping
event with apusher.pong
event.
Clients SHOULD send a ping to Pusher Channels when the connection has been inactive for some time in order to check that the connection is alive. They MUST then wait some time for receipt of a pong message before closing the connection / reconnecting. Clients SHOULD send a protocol ping if supported (sending a pusher:ping
event will also work).
Clients MAY use platform specific APIs to trigger a ping check at an appropriate time (for example when network conditions change).
The precise timeouts before sending a ping and how long to wait for a pong MAY be configurable by the user of the library, but sensible defaults SHOULD be specified. The recommended values are:
- Activity timeout before sending ping: 120s
- Time to wait for pong response before closing: 30s
If the client supports protocol version 7, the server will send anactivity_timeout
value in the data hash of thepusher:connection_established
event (see Connection Events). The client SHOULD set the timeout before sending a ping to be the minimum of the value it has chosen though configuration and the value supplied by the server.
The following example code is taken from the pusher-js
library. This function is called whenever a message is received
1 2 3 4 5 6 7 8 9 10 11
function resetActivityCheck() { if (self._activityTimer) { clearTimeout(self._activityTimer); } // Send ping after inactivity self._activityTimer = setTimeout(function() { self.send_event('pusher:ping', {}) // Wait for pong response self._activityTimer = setTimeout(function() { self.socket.close(); }, (self.options.pong_timeout || Pusher.pong_timeout)) }, (self.options.activity_timeout || Pusher.activity_timeout)) }
Clients may close the WebSocket connection at any time.
The Pusher Channels server may choose to close the WebSocket connection, in which case a close code and reason will be sent.
Clients SHOULD support the following 3 ranges
4000-4099: The connection SHOULD NOT be re-established unchanged.
4100-4199: The connection SHOULD be re-established after backing off. The back-off time SHOULD be at least 1 second in duration and MAY be exponential in nature on consecutive failures.
4200-4299: The connection SHOULD be re-established immediately.
Clients MAY handle specific close codes in particular way, but this is generally not necessary. See error codes below for a list of errors.
pusher:error
event will be sent with an appropriate code before the WebSocket connection is closed (see below.pusher:error
event is also sent before the connection is closed (regardless of the WebSocket draft).Every message on a Pusher Channels WebSocket connection is packaged as an 'event', whether it is user-generated, or if it is a message from the system. There is always an event name that can be used to determine what should happen to the payload.
Every event must contain an event
property containing the event name.
In the docs below "(Pusher Channels -> Client)" indicates that this event is sent from the Pusher Channels server to to client, and similarly vice versa.
All events received and sent by clients can contain a data
field. While all pusher:
-prefixed events contain only JSON-serializable hashes, it is possible for publishers to trigger messages containing arbitrarily-encoded data. In order to keep the protocol consistent, Pusher Channels tries to send thedata
field as a string. In case of pusher:
events data may be JSON-serialized first (see our documentation on individual pusher:
events). As an example of one of these 'double-encoded' events, Pusher Channels will send:
1 2 3 4
{ "event": "pusher:connection_established", "data": "{\"socket_id\":\"123.456\"}" }
instead of:
1 2 3 4
{ "event": "pusher:connection_established", "data": {"socket_id": "123.456"} }
When the client has connected to the Channel service apusher:connection_established
event is triggered. Once this event has been triggered subscriptions can be made to Pusher Channels using the WebSocket connection.
1 2 3 4
{ "event": "pusher:connection_established", "data": String }
Where the data
field is a JSON-encoded hash of following format:
1 2 3 4
{ "socket_id": String "activity_timeout": Number }
- data.socket_id (String)
- A unique identifier for the connected client
- data.activity_timeout (Number) (Protocol 7 and above)
- The number of seconds of server inactivity after which the client should initiate a ping message
Within the client libraries the connection is normally established when the constructor is called.
1
var pusher = new Pusher('APP_KEY');

When an error occurs a pusher:error
event will be triggered. An error may be sent from Pusher Channels in response to invalid authentication, an invalid command, etc.
pusher:error
event will be sent with an appropriate code before the WebSocket connection is closed.1 2 3 4 5 6 7
{ "event": "pusher:error", "data": { "message": String, "code": Integer } }
- data.message (String)
- A textual description of the error
- data.code (Integer) - optional
- A code that identifies the error that has occurred. See error codes below.
The pusher:subscribe
event is generated on the client and sent to Pusher Channels when a subscription is made. For more information on channel names see the channels documentation.
1 2 3 4 5 6 7 8
{ "event": "pusher:subscribe", "data": { "channel": String, "auth": String, "channel_data": String } }
Where the data
members are as follows:
- data.channel (String)
- The name of the channel that is being subscribed to.
- data.auth (String) [optional]
- If the channel is a presence or private channel then the subscription needs to be authenticated. The authentication signature should be provided on this property if required. The value will be generated on the application server. For more information see authentication signatures.
- data.channel_data (String) [optional]
- This property should be populated with additional information about the channel if the channel is a presence channel. The JSON for the
channel_data
will be generated on the application server and should be encoded as a string and assigned to this property. The format of the object is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
{ "event": "pusher:subscribe", "data": { "channel": "presence-example-channel", "auth": "<APP_KEY>:<server_generated_signature>", "channel_data": "{ \"user_id\": \"<unique_user_id>\", \"user_info\": { \"name\": \"Phil Leggetter\", \"twitter\": \"@leggetter\", \"blogUrl\":\"http://blog.pusher.com\" } }" } }
For more information see authenticating users.
From the API users point of view the subscription is made the moment that the subscribe
method is called. However, the actual moment within the client library that a pusher:subscribe
event is triggered depends on the type of channel that is being subscribed to.
1 2
var pusher = new Pusher('APP_KEY'); var channel = pusher.subscribe('public-channel');
Since no authentication must take place when subscribing to a public channel the pusher:subscribe
event can be sent from the client to Pusher Channels as soon as the call to subscribe
is made.

Private, Encrypted and Presence channels require authentication so an additional call needs to be made to the application server hosting the web application in order to make sure the current user can subscribe to the given channel.

For more information on authentication of channels see the Authenticating Users docs.
The pusher:unsubscribe
event is generated on the client and sent to Pusher Channels when a client wishes to unsubscribe from a channel.
1 2 3 4
{ "event": "pusher:unsubscribe", "data" : Object }
Where the data
field is a hash of following format:
1 2 3
{ "channel": String }
- data.channel (String)
- The name of the channel to be unsubscribed from.
Unsubscribing works in the same way as subscribing to a channel with the only difference being that the event name is pusher:unsubscribe
.
1 2 3 4 5 6
var pusher = new Pusher('APP_KEY'); var channel = pusher.subscribe('public-channel'); // ... pusher.unsubscribe('my-channel');

Channel events are associated with a single channel.
1 2 3 4 5 6
{ "event": String, "channel": String, "data": String, "user_id"?: String }
- event (String)
- The name of the event
- channel (String)
- The name of the channel that the event is associated with e.g.
my-channel
- data (String)
- The data associated with the event. It is strongly recommended that this be a JSON-serialized hash (e.g.
{"hello":"world", "foo": {"bar": 1000}}
), although it is possible to send any type of payload, for example a simple string. - user_id (optional, String)
- The
user_id
key is only present if this is a client event on a presence channel. The value is theuser_id
of the client that triggered the event. This value is taken from theauth token generated by your server for that client's subscription to this channel.
1 2 3 4 5
var pusher = new Pusher('APP_KEY'); var channel = pusher.subscribe('my-channel'); channel.bind('my-event', function(data){ // handle event });

Encrypted channel events are similar to plain Channel Events, but thedata
payload is encrypted with a shared per-channel key to ensure that even Pusher cannot see the contents of the event.
Encrypted channel events are only sent to channels where the name is prefixedprivate-encrypted-
.
Pusher WebSocket libraries do not support encryption of client events, and so do not include the facility to send them on encrypted channels.
1 2 3 4 5
{ "event": String, "channel": String, "data": String, }
- event (String)
- The name of the event (plaintext)
- channel (String)
- The name of the channel that the event is associated with e.g.
private-encrypted-my-channel
(plaintext). - data (String)
- A string which encodes a JSON object with the following two keys:
- ciphertext (String)
- The base64 encoded, encrypted payload which would usually appear in the
data
field of a regular Channel Event - nonce (String)
- The base64 encoded "Number used ONCE" which must be used together with the per-channel shared secret retrieved from the auth endpoint to decrypt the contents of the
ciphertext
field
Some events are related only to presence channels.
The pusher_internal:subscription_succeeded
event is sent when a subscription to a presence channel is successful.
1 2 3 4 5
{ "event": "pusher_internal:subscription_succeeded", "channel": "presence-example-channel", "data": String }
Where the data
field is a JSON-encoded hash of following format:
1 2 3 4 5 6 7
{ "presence": { "ids": Array, "hash": Hash, "count": Integer } }
- channel (String)
- The presence channel name
- data.presence.ids (Array)
- An array of unique user identifiers who are subscribe to the channel.
- data.presence.hash (Hash)
- A hash of user IDs to object literals containing information about that user.
- data.presence.count (Integer)
- The number of users subscribed to the presence channel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
{ "event": "pusher_internal:subscription_succeeded", "channel": "presence-example-channel", "data": "{ \"presence\": { \"ids\": [\"11814b369700141b222a3f3791cec2d9\",\"71dd6a29da2a4833336d2a964becf820\"], \"hash\": { \"11814b369700141b222a3f3791cec2d9\": { \"name\":\"Phil Leggetter\", \"twitter\": \"@leggetter\" }, \"71dd6a29da2a4833336d2a964becf820\": { \"name\":\"Max Williams\", \"twitter\": \"@maxthelion\" } }, \"count\": 2 }" }
When a user subscribes to a presence channel thepusher_internal:member_added
is triggered on the channel. The different event name is used to differentiate a public event from an internal one.
1 2 3 4 5
{ "event": "pusher_internal:member_added", "channel": "presence-example-channel", "data": String }
Where the data
field is a JSON-encoded hash of following format:
1 2 3 4
{ "user_id": String, "user_info": Object }
- channel (String)
- The presence channel name
- data.user_id (String)
- The ID of a user who has just subscribed to the presence channel.
- data.user_info (Object)
- An object containing information about that user who has just subscribed to the channel. The contents of the
user_info
property depends on what the application server replied with when the presence channel was authenticated.
1 2 3 4 5 6 7 8 9 10 11 12
{ "event": "pusher_internal:member_added", "channel": "presence-example-channel", "data": "{ \"user_id\": \"11814b369700141b222a3f3791cec2d9\", \"user_info\": { \"name\": \"Phil Leggetter\", \"twitter\": \"@leggetter\", \"blogUrl\": \"http://blog.pusher.com\" } }" }
For more about the user_info
object literal see user_info
in the authenticating users section.
When a user unsubscribes from a presence channel by either actually unsubscribing or their WebSocket connection closing thepusher_internal:member_removed
is triggered on the from Pusher Channels. The different event name is used to differentiate a public event from an internal one.
1 2 3 4 5
{ "event": "pusher_internal:member_removed", "channel": "presence-example-channel", "data": String }
Where the data
field is a JSON-encoded hash of following format:
1 2 3
{ "user_id": String }
- channel (String)
- The presence channel name
- data.user_id (String)
- The ID of a user who has just unsubscribed from the presence channel.
It is possible to trigger events from a client when the application that the client has connected to has had client events enabled, the event name must be prefixed with client-
and the channel must be an authenticated channel (private or presence). For more information on this see the Triggering Client Events docs.
1 2 3 4 5
{ "event": String, "channel": String, "data": String/Object }
- event (String)
- The name of the event which must be prefixed with
client-
to be accepted. For example,client-event
orclient-something-updated
- channel (String)
- The channel for the event to be triggered on. To be accepted the channel must be either a private (
private-
) or a presence (presence-
) channel. - data (String/Object)
- The data to be sent and associated with the event. It is strongly recommended that this be a hash of key/value pairs (
{"hello":"world", "foo": {"bar": 1000}}
) although it is possible to send any type of payload, for example a simple string.
1 2 3 4
var pusher = new Pusher('APP_KEY'); var channel = pusher.subscribe('private-channel'); var data = {"some": "data"}; channel.trigger("client-event", data);

A client library does much more than just proxy information between The Pusher Channels servers and clients. It adds functionality to make using Pusher Channels even easier. It does things such as reconnection, provides information and feedback about the connection state, performs subscription management (keeps track of what channels have been subscribed to) and routes events to the correct event listeners.
We don't want to dictate the structure of code but it's definitely easier if the libraries across different technologies have a similar class structure. The following diagram shows the structure of the JavaScript client library:

The following sections explain the purpose of each class shown within the diagram, what they represent and their interaction with other classes.
A number of classes inherit from the EventEmitter
which makes it easy for events to be bound to and ensures that binding is performed in a consistent way between all classes.
The Pusher
class is the main class which is created when connecting to Pusher Channels. It creates a connection object which then established the connection to Pusher Channels.
The Connection
class represents the connection to Pusher Channels and abstracts away the underlying connection mechanism. The recommended approach for connection is to use a WebSocket
. In the JavaScript implementation there are HTTP streaming and polling fallbacks if the browser cannot establish a WebSocket connection.
The diagram shows a WebSocket
object which is the native object used to connect to Pusher Channels.
A Channel
represents a source of data from Pusher Channels and a subscription. A Pusher
instance can have more than one channel associated with it, and thus have many subscriptions.
A PrivateChannel
inherits from Channel
and represents an authenticated subscription for channel data from Pusher Channels.
A PresenceChannel
represents and authenticated subscription and thus inherits from PrivateChannel
. Additional presence-only events can be subscribed to on the PresenceChannel
object that notify the library user of the members that are subscribed to the channel and when members are subscribe or unsubscribe from the channel.
Client Only Events are events that transition from the client library to the API user only. They are generated within the library to provide the developer with additional information about the state or actions that occurring within the library. In keeping with the event paradigm that we use in Pusher Channels it is recommended that client libraries also use events when communicating change within the library with the library user.
Understanding and having access to information about the connection status to Pusher Channels is very important, especially when developing for applications to run on mobile devices where network connectivity might not be very reliable. For this reasons we've spent a lot of time thinking about how to manage this and how best to keep a developer informed about the connection state. We have implemented functionality for this within the JavaScript library and we recommend that other client libraries copy, or follow, this functionality very closely.
For more information see our connection states documentation.
The pusher:subscription_succeeded
event is triggered following the receipt of a pusher_internal:subscription_succeeded
event. The different event name is used to differentiate a public event from an internal one.
1 2 3 4
{ "event": "pusher:subscription_succeeded", "members": Object }
- members (Object)
- The members object contains information on the members that are subscribed to the presence channel.
The members
object interface is as follows:
1 2 3 4 5
function Members() {}; /* For each member call the 'iterator' function */ Members.prototype.each = function(iterator /* Function */) {}; Members.prototype.count = 0; Members.prototype.get = function(userId){};
each
function.For more information on the members object see thepusher:subscription_succeeded
section of the presence events docs.
Indicates an error resulting in the connection being closed by Pusher Channels, and that attempting to reconnect using the same parameters will not succeed.
4000
: Application only accepts SSL connections, reconnect using wss://4001
: Application does not exist4003
: Application disabled4004
: Application is over connection quota4005
: Path not found4006
: Invalid version string format4007
: Unsupported protocol version4008
: No protocol version supplied4009
: Connection is unauthorized
Indicates an error resulting in the connection being closed by Pusher Channels, and that the client may reconnect after 1s or more.
4100
: Over capacity
Indicates an error resulting in the connection being closed by Pusher Channels, and that the client may reconnect immediately.
4200
: Generic reconnect immediately4201
: Pong reply not received: ping was sent to the client, but no reply was received - see ping and pong messages4202
: Closed after inactivity: Client has been inactive for a long time (currently 24 hours) and client does not support ping. Please upgrade to a newer WebSocket draft or implement version 5 or above of this protocol.
Any other type of error.
4301
: Client event rejected due to rate limit
No changes to the Protocol - simply a name change from Pusher to Channels. No code changes required.
When the server closes connections due to an error, a pusher:error
event is only sent if and old WebSocket draft is in use which does not support close codes. Clients SHOULD therefore expose the close code and reason in some way to the developer.
Pusher Channels expects the client to respond to ping messages [docs]
Added a confirmation message after subscribing to public and private channels (already sent for presence channels)
Significant change to presence events [docs]
Renamed connection_established
event to pusher:connection_established
Initial release