Pusher Events

Events are the primary method of packaging messages in the Pusher system. they form the basis of all communication.

They are essentially ‘named messages’ which means you can set up ‘handlers’ in your client code to deal with the various types. As such they are used for ‘client-side’ routing, and should not be used as filters (channels can do this much more efficiently on the server side).

Events can be seen as a notification of something happening on your system, and they are often named in the past tense. For example: message-created, todo-finished.

Binding to Events

Most binding and triggering behaviour is attached to channels the client is subscribed to, though it is also possible to bind to all events on the Pusher connection regardless of the channel.

Binding on the channel

Events can be bound to directly on a channel which means you will only received an event if it is sent on that specific channel.

channel.bind(eventName, callback);
  • eventName (String)
    • The name of the event to bind to.
  • callback (Function)
    • A function to be called whenever the event is triggered.

Example

The following might be an example of a stock tracking app where several channels are opened for different companies:

var pusher = new Pusher('APP_KEY');
var channel = pusher.subscribe('APPL');
channel.bind('new-price',
  function(data) {
    // add new price into the APPL widget
  }
);

Binding with optional this context

It is possible to provide a third, optional parameter that is used as the this value when calling a handler.

var context = { title: 'Pusher' };
var handler = function(){
  console.log('My name is ' + this.title);
};
channel.bind('new-comment', handler, context);

Once you have created an instance of PTPusherChannel, you can set up event bindings. There is no need to wait for the PTPusher client connection to be established.

When you bind to events on a single channel, you will only receive events with that name if they are sent over this channel.

PTPusherChannel *channel = [_client subscribeToChannelNamed:@"chat"];
[channel bindToEventNamed:@"new-message" handleWithBlock:^(PTPusherEvent *channelEvent) {
  // channelEvent.data is a NSDictianary of the JSON object received
}];

Binding on the client

You can also bind to events regardless of the channel the event is broadcast to. By using the pusher.bind() method rather than channel.bind(), you can listen for an event on all the channels that you are currently subscribed to.

The following is an example of an app that binds to a new-comment event from all channels that we’re currently subscribed to:

pusher.bind(eventName, callback);
  • eventName (String)
    • The name of the event to bind to.
  • callback (Function)
    • A function to be called whenever the event is triggered.

Example

var pusher = new Pusher('APP_KEY');
var channel1 = pusher.subscribe('test_channel_1');
var channel2 = pusher.subscribe('test_channel_2');
var channel3 = pusher.subscribe('test_channel_3');

var eventName = 'new-comment';
var callback = function(data) {
    // add comment into page
  };

// listen for 'new-comment' event on channel 1, 2 and 3
pusher.bind(eventName, callback);

Once you have created an instance of the PTPusher client, you can set up event bindings. There is no need to wait for the connection to be established.

When you bind to events on the client, you will receive all events with that name, regardless of the channel from which they originated.

_binding = [_client bindToEventNamed:@"new-comment" handleWithBlock:^(PTPusherEvent *event) {
  // event.data is a NSDictianary of the JSON object received
}];

Binding to all events from the connection

It is possible to bind to all events at either the global or channel level by using the method bind_all. This is used for debugging, but may have other utilities.

Unbinding from Events

channel.unbind

It’s possible to removing a binding to an event on a channel.

channel.unbind(eventName, callback);
  • eventName (String)
    • The name of the event that the binding is to be removed from.
  • callback (Function)
    • A function event handler used when binding to the event.

Example

var pusher = new Pusher('APP_KEY');
var channel = pusher.subscribe('APPL');
var callback = function(data) {};
channel.bind('new-price', callback);

channel.unbind('new-price', callback);
[_client removeBinding:binding];
  • binding (PTPusherEventBinding)
    • Represents the binding to be removed.

Example

If you no longer want to receive events with a specific name, you can remove the binding. Removing a binding is as simple as storing a reference to the binding object, then passing that as an argument to removeBinding: at a later point.

_binding = [_client bindToEventNamed:@"new-message" target:self action:@selector(handleEvent:)];

[_client removeBinding:_binding];

Pusher channel events

Some events are triggered by Pusher and to clearly indicate this are prefixed with pusher:.

pusher:subscription_succeeded

Note: this feature was introduced in version 1.10 of the Pusher JavaScript library.

Once you’ve subscribed to a channel you can bind to the pusher:subscription_succeeded event so that you know when the subscription has been registered within Pusher.

channel.bind('pusher:subscription_succeeded', function() {
});

This is particularly useful for private and presence channels if you are using client events because you can only trigger an event once a successful subscription has occurred.

For example, if the channel is a Presence Channel a members event argument is also passed to the pusher:subscription_succeeded event handler. The presence channel also introduces a number of other events that can be bound to. For information please see the presence events docs.

pusher:subscription_error

Note: the pusher:subscription_error event was introduced without the pusher: prefix but this is required in version 1.10 of the Pusher JavaScript library and up.

Sometimes things go wrong so we’ve exposed a pusher:subscription_error event that is triggered when an authentication request for a private or presence channels fails. This event is bound to on the channel that is to be authenticated.

