Events
Events are the primary method of packaging messages in the Channels 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 to which the client is subscribed to (refer to Binding on the channel section). It is also possible to bind to the user object to handle messages addressed to the authenticated user. All published messages can be bound to in aggregate via the connection object itself. This aggregated binding triggers for both channel messages and user messages (for the currently authenticated user).
∞ Binding on the channel
Events can be bound to directly on a channel. This means you will only receive an event if it is sent on that specific channel.
channel.bind(eventName, callback);
let myChannel = pusher.subscribe("chat")
myChannel.bind(eventName: "new-message", eventCallback: { (event: PusherEvent) -> Void in
if let data: String = event.data {
// `data` is a string that you can parse if necessary.
}
})
channel.listen(eventName, callback);
- ∞ eventNameString Required
-
The name of the event to bind to.
- ∞ callbackFunction Required
-
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", (data) => {
// add new price into the APPL widget
});∞ Binding with optional
this
contextIt 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 = () => {
console.log(`My name is ${this.title}`);
};
channel.bind("new-comment", handler, context);
- ∞ PusherChannelString Required
-
Once you have created an instance of
PusherChannel
, you can set up event bindings. There is no need to wait for thePusherSwift
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.
- ∞ eventNameString Required
-
The name of the event to bind to.
- ∞ callbackFunction Required
-
A function to be called whenever the event is triggered.
∞ Example
Here’s an example of a stock tracking app where several channels are opened for different companies:
window.Echo = new Echo({
broadcaster: "pusher",
key: "APP_KEY",
cluster: "eu",
forceTLS: true,
});
var channel = Echo.channel("APPL");
channel.listen("new-price", (data) => {
// add new price into the APPL widget
});
∞ Binding on the user object
You can bind to events on the pusher.user
object. That means you will receive events sent to the user that has authenticated on that connection. Refer to User authentication for more information on authenticating users. Refer to Sending events to users for more information on how to send events to specific users based on user ID.
pusher.user.bind(eventName, callback);
pusher.user().bind(eventName, new SubscriptionEventListener() {
public void onEvent(final PusherEvent event) {
// ...
}
});
∞ Binding on the user’s Watchlist
You can bind to events on the pusher.user.watchlist
object. That means you will receive events about the Watchlist of the user authenticated on that connection. Refer to User authentication for more information on authenticating users. Refer to Watchlist events for more information on how to provide the user’s Watchlist and how to enable Watchlist events.
pusher.user.watchlist.bind(eventName, callback);
∞ 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.
Here’s 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);
// `binding` is a unique string that can be used to unbind the event callback later
let binding = pusher.bind(eventCallback: { (event: PusherEvent) -> Void in
if event.eventName == "new-comment" {
// Handle the global event
}
})
- ∞ eventNameString Required
-
The name of the event to bind to.
∞ Example
var pusher = new Pusher("APP_KEY");
var channel1 = pusher.subscribe("my-channel-1");
var channel2 = pusher.subscribe("my-channel-2");
var channel3 = pusher.subscribe("my-channel-3");
var eventName = "new-comment";
var callback = (data) => {
// add comment into page
};
// listen for 'new-comment' event on channel 1, 2 and 3
pusher.bind(eventName, callback);
- ∞ callbackFunction Required
-
This function is called whenever the event is triggered.
- ∞ PusherSwiftPusherSwift Required
-
Once you have created an instance of the
PusherSwift
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 to all events from the connection
It is possible to bind to all events at the global level by using the method bind_global
.
pusher.bind_global(callback);
- ∞ callbackFunction Required
-
This function is called whenever the event is triggered. Your callback will be passed the parameters:
eventName
(String) The name of the received eventdata
(Object) The payload of the received event
∞ Example
var pusher = new Pusher("APP_KEY");
var callback = (eventName, data) => {
console.log(
`bind global: The event ${eventName} was triggered with data ${JSON.stringify(
data
)}`
);
};
// bind to all events on the connection
pusher.bind_global(callback);
You can also use bind_global
at the channel level to bind to all events on the channel, regardless of the event name.
var pusher = new Pusher("APP_KEY");
var channel = pusher.subscribe("my-channel");
var callback = (eventName, data) => {
console.log(
`bind global channel: The event ${eventName} was triggered with data ${JSON.stringify(
data
)}`
);
};
// bind to all events on the channel
channel.bind_global(callback);
∞ Unbinding from events
It is possible to remove a binding to an event on a channel.
channel.unbind(eventName, callback);
channel.unbind(eventName: eventName, callbackId: binding)
channel.stopListening(eventName);
- ∞ eventNameString Required
-
The name of the event from which your want to remove the binding.
- ∞ callbackFunction Required
-
A function event handler used when binding to the event. If no callback function is supplied, all handlers on
eventName
will be removed.∞ Example
var pusher = new Pusher("APP_KEY");
var channel = pusher.subscribe("APPL");
var callback = (data) => {
// Do something with the data here
};
channel.bind("new-price", callback);
// Remove just 'handler' for the 'new-price' event
channel.unbind("new-price", handler);
// Remove all handlers for the 'new-price' event
channel.unbind("new-price");
// Remove all handlers on 'channel'
channel.unbind();
- ∞ bindingString Optional
-
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
unbind(callbackId:)
at a later point.let binding = pusher.bind(eventCallback: { (event: PusherEvent) -> Void in
if event.eventName == "new-message" {
// Handle the global event
}
})
pusher.unbind(callbackId: binding)
- ∞ eventNameString Required
-
The name of the event from which your want to remove the binding.
∞ Example
window.Echo = new Echo({
broadcaster: "pusher",
key: "APP_KEY",
cluster: "eu",
forceTLS: true,
});
var channel = Echo.channel("APPL");
var callback = (data) => {
// Do something with the data here
};
channel.listen("new-price", callback);
// Remove all handlers for the 'new-price' event
channel.stopListening("new-price");
∞ Channel events
Some events are triggered by Channels. To clearly indicate this, these are prefixed with pusher:
.
- ∞ pusher:subscription_succeededEvent
-
Once you have subscribed to a channel, you can bind to the
pusher:subscription_succeeded
event. That way you know when the subscription has been registered within Channels.channel.bind("pusher:subscription_succeeded", () => {});
This is particularly useful for private and presence channels if you are using client events because you can only trigger an event once you have a successful subscription.
For example, if the channel is a Presence Channel a
members
event argument is also passed to thepusher:subscription_succeeded
event handler. The presence channel also introduces a number of other events that can be bound to. For more information, refer to Events in Presence Channels.
- ∞ pusher:subscription_errorEvent
-
Sometimes things go wrong so we have exposed a
pusher:subscription_error
event. It is triggered when an authorization request for a private or presence channels fails. This event is bound to on the channel that is to be authorized.The event is triggered either when the authorization endpoint returns a HTTP status code that is not 200 or if there is a problem parsing the JSON that the endpoint returned.
NOTE:
If the library is unable to create a websocket connection at all, this event will not be emitted. To catch events at the connection level, you must bind toerror
events on the connection as described in Binding to connection eventschannel.bind("pusher:subscription_error", (error) => {});
- ∞ errorObject
-
An error object with the following properties:
type
(String)
Category of error that occured, e.g.AuthError
error
(String)
Human readable details of error that occurred.status
(Number)
The HTTP Status code of the error response from the authorization call.
∞ Example
var pusher = new Pusher("APP_KEY");
var channel = pusher.subscribe("private-channel");
channel.bind("pusher:subscription_error", (error) => {
var { status } = error;
if (status == 408 || status == 503) {
// Retry?
}
});
- ∞ pusher:cache_missEvent
-
When a client subscribes to a cache channel, you can bind to the
pusher:cache_miss
event to let the client know if there is no cached message.channel.bind("pusher:cache_miss", () => {});
- ∞ pusher:subscription_countEvent
-
Provides the number of connections that are currently subscribed to a channel.
To enable the Subscription Count feature, navigate to the Channels dashboard for your app > App Settings and switch the toggle on. Once activated, the event will be broadcast on all channel types except Presence channels.
Pusher broadcasts the event to all clients connected to a channel whenever a new client subscribes or unsubscribes. On channels with more than 100 connected clients, the event is sent every 5 seconds as long as there is activity (subscribe or unsubscribe) on the channel.
channel.bind("pusher:subscription_count", (data) => {
console.log(data.subscription_count);
console.log(channel.subscription_count);
});
NOTE:
This Subscription Count event is available for all channel types except Presence channels.
∞ Additional presence events
Presence comes with a number of presence-specific events. For more information, refer to Events in Presence Channels.
∞ Triggering client events
Not all traffic needs to go via your conventional web server when using Channels. Some actions may not need validation or persistence. They can go directly via the socket to all the other clients connected to the channel.
IMPORTANT:
Apply additional care when using client events, since these originate from other users, and could be subject to tampering by a malicious user of your site.
NOTE:
You cannot trigger client events from the debug console.
Client events have a number of enforced restrictions to ensure that the user subscribing to the channel is an authorized 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 Channels 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 authorization
- Client events must be prefixed by
client-
. Events with any other prefix will be rejected by the Channels 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 Channels. 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);
channel.trigger(eventName: eventName, data: data)
channel.whisper(eventName, data);
- ∞ eventNameString Required
-
The name of the event which will be triggered. A client event must have a name prefixed with
client-
. Otherwise, it will be rejected by the server.
- ∞ dataObject Required
-
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", () => {
var triggered = channel.trigger("client-someEventName", {
your: "data",
});
});
- ∞ eventNameString Required
-
The name of the event which will be triggered. If the event name is not prefixed with
client-
, the library will prepend it.
- ∞ dataObject Optional
-
The object to be converted to JSON and distributed with the event.
∞ Example
let myPrivateChannel = pusher.subscribe("private-chat")
myPrivateChannel.trigger(eventName: "myevent", data: ["foo": "bar"])
- ∞ eventNameString Required
-
The name of the event which will be triggered. A client event must have a name prefixed with
client-
. Otherwise, it will be rejected by the server.
- ∞ dataObject Optional
-
The object to be converted to JSON and distributed with the event.
∞ Example
window.Echo = new Echo({
broadcaster: "pusher",
key: "YOUR_APP_KEY",
cluster: "eu",
forceTLS: true,
});
var channel = Echo.channel("private-channel");
var callback = (data) => {};
channel.listen("pusher:subscription_succeeded", () => {
var triggered = channel.whisper("someeventname", {
your: "data",
});
});
∞ 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 Excluding event recipients.
∞ Best practice when sending client events
Apart from 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. Only the required information should be sent at the right time. With this in mind, we’ve come up with a few best practice for you to follow when triggering 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. For example, 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 Channels.
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
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);
var onMouseMove = (ev) => {
ev = ev || window.event;
state.currentX = ev.pageX || ev.clientX;
state.currentY = ev.pageY || ev.clientY;
};
setInterval(() => {
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
∞ user_id
in client events
When you bind to client events on presence channels, your bound callback will be called with a metadata object as the second argument. This metadata object contains a user_id
key, the value of which is the user_id
of the client that triggered the event, as taken from the authorization token generated by your server for that client.
const channel = pusher.subscribe("presence-chat");
channel.bind("client-msg", (data, metadata) => {
console.log(
"I received",
data,
"from user",
metadata.user_id,
"with user info",
channel.members.get(metadata.user_id).info
);
});
The user_id
field is useful for displaying the author of an event. You should trust the user_id
from the metadata
object, rather than embedding a user ID in the data
object, which would allow any client to impersonate any user!
When you bind to client events on presence channels, your bound callback will be called with a PusherEvent
object as the only argument. This object has a userId
key, accessible by calling getUserId()
on the event. The value of this is the user_id
of the client that triggered the event, as taken from the authorization token generated by your server for that client.
channel.bind("client-my-event", new SubscriptionEventListener() {
@Override
public void onEvent(PusherEvent event) {
System.out.println("Received event with userId: " + event.getUserId());
}
});
The getUserId()
method is useful for displaying the author of an event. You should trust the user ID returned by getUserId()
, rather than embedding a user ID in the data
object, which would allow any client to impersonate any user!
When you bind to client events on presence channels, your bound callback will be called with a PusherEvent
object as the only argument. This object has a userId
property. The value of this is the user_id
of the client that triggered the event, as taken from the authorization token generated by your server for that client.
channel.bind(eventName: "client-my-event", eventCallback: {(event: PusherEvent) in
if let userId = event.userId {
print("Received event with userId: \(userId)")
}
})
The userId
property is useful for displaying the author of an event. You should trust the userId
from the PusherEvent
object, rather than embedding a user ID in the data
object, which would allow any client to impersonate any user!