> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-llms-scoped-indexes.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> Listen to UI Kit events for user actions, group changes, messages, and call lifecycle updates using CometChatEvents SharedFlow.

<Accordion title="AI Integration Quick Reference">
  | Field | Value |
  | - | - |
  | Kotlin (XML Views) | `com.cometchat:chatuikit-kotlin-android` |
  | Jetpack Compose | `com.cometchat:chatuikit-compose-android` |
  | Import | `com.cometchat.uikit.core.events.CometChatEvents` |
  | Event flows | `CometChatEvents.messageEvents`, `CometChatEvents.callEvents`, `CometChatEvents.conversationEvents`, `CometChatEvents.groupEvents`, `CometChatEvents.userEvents`, `CometChatEvents.uiEvents` |
  | Pattern | Kotlin `SharedFlow` with sealed class event types — collect in `viewModelScope` or `lifecycleScope` |
  | Purpose | Decoupled communication between UI Kit components — subscribe to event flows to react to changes without direct component references |
</Accordion>

Events enable a decoupled, flexible architecture in the CometChat UI Kit. Components emit events via the `CometChatEvents` singleton, and other parts of your application collect these `SharedFlow` streams to react without direct references between components.

## When to use this

* You need to update your UI when a user is blocked or unblocked.
* You need to respond to group actions such as member joins, kicks, bans, or ownership transfers.
* You need to track conversation deletions or updates in real time.
* You need to react to messages being sent, edited, deleted, or read.
* You need to handle call lifecycle events (outgoing, accepted, rejected, ended).
* You need to respond to UI-level events such as panel visibility changes or active chat changes.

## Prerequisites

* The `com.cometchat:chatuikit-kotlin-android` or `com.cometchat:chatuikit-compose-android` dependency added to your project.
* `CometChatUIKit.init()` called and completed successfully.
* A logged-in CometChat user (call `CometChatUIKit.login()` before collecting events).

## CometChatEvents Singleton

All events are accessed through the `CometChatEvents` singleton in `chatuikit-core`. Each domain has a dedicated `SharedFlow` that emits sealed class event types:

```kotlin theme={null}
import com.cometchat.uikit.core.events.CometChatEvents
import com.cometchat.uikit.core.events.CometChatMessageEvent
```

| Flow | Sealed Class | Description |
| - | - | - |
| `CometChatEvents.messageEvents` | `CometChatMessageEvent` | Message sent, edited, deleted, read, reactions |
| `CometChatEvents.callEvents` | `CallEvent` | Call initiated, accepted, rejected, ended |
| `CometChatEvents.conversationEvents` | `ConversationEvent` | Conversation deleted, updated |
| `CometChatEvents.groupEvents` | `GroupEvent` | Group created, deleted, member changes |
| `CometChatEvents.userEvents` | `UserEvent` | User blocked, unblocked |
| `CometChatEvents.uiEvents` | `UIEvent` | Panel visibility, active chat changes |
| `CometChatEvents.threadEvents` | `CometChatThreadEvent` | Thread subscription state changes |

## API reference

### Message Events

`CometChatEvents.messageEvents` emits `CometChatMessageEvent` sealed class instances when messages are sent, edited, deleted, or read.

**Event types:**

| Event | Description |
| - | - |
| `CometChatMessageEvent.MessageSent(message, status)` | Triggered when a message is sent. Status can be `inProgress` or `sent`. |
| `CometChatMessageEvent.MessageEdited(message, status)` | Triggered when a message is edited. Status can be `inProgress` or `sent`. |
| `CometChatMessageEvent.MessageDeleted(message)` | Triggered when a message is deleted. |
| `CometChatMessageEvent.MessageRead(message)` | Triggered when a message is read. |
| `CometChatMessageEvent.LiveReaction(icon)` | Triggered when a live reaction is sent. |
| `CometChatMessageEvent.InteractionGoalCompleted(message)` | Triggered when an interaction goal is completed. |
| `CometChatMessageEvent.MessagePinned(message)` | Triggered when a message is pinned. |
| `CometChatMessageEvent.MessageUnpinned(message)` | Triggered when a message is unpinned. |
| `CometChatMessageEvent.MessageSaved(message)` | Triggered when the logged-in user saves a message. |
| `CometChatMessageEvent.MessageUnsaved(message)` | Triggered when the logged-in user unsaves a message. |

