# Custom Events

Custom events allow you to build more complex interactions within a channel or with a user.

### 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>/watch_channel/).

<codetabs>

<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="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="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="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-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="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>

<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 a character used for built-in events, see [Event Object](/chat/docs/<framework>/event_object/) section for more details.

---

This page was last updated at 2025-08-15T14:14:16.224Z.

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