Presence Tracking
Know who's online in real-time. Track user presence across your project and handle join/leave events.
What is Presence?
Presence tracking allows you to see which actors (users, devices, or servers) are currently connected to your project. This is essential for features like:
- Online/offline indicators in chat apps
- Showing who's viewing a document
- Live user counts
- Typing indicators
presence:join, presence:leave, presence:update) are tracked at the client level, not room-scoped. Use client.on() to listen for these events. For observing presence across rooms, use Lobbies.Setting Presence
Set your presence after connecting. Presence data can include any custom fields you need:
import { NoLag } from '@nolag/js-sdk'
const client = NoLag('your_access_token')
await client.connect()
// Set presence at the client level
client.setPresence({
username: 'Alice',
status: 'online',
avatar: 'https://example.com/alice.jpg'
})
// Presence events are client-level, not room-scoped
client.on('presence:join', (actor) => {
console.log(`${actor.presence.username} joined`)
})
client.on('presence:leave', (actor) => {
console.log(`${actor.presence.username} left`)
})
client.on('presence:update', (actor) => {
console.log(`${actor.presence.username} updated status to ${actor.presence.status}`)
})Presence Events
Listen for these events to track when actors come online, go offline, or update their status:
presence:join- An actor connected and set their presencepresence:leave- An actor disconnectedpresence:update- An actor updated their presence data
Getting Current Presence
Get a list of all actors currently present. Note that getPresence() returns all actors from the local cache (not room-scoped):
// Get all present actors from local cache (client-level)
const actors = client.getPresence()
console.log('Users online:', actors.length)
actors.forEach((actor) => {
console.log(`- ${actor.presence.username} (${actor.actorTokenId})`)
})
// Fetch fresh presence list from server
const freshList = await client.fetchPresence()
console.log('Server says online:', freshList.length)Local Cache vs Server Fetch
- JavaScript:
client.getPresence()returns all,client.getPresence(actorId)returns one,client.fetchPresence()fetches from server - Python:
client.get_all_presence()returns all,client.get_presence(actor_token_id)returns one - Go:
client.GetPresence(topic)fetches presence for a specific topic from the server
The local cache is automatically updated when you receive presence events.
Updating Presence
Update your presence data at any time by calling setPresence() again:
// Update your presence data (e.g., status change)
client.setPresence({
username: 'Alice',
status: 'away',
lastActive: Date.now()
})
// Client-level presence is automatically re-sent on reconnectTyping Indicators
A common use case is showing typing indicators. Use presence updates with a debounce:
// For typing indicators, update presence with typing status
let typingTimeout: NodeJS.Timeout
function sendTyping() {
client.setPresence({
username: 'Alice',
status: 'online',
isTyping: true
})
// Clear typing after 3 seconds of inactivity
clearTimeout(typingTimeout)
typingTimeout = setTimeout(() => {
client.setPresence({
username: 'Alice',
status: 'online',
isTyping: false
})
}, 3000)
}
// Listen for typing from others (client-level event)
client.on('presence:update', (actor) => {
if (actor.presence.isTyping) {
showTypingIndicator(actor.presence.username)
} else {
hideTypingIndicator(actor.presence.username)
}
})Actor Presence Structure
Each actor presence object contains:
interface ActorPresence {
actorTokenId: string // Unique actor identifier
actorType: 'device' | 'user' | 'server'
presence: { // Your custom presence data
username?: string
status?: string
// ... any other fields you set
}
joinedAt?: number // Timestamp when actor connected
}Best Practices
- Keep presence data small - Only include necessary information (username, status, avatar URL)
- Use debouncing - For typing indicators, debounce updates to avoid flooding
- Handle reconnections - Client-level presence is automatically re-sent on reconnect
- Consider privacy - Let users opt out of presence tracking if needed
- Use fetchPresence() sparingly - The local cache is usually sufficient