# Listening to Events

The SDK provides two ways to listen to chat events: the closure-based `subscribe` API and the delegate-based `EventsController`.

## Subscribe API

Both `ChatClient` and `Chat` expose `subscribe` methods that return an `AnyCancellable`. Store the cancellable to keep the subscription active.

### Client-Level Events

Subscribe to events across all channels:

```swift
// Subscribe to a specific event type
let cancellable = chatClient.subscribe(toEvent: MessageNewEvent.self) { event in
    print("New message: \(event.message.text)")
}

// Subscribe to all events
let cancellable = chatClient.subscribe { event in
    print("Received event: \(type(of: event))")
}
```

### Channel-Level Events

Subscribe to events for a specific channel using the `Chat` state layer object:

```swift
let chat = chatClient.makeChat(for: channelId)

let cancellable = chat.subscribe(toEvent: MessageNewEvent.self) { event in
    print("New message in channel: \(event.message.text)")
}
```

## Custom Events

You can send and receive custom events on a channel. Define a payload conforming to `CustomEventPayload`:

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

Send a custom event:

```swift
try await chat.sendEvent(MyCustomEvent(someField: "value"))
```

## EventsController

`EventsController` allows you to subscribe to chat events using the delegate pattern. You can receive all events or only events for specific channels.

### Events Controller Delegate

Classes that conform to the `EventsControllerDelegate` protocol can be used to receive events from the controller.

```swift
func eventsController(_ controller: EventsController, didReceiveEvent event: Event)
```

### Client Events

```swift
let eventsController: EventsController = client.eventsController()
```

### Channel Events

```swift
let eventsController: EventsController = channelController.eventsController()
```

### Example: Local Notifications

In this example we create a custom `ChatChannelListVC` that shows a local notification every time a new message event is received.

```swift
class DemoChannelListVC: ChatChannelListVC, EventsControllerDelegate {
    lazy var eventsController: EventsController = controller.client.eventsController()

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

    func eventsController(_: EventsController, didReceiveEvent event: Event) {
        guard let event = event as? MessageNewEvent else { return }

        let message = event.message

        let content = UNMutableNotificationContent()
        content.title = "\(message.author.name ?? message.author.id) @ \(event.channel.name ?? event.channel.cid.id)"
        content.body = message.text

        let request = UNNotificationRequest(
            identifier: message.id,
            content: content,
            trigger: nil
        )

        UNUserNotificationCenter.current().add(request) { error in
            if let error = error {
                log.error("Error when showing local notification: \(error)")
            }
        }
    }
}
```

## Combine

If you prefer reactive programming with Combine, the SDK exposes event publishers on controllers. See the [Combine Events guide](https://getstream.io/chat/docs/sdk/ios/combine/events/) for details.


---

This page was last updated at 2026-08-10T16:00:48.519Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/ios/client/events/](https://getstream.io/chat/docs/sdk/ios/client/events/).