**Collecting events:**

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin theme={null}
    // In an Activity or Fragment — use lifecycleScope
    lifecycleScope.launch {
        CometChatEvents.messageEvents.collect { event ->
            when (event) {
                is CometChatMessageEvent.MessageSent -> {
                    val message = event.message
                    val status = event.status
                    // Update UI when message is sent
                }
                is CometChatMessageEvent.MessageEdited -> {
                    val message = event.message
                    // Update UI when message is edited
                }
                is CometChatMessageEvent.MessageDeleted -> {
                    val message = event.message
                    // Remove message from UI
                }
                is CometChatMessageEvent.MessageRead -> {
                    val message = event.message
                    // Update read receipts
                }
                is CometChatMessageEvent.LiveReaction -> {
                    val icon = event.icon
                    // Show live reaction animation
                }
                is CometChatMessageEvent.InteractionGoalCompleted -> { /* Handle goal completion */ }
                else -> { /* Other events: MessagePinned, MessageSaved, ReactionAdded, TypingStarted, etc. */ }
            }
        }
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin theme={null}
    @Composable
    fun MessageEventsHandler() {
        LaunchedEffect(Unit) {
            CometChatEvents.messageEvents.collect { event ->
                when (event) {
                    is CometChatMessageEvent.MessageSent -> {
                        val message = event.message
                        val status = event.status
                        // Update UI when message is sent
                    }
                    is CometChatMessageEvent.MessageEdited -> {
                        val message = event.message
                        // Update UI when message is edited
                    }
                    is CometChatMessageEvent.MessageDeleted -> {
                        val message = event.message
                        // Remove message from UI
                    }
                    is CometChatMessageEvent.MessageRead -> {
                        val message = event.message
                        // Update read receipts
                    }
                    is CometChatMessageEvent.LiveReaction -> {
                        val icon = event.icon
                        // Show live reaction animation
                    }
                    is CometChatMessageEvent.InteractionGoalCompleted -> { /* Handle goal completion */ }
                    else -> { /* Other events: MessagePinned, MessageSaved, ReactionAdded, TypingStarted, etc. */ }
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

> **What this does:** Collects the `messageEvents` SharedFlow and pattern-matches on the sealed class to handle each message lifecycle event.

***

### Thread Events

`CometChatEvents.threadEvents` emits `CometChatThreadEvent` instances when the logged-in user subscribes to or unsubscribes from a message thread, so every surface showing a subscription control can stay in sync without a refetch.

Every event on this bus is published by the UI Kit itself — the Chat SDK has no thread listener, and a `subscribeToThread()` / `unsubscribeFromThread()` callback *is* the acknowledgement. Because surfaces do not share message instances, a handler should update its own state **and** stamp the flag onto the message objects it holds with `BaseMessage.setThreadSubscribed()`.

**Event types:**

| Event | Description |
| - | - |
| `CometChatThreadEvent.SubscriptionChanged(parentMessageId: Long, subscribed: Boolean)` | Triggered when the logged-in user's subscription state for a thread changes. |

**Collecting events:**

```kotlin theme={null}
lifecycleScope.launch {
    CometChatEvents.threadEvents.collect { event ->
        when (event) {
            is CometChatThreadEvent.SubscriptionChanged -> {
                // Update your subscription control for event.parentMessageId
                // and stamp the flag onto the message object(s) you hold:
                // parentMessage.setThreadSubscribed(event.subscribed)
            }
        }
    }
}
```

See the [Thread Subscription guide](/ui-kit/android/guide-thread-subscription) for the feature end to end.

### Call Events

`CometChatEvents.callEvents` emits `CallEvent` sealed class instances for call lifecycle changes.

**Event types:**

| Event | Description |
| - | - |
| `CallEvent.OutgoingCall(call)` | Triggered when the logged-in user initiates an outgoing call. |
| `CallEvent.Accepted(call)` | Triggered when a call is accepted. |
| `CallEvent.Rejected(call)` | Triggered when a call is rejected. |
| `CallEvent.Ended(call)` | Triggered when a call is ended. |

**Collecting events:**

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin theme={null}
    lifecycleScope.launch {
        CometChatEvents.callEvents.collect { event ->
            when (event) {
                is CallEvent.OutgoingCall -> {
                    val call = event.call
                    // Handle outgoing call initiated
                }
                is CallEvent.Accepted -> {
                    val call = event.call
                    // Handle call accepted
                }
                is CallEvent.Rejected -> {
                    val call = event.call
                    // Handle call rejected
                }
                is CallEvent.Ended -> {
                    val call = event.call
                    // Handle call ended
                }
            }
        }
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin theme={null}
    @Composable
    fun CallEventsHandler() {
        LaunchedEffect(Unit) {
            CometChatEvents.callEvents.collect { event ->
                when (event) {
                    is CallEvent.OutgoingCall -> {
                        // Handle outgoing call initiated
                    }
                    is CallEvent.Accepted -> {
                        // Handle call accepted
                    }
                    is CallEvent.Rejected -> {
                        // Handle call rejected
                    }
                    is CallEvent.Ended -> {
                        // Handle call ended
                    }
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

***

### Conversation Events

`CometChatEvents.conversationEvents` emits `ConversationEvent` sealed class instances when conversations are deleted or updated.

**Event types:**

| Event | Description |
| - | - |
| `ConversationEvent.Deleted(conversation)` | Triggered when the logged-in user deletes a conversation. |
| `ConversationEvent.Updated(conversation)` | Triggered when there is an update in the conversation. |

**Collecting events:**

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin theme={null}
    lifecycleScope.launch {
        CometChatEvents.conversationEvents.collect { event ->
            when (event) {
                is ConversationEvent.Deleted -> {
                    val conversation = event.conversation
                    // Remove conversation from UI
                }
                is ConversationEvent.Updated -> {
                    val conversation = event.conversation
                    // Update conversation in UI
                }
            }
        }
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin theme={null}
    @Composable
    fun ConversationEventsHandler() {
        LaunchedEffect(Unit) {
            CometChatEvents.conversationEvents.collect { event ->
                when (event) {
                    is ConversationEvent.Deleted -> {
                        // Remove conversation from UI
                    }
                    is ConversationEvent.Updated -> {
                        // Update conversation in UI
                    }
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

***

### Group Events

`CometChatEvents.groupEvents` emits `GroupEvent` sealed class instances when the logged-in user performs group-related actions.

**Event types:**

| Event | Description |
| - | - |
| `GroupEvent.Created(group)` | Triggered when the logged-in user creates a group. |
| `GroupEvent.Deleted(group)` | Triggered when the logged-in user deletes a group. |
| `GroupEvent.Left(actionMessage, leftUser, leftGroup)` | Triggered when the logged-in user leaves a group. |
| `GroupEvent.MemberScopeChanged(actionMessage, updatedUser, scopeChangedTo, scopeChangedFrom, group)` | Triggered when a member's scope is changed. |
| `GroupEvent.MemberBanned(actionMessage, bannedUser, bannedBy, bannedFrom)` | Triggered when a member is banned from a group. |
| `GroupEvent.MemberKicked(actionMessage, kickedUser, kickedBy, kickedFrom)` | Triggered when a member is kicked from a group. |
| `GroupEvent.MemberUnBanned(actionMessage, unbannedUser, unBannedBy, unBannedFrom)` | Triggered when a member is unbanned from a group. |
| `GroupEvent.MemberJoined(joinedUser, joinedGroup)` | Triggered when the logged-in user joins a group. |
| `GroupEvent.MemberAdded(actionMessages, usersAdded, userAddedIn, addedBy)` | Triggered when members are added to a group. |
| `GroupEvent.OwnershipChanged(group, newOwner)` | Triggered when group ownership is transferred. |

**Collecting events:**

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin theme={null}
    lifecycleScope.launch {
        CometChatEvents.groupEvents.collect { event ->
            when (event) {
                is GroupEvent.Created -> {
                    val group = event.group
                    // Add new group to UI
                }
                is GroupEvent.Deleted -> {
                    val group = event.group
                    // Remove group from UI
                }
                is GroupEvent.Left -> {
                    val leftUser = event.leftUser
                    val leftGroup = event.leftGroup
                    // Handle user leaving group
                }
                is GroupEvent.MemberScopeChanged -> {
                    val updatedUser = event.updatedUser
                    val newScope = event.scopeChangedTo
                    // Update member scope in UI
                }
                is GroupEvent.MemberBanned -> {
                    val bannedUser = event.bannedUser
                    // Remove banned user from member list
                }
                is GroupEvent.MemberKicked -> {
                    val kickedUser = event.kickedUser
                    // Remove kicked user from member list
                }
                is GroupEvent.MemberUnBanned -> {
                    val unbannedUser = event.unbannedUser
                    // Handle unbanned user
                }
                is GroupEvent.MemberJoined -> {
                    val joinedUser = event.joinedUser
                    // Add user to member list
                }
                is GroupEvent.MemberAdded -> {
                    val usersAdded = event.usersAdded
                    // Add users to member list
                }
                is GroupEvent.OwnershipChanged -> {
                    val newOwner = event.newOwner
                    // Update group owner in UI
                }
            }
        }
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin theme={null}
    @Composable
    fun GroupEventsHandler() {
        LaunchedEffect(Unit) {
            CometChatEvents.groupEvents.collect { event ->
                when (event) {
                    is GroupEvent.Created -> { /* Add new group to UI */ }
                    is GroupEvent.Deleted -> { /* Remove group from UI */ }
                    is GroupEvent.Left -> { /* Handle user leaving group */ }
                    is GroupEvent.MemberScopeChanged -> { /* Update member scope */ }
                    is GroupEvent.MemberBanned -> { /* Remove banned user */ }
                    is GroupEvent.MemberKicked -> { /* Remove kicked user */ }
                    is GroupEvent.MemberUnBanned -> { /* Handle unbanned user */ }
                    is GroupEvent.MemberJoined -> { /* Add user to member list */ }
                    is GroupEvent.MemberAdded -> { /* Add users to member list */ }
                    is GroupEvent.OwnershipChanged -> { /* Update group owner */ }
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

***

### User Events

`CometChatEvents.userEvents` emits `UserEvent` sealed class instances when the logged-in user blocks or unblocks another user.

**Event types:**

| Event | Description |
| - | - |
| `UserEvent.Blocked(user)` | Triggered when the logged-in user blocks another user. |
| `UserEvent.Unblocked(user)` | Triggered when the logged-in user unblocks another user. |

**Collecting events:**

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin theme={null}
    lifecycleScope.launch {
        CometChatEvents.userEvents.collect { event ->
            when (event) {
                is UserEvent.Blocked -> {
                    val user = event.user
                    // Update UI to reflect blocked user
                }
                is UserEvent.Unblocked -> {
                    val user = event.user
                    // Update UI to reflect unblocked user
                }
            }
        }
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin theme={null}
    @Composable
    fun UserEventsHandler() {
        LaunchedEffect(Unit) {
            CometChatEvents.userEvents.collect { event ->
                when (event) {
                    is UserEvent.Blocked -> {
                        // Update UI to reflect blocked user
                    }
                    is UserEvent.Unblocked -> {
                        // Update UI to reflect unblocked user
                    }
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

***

### UI Events

`CometChatEvents.uiEvents` emits `CometChatUIEvent` sealed class instances for UI-level actions such as panel visibility and active chat changes.

**Event types:**

| Event | Description |
| - | - |
| `CometChatUIEvent.ShowPanel(id, alignment, view)` | Triggered to show an additional UI panel with custom elements. |
| `CometChatUIEvent.HidePanel(id, alignment)` | Triggered to hide a previously shown UI panel. |
| `CometChatUIEvent.ActiveChatChanged(id, message, user, group)` | Triggered when the active chat changes. |
| `CometChatUIEvent.OpenChat(user, group)` | Triggered to open a chat with a specific user or group. |
| `CometChatUIEvent.CardActionClicked(message, actionEvent)` | Triggered when a user taps an interactive element (button/link) inside a [card message](/sdk/android/v5/send-message#card-message) (`CardMessage`) or an AI agent card (`AIAssistantMessage`). `actionEvent` is typed `Any`; cast it to `com.cometchat.cards.actions.CometChatCardActionEvent`. |

**Collecting events:**

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin theme={null}
    lifecycleScope.launch {
        CometChatEvents.uiEvents.collect { event ->
            when (event) {
                is CometChatUIEvent.ShowPanel -> {
                    val alignment = event.alignment
                    // Show custom UI panel
                }
                is CometChatUIEvent.HidePanel -> {
                    val alignment = event.alignment
                    // Hide custom UI panel
                }
                is CometChatUIEvent.ActiveChatChanged -> {
                    val user = event.user
                    val group = event.group
                    // React to active chat change
                }
                is CometChatUIEvent.OpenChat -> {
                    val user = event.user
                    val group = event.group
                    // Navigate to chat with user or group
                }
                is CometChatUIEvent.CardActionClicked -> {
                    val message = event.message            // CardMessage or AIAssistantMessage
                    val action = event.actionEvent as CometChatCardActionEvent
                    // action.action, action.elementId, action.cardJson
                    // Handle the card / agent-card action tap
                }
                else -> { /* no-op */ }
            }
        }
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin theme={null}
    @Composable
    fun UIEventsHandler() {
        LaunchedEffect(Unit) {
            CometChatEvents.uiEvents.collect { event ->
                when (event) {
                    is CometChatUIEvent.ShowPanel -> { /* Show custom UI panel */ }
                    is CometChatUIEvent.HidePanel -> { /* Hide custom UI panel */ }
                    is CometChatUIEvent.ActiveChatChanged -> { /* React to active chat change */ }
                    is CometChatUIEvent.OpenChat -> { /* Navigate to chat */ }
                    is CometChatUIEvent.CardActionClicked -> { /* Handle the card agent-card action tap */ }
                    else -> { /* no-op */ }
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

> **About `CardActionClicked`:** The UI Kit renders card bubbles automatically (`CometChatCardBubble`) and emits this event when a user taps an action inside one — so a single subscriber handles every card action across your app. `event.message` is a `CardMessage` for standalone [card messages](/sdk/android/v5/send-message#card-message) and an `AIAssistantMessage` for cards embedded in AI agent replies. `event.actionEvent` is typed `Any`; import and cast it to `com.cometchat.cards.actions.CometChatCardActionEvent` to read its `action`, `elementId`, and `cardJson`.

***

## Lifecycle Management

Since `SharedFlow` collection is coroutine-based, lifecycle management is handled automatically:

* In XML Views, use `lifecycleScope.launch` — the coroutine is cancelled when the lifecycle owner is destroyed.
* In Jetpack Compose, use `LaunchedEffect` — the coroutine is cancelled when the composable leaves the composition.

No manual `removeListener` calls are needed, unlike the old static listener pattern.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Methods Reference" icon="code" href="/ui-kit/android/methods">
    UI Kit wrapper methods for initialization, authentication, and sending messages
  </Card>

  <Card title="Conversations" icon="comments" href="/ui-kit/android/conversations">
    Display and manage the conversation list, which reacts to conversation events
  </Card>

  <Card title="Message List" icon="messages" href="/ui-kit/android/message-list">
    Display messages in a chat, which reacts to message events
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.