# Events

All changes to the chat state are exposed as events.
When a new message is sent, a reaction is added, or any other action occurs, the client receives an event in real-time.
You can also send custom events, enabling you to build your own pub/sub functionality on top of a channel.

### Listening for Events

The code sample below shows how to listen to events:

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
channel.on("message.new", (event) => {
  console.log("received a new message", event.message.text);
});

channel.on("message.deleted", (event) => {
  console.log("message was deleted", event.message.id);
});
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val channelClient = client.channel("messaging", "general")

// Subscribe for new message events
val disposable: Disposable = channelClient.subscribeFor<NewMessageEvent> { newMessageEvent ->
  val message = newMessageEvent.message
}

// Dispose when you want to stop receiving events
disposable.dispose()
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// There are 2 ways to listen for events
// 1. Use an EventsController
class MyViewController: UIViewController, EventsControllerDelegate {
  var client: ChatClient!
  var eventsController: EventsController!

  override func viewDidLoad() {
    super.viewDidLoad()
    eventsController = client.eventsController()
    eventsController.delegate = self
  }

  func eventsController(_ controller: EventsController, didReceiveEvent event: Event) {
    // Handle any event received
    switch event {
    case let event as MessageNewEvent:
      // handle MessageNewEvent
    default:
      break
    }
  }
}
// 2. Use the appropriate controller's delegate methods
// ChannelController delegate methods to listen Channel events
// CurrentUserController delegate methods to listen Current User events
/// * Delegates *

class ChannelViewController: ChatChannelControllerDelegate {
  func channelController(_ channelController: ChatChannelController, didUpdateMessages changes: [ListChange<ChatMessage>]) {
    // animate the changes to the message list
  }
}

let channelViewController = ChannelViewController()

channelController.delegate = channelViewController

/// * Combine *

channelController.messagesChangesPublisher
  .receive(on: RunLoop.main)
  .sink { changes in
    // animate the changes to the message list
  }
  .store(in: &cancellables)
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
channel.on("message.new").listen((Event event) {
 print("new message: ${event.message.text}");
});

