# Presence The presence feature of a chat room enables online users to advertise to others that they are online. Use this feature to build online status indicators to display who is online in a chat room. Users can also share additional information such as avatar URLs or custom statuses. ## Subscribe to presence Subscribe to users' presence status by registering a listener. Presence events are emitted whenever a member enters or leaves the presence set, or updates their user data. Use the [`presence.subscribe()`](https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-js.Presence.html#subscribe)[`presence.subscribe()`](https://sdk.ably.com/builds/ably/ably-chat-swift/main/AblyChat/documentation/ablychat/presence/subscribe%28_%3A%29)[`presence.subscribe()`](https://sdk.ably.com/builds/ably/ably-chat-kotlin/main/dokka/chat/com.ably.chat/-presence/subscribe.html) method in a room to receive updates: Use the [`collectAsPresenceMembers()`](https://sdk.ably.com/builds/ably/ably-chat-kotlin/main/jetpack/chat-extensions-compose/com.ably.chat.extensions.compose/collect-as-presence-members.html) extension function to observe user presence changes reactively in Jetpack Compose: Subscribe to users' presence status with the [`usePresenceListener`](https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/functions/chat-react.usePresenceListener.html) hook. Supply an optional listener to receive presence status updates, or use the [`presenceData`](https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-react.UsePresenceListenerResponse.html#presenceData) property returned by the hook. To enter the presence set of a room, use the [`usePresence`](#set) hook instead. ```javascript const { unsubscribe } = room.presence.subscribe((event) => { console.log(`Presence event ${event.type} from ${event.member.clientId} with data ${event.member.data}`); }); ``` ```react const MyComponent = () => { const { presenceData, error } = usePresenceListener({ listener: (event) => { console.log('Presence event: ', event); }, }); return (

Presence data:

