Presence channels
Presence channels
Section titled “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.
Basic usage
Section titled “Basic usage”Client-side subscription
Section titled “Client-side subscription”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");Server-side authorization
Section titled “Server-side authorization”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"); }});Channel events
Section titled “Channel events”Subscription succeeded
Section titled “Subscription succeeded”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); });});Member added
Section titled “Member added”When a new user joins the channel:
presenceChannel.bind("jetsocket:member_added", (member) => { console.log("User joined:", member.id, member.info.name); addUserToList(member);});Member removed
Section titled “Member removed”When a user leaves the channel:
presenceChannel.bind("jetsocket:member_removed", (member) => { console.log("User left:", member.id, member.info.name); removeUserFromList(member.id);});Member information
Section titled “Member information”Accessing member data
Section titled “Accessing member data”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); }});Member object structure
Section titled “Member object structure”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" }}Complete example
Section titled “Complete example”Chat room with online users
Section titled “Chat room with online users”<!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>Server-side implementation
Section titled “Server-side implementation”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 endpointapp.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 countapp.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);Use cases
Section titled “Use cases”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
Best practices
Section titled “Best practices”User information
Section titled “User information”- 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 changesfunction updateUserInfo(userId, newInfo) { jetsocket.trigger("presence-my-channel", "jetsocket:member_updated", { user_id: userId, user_info: newInfo });}Performance considerations
Section titled “Performance considerations”- 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
Security
Section titled “Security”- 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
Next steps
Section titled “Next steps”- Learn about private channels for secure communication
- Explore encrypted channels for additional security
- Check out authentication for user management
- See examples for complete application patterns