The event is triggered either when the authentication endpoint returns a HTTP status code that is not 200 or if there is a problem parsing the JSON that the endpoint returned.

channel.bind('pusher:subscription_error', function(status) {
});
  • status (Number)

Example

var pusher = new Pusher('APP_KEY');
var channel = pusher.subscribe('private-channel');
channel.bind('pusher:subscription_error', function(status) {
  if(status == 408 || status == 503){
    // retry?
  }
});

Additional presence events

Presence comes with a number of presence specific events. For more information please see the presence events docs.

Triggering Client Events

Not all traffic needs to go via your conventional web server when using Pusher. Some actions may not need validation or persistence and can go directly via the socket to all the other clients connected to the channel.

It is important that you apply additional care when when using client events, since these originate from other users, and could be subject to tampering by a malicious user of your site.

Client events have a number of enforced restrictions to ensure that the user subscribing to the channel is an authenticated user and so that client events can be clearly identified:

  • Client events must be enabled for the application. You can do this in the Settings tab for your app within the Pusher dashboard
  • The user must be subscribed to the channel that the event is being triggered on
  • Client events can only be triggered on private and presence channels because they require authentication
  • Client events must be prefixed by client-. Events with any other prefix will be rejected by the Pusher server, as will events sent to channels to which the client is not subscribed.
  • You can only trigger a client event once a subscription has been successfully registered with Pusher. You can ensure this is the case using the pusher:subscription_succeeded event.
  • Client events are not delivered to the originator of the event. For more information see Message Routing.
  • Publish no more than 10 messages per second per client (connection). Any events triggered above this rate limit will be rejected by our API. See Rate limit your events.
var triggered = channel.trigger(eventName, data);
  • eventName (String)
    • The name of the event to be triggered. A client event must have a name prefixed with client- or it will be rejected by the server.
  • data (Object)
    • The object to be converted to JSON and distributed with the event.
  • Returns (Boolean)
    • true if the event was successfully triggered, otherwise false

Example

var pusher = new Pusher('YOUR_APP_KEY');
var channel = pusher.subscribe('private-channel');
channel.bind('pusher:subscription_succeeded', function() {
  var triggered = channel.trigger('client-someeventname', { your: data });
});
[private triggerEventNamed:eventName data:data];
  • eventName (String)
    • The name of the event to be triggered. If the event name is not prefixed with client- the library will prepend it.
  • data (Object)
    • The object to be converted to JSON and distributed with the event.

Example

PTPusherPrivateChannel *private = [_client subscribeToPrivateChannelNamed:@"chat"];
[private triggerEventNamed:@"myevent" data:@{@"foo": @"bar"}];

Message routing

When you trigger a client event, the event will not be fired in the client which calls trigger. This is similar to the case described in the page on excluding event recipients.

Best practice when sending client events

As well as the obvious security implications of sending messages from clients, and in particular web browsers, it’s also important to consider what events are sent and when. If the destination client is also a web browser there is only so much data that web browser can handle so there only the required information should be sent at the right time. With this in mind we’ve come up with a few best practice guidelines to follow when trigger client events.

Rate limit your events

Publish no more than 10 messages per second per client (connection). Any events triggered above this rate limit will be rejected by our API.

This is not a system issue, it is a client issue. 100 clients in a channel sending messages at this rate would each also have to be processing 1,000 messages per second! Whilst some modern browsers might be able to handle this it’s most probably not a good idea.

When to trigger events

The obvious things that result in events being triggered from a client application with a user interface are user actions such as mouse movement or key presses. In this scenario we still need to consider limiting how much information we send. Quite frequently a UI event should not lead directly to a client event being published into Pusher.

For example, if you have bound the the mousemove event and a user is wildly waving their pointer around the screen it’s not a good idea to translate each mouse move event into a client event. Instead you should define an interval at which the mouse position should be sent and if the mouse position has moved when the next interval fires send a single client event. The time interval may need to be tuned to suit your requirements.

Example

Information to appear here

var outputEl = document.getElementById('client_event_example_log');
var state = {
  currentX: 0,
  currentY: 0,
  lastX: undefined,
  lastY: undefined
};

var pusher = new Pusher("YOUR_APP_KEY");
var channel = pusher.subscribe("private-mousemoves");

// this method should be bound as a 'mousemove' event listener
document.body.addEventListener('mousemove', onMouseMove, false);
function onMouseMove(ev){
  ev = ev || window.event;
  state.currentX = ev.pageX || ev.clientX;
  state.currentY = ev.pageY || ev.clientY;
}

setInterval(function(){
  if(state.currentX !== state.lastX || state.currentY !== state.lastY){
    state.lastX = state.currentX;
    state.lastY = state.currentY;

    var text = document.createTextNode(
      'Triggering event due to state change: x: ' + state.currentX + ', y: ' + state.currentY
    );
    outputEl.replaceChild( text, outputEl.firstChild );

    channel.trigger("client-mouse-moved", {x:state.currentX, y: state.currentY});
  }
}, 300); // send every 300 milliseconds if position has changed

Also see

Have you tried using the search to find what you’re after? If you still have a question then get in touch with us and let us help you out.