channel.on("message.deleted").listen((Event event) {
 print("message ${event.message.id} was deleted");
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
ChannelClient channelClient = client.channel("messaging", "general");

// Subscribe for new message events
Disposable disposable = channelClient.subscribeFor(
    new Class[]{NewMessageEvent.class},
    event -> {
        NewMessageEvent newMessageEvent = (NewMessageEvent) event;
        Message message = newMessageEvent.getMessage();
    }
);

// Dispose when you want to stop receiving events
disposable.dispose();
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
// Subscribing via a UOBJECT member function
Channel->On<FMessageDeletedEvent>(this, &UMyObject::OnMessageDeleted);

// Subscribing via a lambda function
Channel->On<FMessageDeletedEvent>(
  [](const FMessageDeletedEvent& Event)
  {
    // Message was deleted
  });
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Get a single channel
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, "my-channel-id");

// Or multiple with optional filters
var channels = await Client.QueryChannelsAsync(new List<IFieldFilterRule>()
{
  ChannelFilter.Members.In(Client.LocalUserData.User)
});

// Subscribe to events
channel.MessageReceived += OnMessageReceived;
channel.MessageUpdated += OnMessageUpdated;
channel.MessageDeleted += OnMessageDeleted;

channel.ReactionAdded += OnReactionAdded;
channel.ReactionUpdated += OnReactionUpdated;
channel.ReactionRemoved += OnReactionRemoved;

channel.MemberAdded += OnMemberAdded;
channel.MemberRemoved += OnMemberRemoved;
channel.MemberUpdated += OnMemberUpdated;

channel.MembersChanged += OnMembersChanged;
channel.VisibilityChanged += OnVisibilityChanged;
channel.MuteChanged += OnMuteChanged;
channel.Truncated += OnTruncated;
channel.Updated += OnUpdated;
channel.WatcherAdded += OnWatcherAdded;
channel.WatcherRemoved += OnWatcherRemoved;
channel.UserStartedTyping += OnUserStartedTyping;
channel.UserStoppedTyping += OnUserStoppedTyping;
channel.TypingUsersChanged += OnTypingUsersChanged;
```

</codetabs-item>

</codetabs>

You can also listen to all events at once:

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
channel.on((event) => {
  console.log("event", event);
  console.log("channel.state", channel.state);
});
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val disposable: Disposable = channelClient.subscribe { event: ChatEvent ->
  when (event) {
    // Check for specific event types
    is NewMessageEvent -> {
      val message = event.message
    }
  }
}

// Dispose when you want to stop receiving events
disposable.dispose()
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// There are 2 ways to listen for events
// 1. Use an EventsController
class MyViewController: UIViewController, EventsControllerDelegate {
  var client: ChatClient!
  var eventsController: EventsController!

  override func viewDidLoad() {
    super.viewDidLoad()
    eventsController = client.eventsController()
    eventsController.delegate = self
  }

  func eventsController(_ controller: EventsController, didReceiveEvent event: Event) {
    // Handle any event received
    switch event {
    case let event as MessageNewEvent:
      // handle MessageNewEvent
    default:
      break
    }
  }
}
// 2. Use the appropriate controller's delegate methods
// ChannelController delegate methods to listen Channel events
// CurrentUserController delegate methods to listen Current User events
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
channel.on().listen((Event event) {
 print("received a new event of type ${event.type}");
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
Disposable disposable = channelClient.subscribe(event -> {
    if (event instanceof NewMessageEvent) {
        Message message = ((NewMessageEvent) event).getMessage();
    }
});

// Dispose when you want to stop receiving events
disposable.dispose();
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
// Not supported in the Unreal SDK
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Not supported in the Unity SDK
```

</codetabs-item>

</codetabs>

### Event Types

There are different type of events

- User level/connection level events. You always receive these events.
- Notification events you receive if you are a member of the channel
- Channel level events you receive if you are watching the channel
- User presence events are sent when you specify presence=true
- Custom events. Your own pub/sub on top of the chat channel.

The example below shows how to watch a channel and enable user presence events.
You can also watch channels and enable user presence when using query channels.
See these links for more details on user presence, watching and query channels.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Watch a channel with presence enabled to receive user presence events
const channel = client.channel("messaging", "my-conversation-123", {
  members: ["john", "jack"],
});

const state = await channel.watch({ presence: true });

// Listen for user presence changes
channel.on("user.presence.changed", (event) => {
  console.log(
    `${event.user.name} is now ${event.user.online ? "online" : "offline"}`,
  );
});
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Watch a channel with presence enabled
val watchRequest = WatchChannelRequest().apply {
  data["members"] = listOf("john", "jack")
  presence = true
}
channelClient.watch(watchRequest).enqueue { result ->
  if (result.isSuccess) {
    val channel: Channel = result.data()
  } else {
    // Handle result.error()
  }
}

// Subscribe to presence events
client.subscribeFor<UserPresenceChangedEvent> { event ->
  // Handle presence change
}
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
class PresenceObservingChannelVC: ChatChannelVC, EventsControllerDelegate {
  let eventsController: EventsController!

  override func viewDidLoad() {
    super.viewDidLoad()

    eventsController.delegate = self
  }

  func eventsController(_ controller: EventsController, didReceiveEvent event: Event) {
    if let event = event as? UserPresenceChangedEvent {
      showUser(event.user, isOnline: event.user.isOnline)
    }
  }
}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// Watch a channel with presence enabled to receive user presence events
final channel = client.channel(
  'messaging',
  id: 'my-conversation-123',
  extraData: {
    'members': ['john', 'jack'],
  },
);

await channel.watch({
  'presence': true,
});

// Listen for user presence changes
channel.on('user.presence.changed').listen((event) {
  print('${event.user?.name} is now ${event.user?.online == true ? "online" : "offline"}');
});
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
// Watch a channel with presence enabled
constexpr EChannelFlags AllFlags = EChannelFlags::Watch | EChannelFlags::State | EChannelFlags::Presence;
const FChannelProperties Properties{TEXT("messaging"), TEXT("my-conversation-123")};
Client->QueryChannel(Properties, AllFlags);

// Subscribe to presence events
Client->On<FUserPresenceChangedEvent>(
  [](const FUserPresenceChangedEvent& Event)
  {
    // Handle presence change
  });
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Watch a channel with presence enabled
WatchChannelRequest watchRequest = new WatchChannelRequest();
watchRequest.setPresence(true);
watchRequest.getData().put("members", Arrays.asList("john", "jack"));
channelClient.watch(watchRequest).enqueue(result -> {
  if (result.isSuccess()) {
    Channel channel = result.data();
  } else {
    // Handle result.error()
  }
});

// Subscribe to presence events
client.subscribeFor(
    new Class[]{UserPresenceChangedEvent.class},
    event -> {
      // Handle presence change
    }
);
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Get a channel
var channel = await Client.GetOrCreateChannelWithIdAsync(ChannelType.Messaging, "my-channel-id");

// Each user object exposes the PresenceChanged event
foreach (var member in channel.Members)
{
  member.User.PresenceChanged += (userObj, isOnline, isActive) =>
  {
    // Handle presence change
  };
}
```

</codetabs-item>

</codetabs>

### Connection Events

The official SDKs make sure that a connection to Stream is kept alive at all times and that chat state is recovered when the user's internet connection comes back online. Your application can subscribe to changes to the connection using client events.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
client.on("connection.changed", (e) => {
  if (e.online) {
    console.log("the connection is up!");
  } else {
    console.log("the connection is down!");
  }
});
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
client.subscribeFor(
  ConnectedEvent::class,
  ConnectingEvent::class,
  DisconnectedEvent::class,
) { event ->
  when (event) {
    is ConnectedEvent -> {
      // Socket is connected
    }
    is ConnectingEvent -> {
      // Socket is connecting
    }
    is DisconnectedEvent -> {
      // Socket is disconnected
    }
  }
}
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
let connectionController = client.connectionController()

class ConnectionDelegate: ChatConnectionControllerDelegate {
  func connectionController(_ controller: ChatConnectionController,
               didUpdateConnectionStatus status: ConnectionStatus) {
     // handle connection change
  }
}

connectionController.delegate = ConnectionDelegate()
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
client.on('connection.changed', (e) {
  if (e.online) {
    print('the connection is up!');
  } else {
    print('the connection is down!');
  }
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
client.subscribeFor(
    new Class[]{ConnectedEvent.class, ConnectingEvent.class, DisconnectedEvent.class},
    event -> {
        if (event instanceof ConnectedEvent) {
            // Socket is connected
        } else if (event instanceof ConnectingEvent) {
            // Socket is connecting
        } else if (event instanceof DisconnectedEvent) {
            // Socket is disconnected
        }
    }
);
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
Client->On<FConnectionChangedEvent>(
  [](const FConnectionChangedEvent& Event)
  {
    if (Event.bOnline)
    {
      // Came online
    } else
    {
      // Went offline
    }
  });
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
public void SubscribeToConnectionEvents()
{
  Client.Connected += OnConnected;
  Client.Disconnected += OnDisconnected;
  Client.ConnectionStateChanged += OnConnectionStateChanged;
}

private void OnConnected(IStreamLocalUserData localUserData)
{
}

private void OnDisconnected()
{
}

private void OnConnectionStateChanged(ConnectionState previous, ConnectionState current)
{
}
```

</codetabs-item>

</codetabs>

### Stop Listening for Events

It is a good practice to unregister event handlers once they are not in use anymore. Doing so will save you from performance degradations coming from memory leaks or even from errors and exceptions (i.e. null pointer exceptions)

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// remove the handler from all client events
// const myClientEventListener = client.on('connection.changed', myClientEventHandler)
myClientEventListener.unsubscribe();

// remove the handler from all events on a channel
// const myChannelEventListener = channel.on('connection.changed', myChannelEventHandler)
myChannelEventListener.unsubscribe();
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val disposable: Disposable = client.subscribe { /* ... */ }
disposable.dispose()
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// There are 2 ways to listen for events
// 1. Use an EventsController
class MyViewController: UIViewController, EventsControllerDelegate {
  var client: ChatClient!
  var eventsController: EventsController!

  override func viewDidLoad() {
    super.viewDidLoad()
    eventsController = client.eventsController()
    eventsController.delegate = self

    // stop listening for events
    eventsController = nil
  }

  func eventsController(_ controller: EventsController, didReceiveEvent event: Event) {
    // Handle any event received
    switch event {
    case let event as MessageNewEvent:
      // handle MessageNewEvent
    default:
      break
    }
  }
}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final subscription = channel.on().listen((Event event) {
 print("received a new event of type ${event.type}");
});

subscription.cancel();
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
Disposable disposable = client.subscribe(event -> { /* ... */ });
disposable.dispose();
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
// Subscribe
const FDelegateHandle Handle = Client->On<FHealthCheckEvent>(this, &UMyObject::OnHealthCheck);

// Unsubscribe
const bool bSuccess = Client->Unsubscribe<FHealthCheckEvent>(Handle);
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
Client.Connected -= OnConnected;
Client.Disconnected -= OnDisconnected;
Client.ConnectionStateChanged -= OnConnectionStateChanged;
```

</codetabs-item>

</codetabs>

### Custom Events

Custom events allow you to build your own pub/sub functionality on top of a channel. You can send any event with custom data and have it delivered to all users watching the channel.

#### To a channel

Users connected to a channel, either as a watcher or member, can send custom events and have them delivered to all users [watching the channel](/chat/docs/<framework>/creating_channels/).

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// sends an event for the current user to all connect clients on the channel
await channel.sendEvent({
  type: "friendship_request",
  text: "Hey there, long time no see!",
});

// custom events can also be sent server-side, in that case a user must be included in the event payload
await channel.sendEvent({
  type: "friendship_request",
  text: "Hey there, long time no see!",
  user: user,
});
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
val channelClient = client.channel("messaging", "general")

// Send a custom event to all users watching the channel
channelClient.sendEvent(
  eventType = "friendship_request",
  extraData = mapOf("text" to "Hey there, long time no see!")
).enqueue { result ->
  if (result.isSuccess) {
    val chatEvent: ChatEvent = result.data()
  } else {
    // Handle result.error()
  }
}

// Subscribe for custom events
val disposable: Disposable = channelClient.subscribeFor<UnknownEvent> { customEvent ->
  val text = customEvent.rawData["text"]
}

// Dispose when you want to stop receiving events
disposable.dispose()
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
struct MyCustomEvent: CustomEventPayload {
  static let eventType: EventType = "my_custom_event"

  let text: String
}

// Send channel events using the channel controller
let event = MyCustomEvent(text: "This is my custom text")
channelController.eventsController().sendEvent(event)

// Subscribe for custom events works with delegation pattern
extension MyChannelViewModel: EventsControllerDelegate {

  private var eventsController: EventsController?

  func setupEventListening(channelController: ChatChannelController) {
    // eventsController needs to be retained (eg. class var)
    eventsController = channelController.eventsController()
    eventsController?.delegate = self
  }

  // EventsControllerDelegate method
  func eventsController(_: EventsController, didReceiveEvent event: Event) {
    // ignore regular events, we only care about custom channel event
    guard let channelEvent = event as? UnknownChannelEvent else {
      return
    }

    // Filter only `MyCustomEvent` event
    guard let customPayload = channelEvent.payload(ofType: MyCustomEvent.self) else {
      return
    }

    print("Received a custom event with text \(myCustomPayload.text)")
  }
}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// sends an event for the current user to all connect clients on the channel
await channel.sendEvent(
  Event(
   type: 'friendship_request',
   extraData: {
    'text': 'Hey there, long time no see!',
   },
  ),
);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
Map<Object, Object> extraData = new HashMap<>();
extraData.put("text", "Hey there, long time no see!");

// Send a custom event to all users watching the channel
channelClient.sendEvent("friendship_request", extraData).enqueue(result -> {
  if (result.isSuccess()) {
    ChatEvent chatEvent = result.data();
  } else {
    // Handle result.error()
  }
});
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
// Custom events must be defined as a USTRUCT with a static FName member `StaticType`:
USTRUCT()
struct FMyCustomEvent
{
  GENERATED_BODY()

  inline static FName StaticType = TEXT("my_custom_event");

  // Custom members must be UPROPERTYs to be picked up by the serializer
  UPROPERTY()
  float MyCustomData;
};

// Send the custom event
Channel->SendEvent(FMyCustomEvent{5000.f});
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$channel->sendEvent(["type" => "friendship_request", "text" => "Hey there, long time no see!"], $serverUser["id"]);
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
channel.send_event({"type": "friendship_request", "text": "Hey there, long time no see!"}, server_user["id"])
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
# require 'stream-chat'

channel.send_event({type: "friendship_request", text: "Hey there, long time no see!"}, server_user["id"]
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var channelEvent = new Event { Type = "friendship_request", UserId = serverUser.Id };
channelEvent.SetData("text", "Hey there, long time no see!");
await eventClient.SendEventAsync("channel-type", "channel-id", channelEvent);
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
ch.SendEvent(context.Background(), &Event{
	Type:   "friendship_request",
	ExtraData: map[string]interface{}{"text": "Hey there, long time no see!"},
}, "userId")
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Not yet supported in the Unity SDK
```

</codetabs-item>

</codetabs>

<admonition type="info">

Custom events are enabled by default on all channel types, you can disable them using the Dashboard or the API the same way as you would manage other channel features (ie. replies, URL previews, ...)

</admonition>

#### Permissions

Like every client-side API request, sending a custom event includes a permission check. By default users that can read messages on a channel can also send custom events. Check the [Auth & Permission](/chat/docs/<framework>/chat_permission_policies/) section to find out more about how permissions can be customized for your application.

<admonition type="info">

Keep in mind a clever user can send their own custom events. We recommend using the type attribute or custom data on the event to limit the kinds of events that are displayed to the recipient to ones that are safe e.g. if a bad actor sends a "password reset" or other malicious events, your client app should just ignore it.

</admonition>

#### To a user

This allows you to send custom events to a connected user. The event is delivered to all connected clients for that user.

It is only available with server-side authentication. A copy of the event is sent via web-hooks if it is enabled.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
await client.sendUserCustomEvent(targetUserID, {
  type: "friendship_request",
  text: "Tommaso wants to be your friend",
});
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
ev := UserCustomEvent{
	Type: "friendship_request",
	ExtraData: map[string]interface{}{
		"text":  "Tommaso wants to be your friend",
	},
}

err := client.SendUserCustomEvent(targetUserID, &ev)
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
$client->sendCustomEvent($user["id"], ["type" => "friendship_request", "text" => "Tommaso wants to be your friend"]);
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
Event.sendUserCustom(user.getId())
  .event(
    EventUserCustomRequestObject.builder()
      .type("friendship_request")
      .additionalField("text", "Tommaso wants to be your friend")
      .build())
  .request();
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
client.send_user_custom_event(
  server_user["id"], {"type": "friendship_request", "text": "Tommaso wants to be your friend"}
)
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
client.send_user_event(server_user[:id], { event: { type: 'friendship_request', text: 'Tommaso wants to be your friend' } })
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
var customEvent = new UserCustomEvent { Type = "friendship_request" };
customEvent.SetData("text", "Tommaso wants to be your friend");
await eventClient.SendUserCustomEventAsync(user.Id, customEvent);
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
// Not yet supported in the Unity SDK
```

</codetabs-item>

</codetabs>

| name         | type   | description       | default | optional |
| ------------ | ------ | ----------------- | ------- | -------- |
| targetUserID | string | target user ID    | -       |          |
| data         | object | event to be sent  | -       |          |
| data.type    | string | type of the event | -       |          |

If the user doesn't exist, a `404 Not Found` error is returned.

The type of the event shouldn't contain any `.` character otherwise a `400 Bad Request` error is returned. This is a character used for built-in events, see the Built-in Events section below for more details.

### Event Object

| name               | type   | description                                                                       | default | optional |
| ------------------ | ------ | --------------------------------------------------------------------------------- | ------- | -------- |
| cid                | string | Channel ID                                                                        |         | ✓        |
| type               | string | Event type                                                                        |         |          |
| message            | object | [Message Object](/chat/docs/<framework>/send_message/#message-response-structure) |         | ✓        |
| reaction           | object | [Reaction Object](/chat/docs/<framework>/send_reaction/)                          |         | ✓        |
| channel            | object | [Channel Object](/chat/docs/<framework>/creating_channels/)                       |         | ✓        |
| member             | object | User object for the channel member that was added/removed                         |         | ✓        |
| user               | object | User object of the current user                                                   |         | ✓        |
| me                 | object | User object of the health check user                                              |         | ✓        |
| total_unread_count | int    | the number of unread messages for current user                                    |         | ✓        |
| watcher_count      | int    | Number of users watching this channel                                             |         | ✓        |

### Built-in Events

The table below shows an overview of all built-in events:

| Event                              | Trigger                                                                                    | Recipients                                                                     | Type                |
| ---------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------- |
| channel.deleted                    | when a channel is deleted                                                                  | clients watching the channel                                                   | channel event       |
| channel.hidden                     | when a channel is marked as hidden                                                         | clients from the user that marked the channel as hidden (see hiding channels)  | channel event       |
| channel.truncated                  | when a channel's history is truncated                                                      | clients watching the channel                                                   | channel event       |
| channel.updated                    | when a channel is updated                                                                  | clients watching the channel                                                   | channel event       |
| channel.visible                    | when a channel is made visible                                                             | clients from the user that marked the channel as visible (see hiding channels) | channel event       |
| connection.changed                 | when the state of the connection changed                                                   | local event                                                                    | client event        |
| connection.recovered               | when the connection to chat servers is back online                                         | local event                                                                    | client event        |
| health.check                       | every 30 seconds to confirm that the client connection is still alive                      | all clients                                                                    | client event        |
| member.added                       | when a member is added to a channel                                                        | clients watching the channel                                                   | channel event       |
| member.removed                     | when a member is removed from a channel                                                    | clients watching the channel                                                   | channel event       |
| member.updated                     | when a channel member is updated (promoted to moderator/accepted/rejected the invite)      | clients watching the channel                                                   | channel event       |
| message.deleted                    | when a message is deleted                                                                  | clients watching the channel                                                   | channel event       |
| message.new                        | when a new message is added on a channel                                                   | clients watching the channel                                                   | channel event       |
| message.read                       | when a channel is marked as read                                                           | clients watching the channel                                                   | channel event       |
| message.updated                    | when a message is updated                                                                  | clients watching the channel                                                   | channel event       |
| notification.added_to_channel      | when the user is added to the list of channel members                                      | clients from the user added that are not watching the channel                  | notification event  |
| notification.channel_deleted       | when a channel is deleted                                                                  | clients from members that are not watching the channel                         | notification event  |
| notification.channel_mutes_updated | when a channel is muted                                                                    | clients from the user that muted the channel                                   | notification event  |
| notification.channel_truncated     | when a channel's history is truncated                                                      | clients from members that are not watching the channel                         | notification event  |
| notification.invite_accepted       | when the user accepts an invite                                                            | clients from the user invited that are not watching the channel                | notification event  |
| notification.invite_rejected       | when the user rejects an invite                                                            | clients from the user invited that are not watching the channel                | notification event  |
| notification.invited               | when the user is invited to join a channel                                                 | clients from the user invited that are not watching the channel                | notification event  |
| notification.mark_read             | when the total count of unread messages (across all channels the user is a member) changes | clients from the user with the new unread count                                | notification event  |
| notification.mark_unread           | when the user marks a message as unread                                                    | clients from the user with the new unread count                                | notification event  |
| notification.message_new           | when a message is added to a channel                                                       | clients that are not currently watching the channel                            | notification event  |
| notification.mutes_updated         | when the user mutes are updated                                                            | clients from the user that updated the list of mutes                           | notification event  |
| notification.removed_from_channel  | when a user is removed from the list of channel members                                    | clients from the user removed that are not watching the channel                | notification event  |
| reaction.deleted                   | when a message reaction is deleted                                                         | clients watching the channel                                                   | channel event       |
| reaction.new                       | when a message reaction is added                                                           | clients watching the channel                                                   | channel event       |
| reaction.updated                   | when a message reaction is updated                                                         | clients watching the channel                                                   | channel event       |
| typing.start                       | when a user starts typing                                                                  | clients watching the channel                                                   | channel event       |
| typing.stop                        | when a user stops typing                                                                   | clients watching the channel                                                   | channel event       |
| user.banned                        | when the user is banned                                                                    | clients for the banned user                                                    | client event        |
| user.deleted                       | when a user is deleted                                                                     | clients subscribed to the user status                                          | user presence event |
| user.messages.deleted              | when the user's messages are deleted                                                       | clients for the banned user                                                    | client event        |
| user.messages.deleted              | when the user's messages are deleted                                                       | clients watching the channel where the user was banned                         | channel event       |
| user.presence.changed              | when a user status changes (eg. online, offline, away, etc.)                               | clients subscribed to the user status                                          | user presence event |
| user.unbanned                      | when the user ban is lifted                                                                | clients for the banned user                                                    | client event        |
| user.updated                       | when a user is updated                                                                     | clients subscribed to the user status                                          | user presence event |
| user.watching.start                | when a user starts watching a channel                                                      | clients watching the channel                                                   | channel event       |
| user.watching.stop                 | when a user stops watching a channel                                                       | clients watching the channel                                                   | channel event       |


---

This page was last updated at 2026-03-05T19:05:49.299Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/node/event_object/](https://getstream.io/chat/docs/node/event_object/).