{error === undefined ? ( ) : (

Error loading presence data

)}
); }; ``` ```swift let presenceSubscription = room.presence.subscribe() for await event in presenceSubscription { print("Presence event `\(event.type)` from `\(event.member.clientId)` with data `\(event.member.data)`") } ``` ```kotlin const MyComponent = () => { // This data is only relevant when auto-entry is enabled // Once it has been used once, subsequent changes will have no effect const presenceParams = { initialData: { status: 'Online' }, }; // By default, presence will be entered when the hook mounts and left // when it subsequently unmounts. const { isPresent } = usePresence(presenceParams); return (
Presence status: {isPresent ? 'Online' : 'Offline'}
); }; ``` ```swift try await room.presence.enter(withData: ["status": "Online"]) ``` ```kotlin // import com.ably.chat.json.* room.presence.enter( jsonObject { put("status", "Online") }, ) ``` ```jetpack const MyComponent = () => { const presenceParams = { initialData: { status: 'Online' }, }; const { update, isPresent } = usePresence(presenceParams); const updatePresence = () => { update({ status: 'Away' }); }; return (
Presence status: {isPresent ? 'Online' : 'Offline'}
); }; ``` ```swift try await room.presence.update(withData: ["status": "Busy"]) ``` ```kotlin // import com.ably.chat.json.* room.presence.update( jsonObject { put("status", "Busy") }, ) ``` ```jetpack const MyComponent = () => { const presenceParams = { initialData: { status: 'Online' }, }; // Call leave explicitly to disable auto-entry and leave presence const { isPresent, leave } = usePresence(presenceParams); return (
Presence status: {isPresent ? 'Online' : 'Offline'}
); }; ``` ```swift try await room.presence.leave(withData: ["status": "Be back later!"]) ``` ```kotlin // import com.ably.chat.json.* room.presence.leave( jsonObject { put("status", "Be back later!") }, ) ``` ```jetpack import { usePresence } from '@ably/chat/react'; const MyComponent = () => { // Mount the hook without auto-entry const presenceParams = { autoEnterLeave: false, }; const { isPresent, leave, enter, update } = usePresence(presenceParams); // Manual mount behavior - enter presence when component mounts useEffect(() => { enter({ status: 'active' }); // Manual unmount behavior - leave presence when component unmounts return () => { leave({ status: 'disconnecting' }); }; }, [enter, leave]); // Update presence data when some event happens const onSomeEvent = useCallback(() => { const now = Date.now(); update({status: 'active', updated: now}); }, [update]); return (
Presence status: {isPresent ? 'Online' : 'Offline'}
); }; ```
### Multiple Presence Data Contributors Using multiple instances of `usePresence` with `autoEnterLeave` set to `true` is not recommended as the hooks maintain internal state to manage this behavior that is not shared between hooks. Furthermore, all instances of the hook use the same underlying presence instances, so calls to `enter`, `update` and `leave` can interact in unintended ways and lead to race conditions. Furthermore, the calls are PUT-like operations that replace your entire presence data payload. If you have multiple areas of your application that contribute data to presence, you can achieve this by using a central place to store your presence data. To implement this pattern, you would define a Provider or Context further up your application tree, or using a global state store such as Redux. Individual areas of your codebase then update this value (or contribute to parts of it). A single call to `usePresence` can then be used to keep this state synchronized with presence whenever the value changes. This allows multiple distinct components to contribute to the presence data, without multiple calls to `usePresence` and importantly, without requiring them to know anything about the complete presence data. ## Presence options The following options can be set when [creating a room](https://ably.com/docs/chat/rooms#create) that are specific to presence: | Property | Description | Default | | --- | --- | --- | | enableEvents | Set whether the client has permissions to subscribe to the presence set. Calling `presence.subscribe()` is still required. | true | ## Retrieve the presence set The online presence of users can be retrieved in one-off calls. This can be used to check the status of an individual user, or return the entire presence set as an array. The `presence.get()` method may return multiple entries for the same `clientId` if the user has multiple active connections or has reconnected. When displaying presence members in UI, consider deduplicating by unique `clientId` to avoid showing duplicate users. Use the [`presence.get()`](https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-js.Presence.html#get)[`presence.get()`](https://sdk.ably.com/builds/ably/ably-chat-swift/main/AblyChat/documentation/ablychat/presence/get%28%29)[`presence.get()`](https://sdk.ably.com/builds/ably/ably-chat-kotlin/main/dokka/chat/com.ably.chat/-presence/get.html) method to retrieve an array of all users currently entered into the presence set, or individual users: ```javascript // Retrieve all users entered into presence as an array: const presentMembers = await room.presence.get(); // Retrieve the status of specific users by their clientId: const presentMember = await room.presence.get({ clientId: 'clemons123' }); ``` ```swift // Retrieve all users entered into presence as an array: let presentMembers = try await room.presence.get() // Retrieve the status of specific users by their clientId: let presentMember = try await room.presence.get(withParams: .init(clientID: "clemons123")) ``` ```kotlin // Retrieve all users entered into presence as an array: val presentMembers = room.presence.get() // Retrieve the status of specific users by their clientId: val presentMember = room.presence.get(clientId = "clemons123") ``` ```jetpack // Retrieve all users entered into presence as an array: val presentMembers = room.presence.get() // Retrieve the status of specific users by their clientId: val presentMember = room.presence.get(clientId = "clemons123") ``` Alternatively, use the [`presence.isUserPresent()`](https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-js.Presence.html#isUserPresent)[`presence.isUserPresent()`](https://sdk.ably.com/builds/ably/ably-chat-swift/main/AblyChat/documentation/ablychat/presence/isuserpresent%28withclientid%3A%29)[`presence.isUserPresent()`](https://sdk.ably.com/builds/ably/ably-chat-kotlin/main/dokka/chat/com.ably.chat/-presence/is-user-present.html) method and pass in a user's `clientId` to check whether they are online or not. This will return a boolean: ```javascript const isPresent = await room.presence.isUserPresent('clemons123'); ``` ```swift let isPresent = try await room.presence.isUserPresent(withClientID: "clemons123") ``` ```kotlin val isPresent = room.presence.isUserPresent("client-id") ``` ```jetpack val isPresent = room.presence.isUserPresent("client-id") ``` Use the [`presenceData`](https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/interfaces/chat-react.UsePresenceListener.html#presenceData) property available from the response of the `usePresence` hook to view a list of all member's presence status in the room. ### Presence member structure The following are the properties of an individual presence member: | Property | Description | Type | | -------- | ----------- | ---- | | clientId | The ID of the client this event relates to. | String | | data | The latest optional user data associated with the user. | Object | | extras | A JSON object of arbitrary key-value pairs that may contain metadata, and/or ancillary payloads related to the user's latest presence event. | JsonObject (optional) | | updatedAt | The time of the last presence event. | DateTime |