Here’s how to build apps with the who’s online feature using Pusher Presence channels and User Authentication.
Being able to see “who’s online” is an important feature for many applications. For instance, chat rooms, teams collaborating in real time on a document, audiences in a live video stream, users viewing the same web page, and players within an online game. All benefit from the visibility of who they’re interacting with.
Presence channels are the go-to solution for Pusher users working on those scenarios. This channel type notifies subscribed connections about other users joining or leaving the channel. With our User Authentication feature, it is even easier to use Presence channels. User Authentication helps automate development around identifying users trying to connect and subscribe. To learn how we use and define these Pusher-specific terms, check out the Pusher Glossary.
Let’s take a look at an application that takes advantage of the two features in tandem.
Let’s take an example of the chat room use case. How can you use User Authentication and Presence channels to implement the “who’s online” feature with rich user information?
The user_info
you choose to provide can be any identifiable. Any user-specific details that are relevant to your application. You may want users to be able to see contact information, social pages, a role, icon, nickname, or anything else.
In this case, we’re interested in seeing users’ icons, names, and the admin authority they have in the channel.
Imagine that the chat application we want to build has the following features:
The following sections will take you through the steps needed to integrate Pusher with our example chat application. Then implement the “who’s online” feature for the two chat rooms.
You can use Pusher on any client device. Whether it’s a mobile phone with Android or iOS operating system, or on any web browser. We’ll be using pusher-js which is the JavaScript client SDK for Pusher for web browsers.
If you don’t have a Pusher account yet, sign up. Now let’s get started!
Here’s how to initialize the SDK.
Client side – JavaScript
1const Pusher = require('pusher-js'); 2 3const pusher = new Pusher(APP\_KEY, { 4 cluster: APP\_CLUSTER, 5 userAuthentication: { 6 endpoint: '/pusher/user-auth', 7 } 8 channelAuthorization: { 9 endpoint: '/pusher/auth', 10 }, 11});
NOTE: You need to enter the APP_KEY
and APP_CLUSTER
which you get when you create a new Channels app on pusher.com. To get the app key and app cluster, log in to the Pusher dashboard, click the Channels project you’re working on > App Keys.
Pusher allows you to indicate which user is currently logged in. This is handy for many user-related features like server-to-user messaging and terminating user connections.
In this example, User Authentication will be used as an add-on feature to Presence Channels. This is to provide more details about the user connected.
On the client side, you need to initiate the user authentication flow:
Client side – JavaScript
pusher.signin();
This will result in an HTTP call to the user authentication endpoint /pusher/user-auth
configured above in userAuthentication
. You need to implement this endpoint in your server code.
Here’s an example implementation for this endpoint in Node.js using the [Node.js SDK](http://npmjs.com/package/pusher)(opens in a new tab) for Pusher:
Server side – Node.js
1const Pusher = require("pusher") 2const express = require("express") 3const bodyParser = require("body-parser"); 4const pusher = new Pusher({ 5 appId: APP\_ID, 6 key: APP\_KEY, 7 secret: APP\_SECRET, 8 cluster: APP\_CLUSTER, 9}); 10 11const app = express() 12app.use(bodyParser.json()); 13app.use(bodyParser.urlencoded({ extended: false })); 14 15app.post("/pusher/user-auth", async function (req, res) { 16// Find the logged in user. This step comes from your 17// system depending on Headers or Cookies 18user = whoIsLoggedIn(); 19 20const userData = { 21 id: user.id, 22 user_info: { 23 name: user.name, 24 icon: user.icon, 25 } 26} 27 const socketId = req.body.socket_id; 28 const auth = pusher.authenticateUser(socketId, userData); 29 res.send(auth); 30}); 31 32app.listen(9000);
NOTE: You need to enter the APP_ID
, APP_KEY
, APP_SECRET
, and APP_CLUSTER
. You get these when you create a new Channels app on pusher.com. To get the app key and app cluster, log in to the Pusher dashboard, click the Channels project you’re working on > App Keys.
When the user authentication endpoint is called, your server should be able to identify the currently logged in user using cookies or headers. You can further configure the HTTP call to the user authentication endpoint using userAuthentication
fields on the client SDK.
After identifying the logged in user, your server needs to provide a userData
object with the ID of the user. Additionally, you can provide more information about the user in the user_info
field. For example, their name and a link to their icon. The information is shared with other members of Presence channels when this new user joins.
Here’s a sequence diagram to illustrate the Presence channels and user authentication process workflow.
Each chat room in this application will be represented by a Presence Channel which is named using presence-
. For example, the chat room called “gaming” will use the channel presence-gaming
.
The client side of your application can subscribe to a Presence channel via the client SDK as follows:
Client side – JavaScript
const presence_gaming = pusher.subscribe('presence-gaming');
Subscribing to a Presence channel will result in an HTTP call to the channel authorization endpoint /pusher/auth
configured above in channelAuthorization
. You need to implement this endpoint in your server code. Here’s an example implementation for this endpoint in Node.js:
Server side – Node.js
1app.post("/pusher/auth", async function (req, res) { 2 const socketId = req.body.socket_id; 3 const channel = req.body.channel_name; 4 const auth = pusher.authorizeChannel(socketId, channel); 5 res.send(auth); 6});
Through this endpoint, you can allow or deny access to Presence channels depending on the logged in user. The code example allows access to all Presence channels. You can modify the code according to your needs.
On the client side, you can bind functions to be called when a user joins or leaves a Presence channel as follows.
Client side – JavaScript
1presence_gaming.bind("pusher:member_added", (member) => { 2 console.log(`Member added: ${JSON.stringify(member)}`); 3}); 4 5presence_gaming.bind("pusher:member_removed", (member) => { 6 console.log(`Member removed: ${JSON.stringify(member)}`); 7});
The member
object will look like this:
1{ 2 "id": "<id>", 3 "info": { 4 "name": "<name>", 5 "icon": "<icon>" 6 } 7}
Notice that this member
object comes from the userData
object during user authentication.
For example, a user named Emily is the first one to join the Presence channel presence-gaming
. Then another user named John joins the same channel. Emily will be notified with the pusher:member_added
event which contains a member
object with information about John. Now Emily knows that someone else is in the channel with her, and who they are.
You can also access all the members in a Presence channel as follows:
Client side – JavaScript
presence_gaming.members
Providing user information during user authentication using the userData
object is convenient as it will be shared in all presence channels that the user joins.
However, there are cases where the user information needs to be different for specific Presence channels. This use case is also supported by providing a channel-specific user information through the channel authorization endpoint as follows:
Server side – Node.js
1app.post("/pusher/auth", async function(req, res) { 2 const socketId = req.body.socket_id; 3 const channel = req.body.channel_name; 4 const channelData = { 5 user_id: `<id>`, 6 user_info: { 7 name: `<name>`, 8 icon: `<icon>` 9 } 10 } 11 const auth = pusher.authorizeChannel(socketId, channel, channelData); 12 res.send(auth); 13});
Notice that the call to authorizeChannel
has an additional parameter called channelData
. You can pass a channel specific user object using this parameter.
In the example application we’re developing for this blog post, this channel-specific user information feature is useful for the business type of chat rooms. Because the user information needs to indicate the admin of this chat room so that people know who to contact in case an admin is needed.
The server side can provide a different set of information for business channels. On the other hand, the hobbies channels can keep using the user information retrieved from User Authentication.
Here’s a code example:
Server side – Node.js
1app.post("/pusher/auth", async function(req, res) { 2 const socketId = req.body.socket_id; 3 const channel = req.body.channel_name; 4 if (channel.startsWith(`presence-business-`)) { // Find the logged in user. This step comes from your 5// system depending on Headers or Cookies 6 user = whoIsLoggedIn(); 7 const channelData = { 8 user_id: user.id, 9 user_info: { 10 name: user.id, 11 icon: user.icon, 12 isAdmin: user.isAdmin, 13 } 14 } 15 const auth = pusher.authorizeChannel(socketId, channel, channelData); 16 } else { 17 const auth = pusher.authorizeChannel(socketId, channel); 18 } 19 res.send(auth); 20});
Pusher Channels helps you to build fully-featured presence views and implement different use cases related to “who’s online”. Presence channels can be used to send realtime messages about the members of the channel, with User Authentication providing the context which identifies who the user is. You can also offer channel-specific information for each user if needed.
To get started with your next live presence project, sign up. If you need any help, reach out to our support team.