Skip to content

Presence channels

Presence channels are private channels that also track who is currently subscribed. They provide information about the members of the channel, making them perfect for building features like online user lists, chat rooms, and collaborative applications.

Presence channels are identified by the presence- prefix:

const jetsocket = new Jetsocket("APP_KEY", {
cluster: "APP_CLUSTER",
channelAuthorization: {
endpoint: "/jetsocket/auth"
}
});
const presenceChannel = jetsocket.subscribe("presence-my-channel");

You need to set up an authorization endpoint that includes user information:

app.post("/jetsocket/auth", (req, res) => {
const socketId = req.body.socket_id;
const channel = req.body.channel_name;
const user = req.user;
if (canAccessChannel(user, channel)) {
const authResponse = jetsocket.authorizeChannel(socketId, channel, {
user_id: user.id,
user_info: {
name: user.name,
email: user.email,
avatar: user.avatar
}
});
res.send(authResponse);
} else {
res.status(403).send("Forbidden");
}
});

When a user successfully subscribes to a presence channel, they receive information about all current members:

presenceChannel.bind("jetsocket:subscription_succeeded", (members) => {
console.log("Current members:", members);
// members is an object with user IDs as keys
Object.values(members).forEach(member => {
console.log("Member:", member.id, member.info.name);
});
});

When a new user joins the channel:

presenceChannel.bind("jetsocket:member_added", (member) => {
console.log("User joined:", member.id, member.info.name);
addUserToList(member);
});

When a user leaves the channel:

presenceChannel.bind("jetsocket:member_removed", (member) => {
console.log("User left:", member.id, member.info.name);
removeUserFromList(member.id);
});
presenceChannel.bind("jetsocket:subscription_succeeded", (members) => {
// Get member count
const memberCount = presenceChannel.members.count;
console.log("Total members:", memberCount);
// Get all members
const allMembers = presenceChannel.members.members;
// Check if specific user is present
const isPresent = presenceChannel.members.get("user-123");
if (isPresent) {
console.log("User info:", isPresent.info);
}
// Get member by user ID
const member = presenceChannel.members.get("user-123");
if (member) {
console.log("Member found:", member.info.name);
}
});

Each member object contains:

{
id: "user-123", // User ID
info: { // User information
name: "John Doe",
email: "john@example.com",
avatar: "https://example.com/avatar.jpg"
}
}
<!DOCTYPE html>
<html>
<head>
<script src="https://js.jetsocket.io/latest/jetsocket.min.js"></script>
</head>
<body>
<div id="chat-container">
<div id="online-users">
<h3>Online Users</h3>
<ul id="users-list"></ul>
</div>
<div id="messages"></div>
<input type="text" id="message-input" placeholder="Type a message...">
<button onclick="sendMessage()">Send</button>
</div>
<script>
const jetsocket = new Jetsocket("APP_KEY", {
cluster: "APP_CLUSTER",
channelAuthorization: {
endpoint: "/jetsocket/auth"
}
});
const presenceChannel = jetsocket.subscribe("presence-chat-room");
const messagesDiv = document.getElementById("messages");
const usersList = document.getElementById("users-list");
// Handle successful subscription
presenceChannel.bind("jetsocket:subscription_succeeded", (members) => {
console.log("Joined chat room with", Object.keys(members).length, "members");
// Display all current members
Object.values(members).forEach(member => {
addUserToList(member);
});
});
// Handle new members joining
presenceChannel.bind("jetsocket:member_added", (member) => {
console.log("User joined:", member.info.name);
addUserToList(member);
// Show join notification
addMessage({
type: "system",
message: `${member.info.name} joined the chat`
});
});
// Handle members leaving
presenceChannel.bind("jetsocket:member_removed", (member) => {
console.log("User left:", member.info.name);
removeUserFromList(member.id);
// Show leave notification
addMessage({
type: "system",
message: `${member.info.name} left the chat`
});
});
// Handle new messages
presenceChannel.bind("new-message", (data) => {
addMessage(data);
});
function addUserToList(member) {
const li = document.createElement("li");
li.id = `user-${member.id}`;
li.textContent = member.info.name;
usersList.appendChild(li);
}
function removeUserFromList(userId) {
const userElement = document.getElementById(`user-${userId}`);
if (userElement) {
userElement.remove();
}
}
function addMessage(data) {
const messageDiv = document.createElement("div");
messageDiv.className = "message";
if (data.type === "system") {
messageDiv.className += " system-message";
messageDiv.textContent = data.message;
} else {
messageDiv.innerHTML = `
<strong>${data.username}:</strong> ${data.message}
`;
}
messagesDiv.appendChild(messageDiv);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
function sendMessage() {
const input = document.getElementById("message-input");
const message = input.value.trim();
if (message) {
// Trigger client event
presenceChannel.trigger("client-new-message", {
message: message
});
input.value = "";
}
}
</script>
</body>
</html>
const express = require("express");
const Jetsocket = require("jetsocket");
const app = express();
app.use(express.json());
const jetsocket = new Jetsocket({
appId: "APP_ID",
key: "APP_KEY",
secret: "APP_SECRET",
cluster: "APP_CLUSTER",
});
// Authorization endpoint
app.post("/jetsocket/auth", (req, res) => {
const socketId = req.body.socket_id;
const channel = req.body.channel_name;
const user = req.user; // From your authentication middleware
if (channel.startsWith("presence-")) {
// Authorize presence channel with user info
const authResponse = jetsocket.authorizeChannel(socketId, channel, {
user_id: user.id,
user_info: {
name: user.name,
email: user.email,
avatar: user.avatar
}
});
res.send(authResponse);
} else {
res.status(403).send("Forbidden");
}
});
// Get online users count
app.get("/online-users", async (req, res) => {
try {
const channelInfo = await jetsocket.getChannelInfo("presence-chat-room", {
info: "user_count"
});
res.json({
onlineCount: channelInfo.user_count
});
} catch (error) {
console.error("Error getting online users:", error);
res.status(500).json({ error: "Failed to get online users" });
}
});
app.listen(3000);

Presence channels are perfect for:

  • Chat applications: Show who’s online and typing
  • Collaborative tools: Track who’s working on a document
  • Gaming: Show players in a lobby or game room
  • Support systems: Show available agents
  • Live events: Track attendees and participants
  • Keep user info minimal: Only include necessary information
  • Use consistent user IDs: Ensure user IDs are unique and consistent
  • Handle user updates: Update user info when it changes
// Update user info when it changes
function updateUserInfo(userId, newInfo) {
jetsocket.trigger("presence-my-channel", "jetsocket:member_updated", {
user_id: userId,
user_info: newInfo
});
}
  • Limit channel size: Presence channels work best with reasonable numbers of users
  • Use multiple channels: Split large groups into smaller channels
  • Handle disconnections: Users may disconnect unexpectedly
  • Always authorize: Never allow unauthorized access to presence channels
  • Validate user data: Ensure user information is valid and safe
  • Monitor usage: Track presence channel usage for abuse