---
source_url: https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/custom-events
title: Create custom events
updated_at: 2026-06-23T11:42:29.696Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Create custom events

Learn how Chat SDK handles events before creating your own [custom chat events](#create-and-send-events).

## Event handling

### PubNub events

Chat SDK handles subscription and event listeners automatically. All listener methods return a function to stop receiving events and unsubscribe from the channel.

| Entity | Method(s) | Events handled |
| --- | --- | --- |
| `Channel` | [StreamUpdates() or StreamUpdatesOn()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/updates#get-channel-updates) | (Un)Subscribe the current user to/from a channel and start/stop getting all `objects` events of type `channel`. |
| `User` | [StreamUpdates() or StreamUpdatesOn()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/users/updates#get-user-updates) | (Un)Subscribe the current user to/from a channel and start/stop getting all `objects` events of type `uuid`. |
| `Message` | [StreamUpdates() or StreamUpdatesOn()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/updates#get-message-updates) | (Un)Subscribe the current user to/from a channel and start/stop getting all `messageAction` events (for message and message actions changes) of type `added` or `removed`. |
| `Membership` | [OnUpdated and StreamUpdatesOn()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/membership#get-updates) | (Un)Subscribe the current user to/from a channel and start/stop getting all `objects` events of type `membership`. |
| `Channel` | [Connect()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/watch) | (Un)Subscribe the current user to/from a channel and start/stop getting all `message` events of type `text`. |
| `Channel` | [OnUsersTyping](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/typing-indicator#get-typing-events) | (Un)Subscribe the current user to/from a channel and start/stop getting all `Signal` events of type `typing`. |
| `Channel` | [OnPresenceUpdate](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/users/presence#get-presence-updates) | (Un)Subscribe the current user to/from a channel and start/stop getting all `presence` events of type `action` (responsible for monitoring when users join, leave the channels, or when their channel connection times out and they get disconnected). |

### Chat events

Events are separate [entities](https://www.pubnub.com/docs/chat/unity-chat-sdk/learn/chat-entities/event) that carry data payloads and can trigger business logic (for example, the Typing Indicator starts or stops based on typing events).

Chat SDK automatically emits these event types when a user:

* Reports a message (`report` event type)
* Starts/Stops typing a message on a channel ([typing](#events-for-typing-indicator) event type)
* Mentions someone else in the message ([mention](#events-for-mentions) event type)
* Reads a message published on a channel ([receipt](#events-for-read-receipts) event type)
* Invites another user to join a channel ([invite](#events-for-channel-initations) event type)
* Mutes a user, bans them, or removes these restrictions ([moderation](#events-for-user-moderation) event type)

All event types use underneath the PubNub Pub/Sub API and one of these methods:

* [Publish()](https://www.pubnub.com/docs/sdks/unity/api-reference/publish-and-subscribe#publish) - if event history is required, like for storing reported messages. For the purpose of the Unity Chat SDK, history is always [enabled](https://www.pubnub.com/docs/sdks/unity/api-reference/publish-and-subscribe#methods) when emitting an event with the `Publish()` method.
* [Signal()](https://www.pubnub.com/docs/sdks/unity/api-reference/publish-and-subscribe#signal) - if no event history is required, like in the case of the typing indicator that relies on short-lived signals.

Different Unity Chat SDK methods emit (handle) different chat event types. For example, the `SendText()` method called on the `Channel` object emits `mention` events because the IDs of the mentioned users are always passed as part of published messages.

To listen to those events, Unity Chat SDK uses different methods:

* Stream{Type}() methods for the current events that are emitted with the Signal() or Publish() method. The {Type} stands for a given type of emitted events: StreamReportEvents(), StreamCustomEvents(), StreamPresence(), StreamTyping(), StreamReadReceipts(). Earlier versions used SetListeningFor{Type}Events() methods which have been superseded but remain available for backward compatibility.
* GetEventsHistory() to get historical events that were emitted with the Publish() method.

:::note Events history limitations
The `GetEventsHistory()` method uses PubNub Message Persistence API which has limitations - you cannot filter the results by type. Calling this method would return all event types that happened on a given channel in a given timeframe as long as they were emitted with the `Publish()` method that stores history. Check [custom events](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/custom-events#get-historical-events) for an example showing this method.
:::

The payload structure of the chat events is fixed and depends on the event type.

Read the subsections to get a better overview of each event type - check how they work and get some ideas on using them in your chat app to trigger additional business logic.

#### Events for reported messages

* **Type:** `Report`
* **PubNub method:** PubNub method used to send events you listen for. `Publish()` (with history) is used for all events related to message reporting.
* **Target:** [PUBNUB_INTERNAL_MODERATION_{channel_id}](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/moderation)
* **Trigger:** [report()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/moderation#flagreport-messages) method on the `Message` object
* **Listener:** `StreamReportEvents()` (current)
* **Sample use case:** [Message moderation](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/moderation#listen-to-report-events). You might want to create a UI for an operational dashboard to monitor and manage all reported messages.
* **Payload:**

```json
{
  "text": "string // content of the flagged message (optional)",
  "reason": "string // reason for flagging the message",
  "reportedMessageTimetoken": "string // timetoken of the flagged message (optional)",
  "reportedMessageChannelId": "string // channel where message was flagged (optional)",
  "reportedUserId": "string // author of the flagged message (optional)"
}
```

#### Events for typing indicator

* **Type:** `Typing`
* **PubNub method:** PubNub method used to send events you listen for. `Signal()` (without history) is used for all events related to typing.
* **Target:** The same channel where messages are published.
* **Trigger:** [startTyping() and stopTyping()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/typing-indicator) methods on the `Channel` object
* **Listener:** Handler of the [OnUsersTyping events](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/typing-indicator#get-typing-events)
* **Sample use case:** [Typing indicator](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/typing-indicator#get-typing-events). You might want to show graphically on the channel that another channel member is typing or has stopped typing a message.
* **Payload:**

```json
{
  "value": "boolean // value showing whether someone is typing or not"
}
```

#### Events for mentions

* **Type:** `Mention`
* **PubNub method:** PubNub method used to send events you listen for. `Publish()` (with history) is used for all events related to mentions.
* **Target:** Unlike in other event types, a target for mention events is equal to a user ID. This ID is treated as a user-specific channel and is used to send system notifications about changes concerning a [User object](https://www.pubnub.com/docs/chat/unity-chat-sdk/learn/chat-entities/user), such as creating, updating, or deleting that user. The channel name is equal to the ID (`id`) of the user and you can retrieve it by calling the [GetCurrentUser()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/users/details#get-current-user) method on the `Chat` object.
* **Trigger:** [SendText()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/send-receive) method on the `Channel` object
* **Listener:** Events for user mentions are listened to through the user-specific channel. Monitor the user channel with [Connect()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/watch) or use `GetEventsHistory()` (historical) on the `Chat` object
* **Sample use case:** [User mentions](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/users/mentions#show-notifications-for-mentions). You might want to receive notifications for all events emitted when you are mentioned in a parent or thread channel.
* **Payload:**

```json
{
  "messageTimetoken": "string // timetoken of the message where someone is mentioned",
  "channel": "string // channel on which the message with mention was sent"
}
```

#### Events for read receipts

* **Type:** `Receipt`
* **PubNub method:** PubNub method used to send events you listen for. `Signal()` (with history persisted as the last read message on the `Membership` object) is used for all events related to message read receipts.
* **Target:** The same channel where messages are published.
* **Trigger:** [MarkAllMessagesAsRead()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/unread#mark-messages-as-read-all-channels) method on the `Chat` object, the [SetLastReadMessageTimeToken()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/unread#mark-messages-as-read-one-channel) method on the `Membership` object, and the [SetLastReadMessage()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/unread#mark-messages-as-read-one-channel) method on the `Membership` object
* **Listener:** `StreamReadReceipts()` (current) on the `Channel` object
* **Sample use case:** [Read receipts](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/read-receipts). You might want to indicate on a channel - through avatars or some other indicator - that a message was read by another user/other users.
* **Payload:**

```json
{
  "messageTimetoken": "string // timetoken of the read message"
}
```

#### Events for channel initations

* **Type:** `Invite`
* **PubNub method:** PubNub method used to send events you listen for. `Publish()` (with history) is used for all events related to channel invitations.
* **Target:** An event is sent to the ID of the invited user (user channel with the name same as the user ID).
* **Trigger:** [Invite()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/invite#invite-one-user) and [InviteMultiple](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/invite#invite-multiple-users) methods on the `Channel` object
* **Listener:** Events for channel invitations are sent to the user-specific channel. Monitor the user channel with [Connect()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/watch) or use `GetEventsHistory()` (historical) on the `Chat` object
* **Sample use case:** [Channel invitations](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/invite). You might want to notify users that they were invited to join a channel.
* **Payload:**

```json
{
  "channelType": "ChannelType || \"unknown\" // type of a channel to which a user was invited (direct or group)",
  "channelId": "string // ID of the channel to which a user was invited"
}
```

#### Events for user moderation

* **Type:** `Moderation`
* **PubNub method:** PubNub method used to send events you listen for. `Publish()` (with history) is used for all events related to user restrictions.
* **Target:** An event is sent to the ID of the moderated user (user channel with the name same as the user ID) preceded by the `PUBNUB_INTERNAL_MODERATION.` prefix, like `PUBNUB_INTERNAL_MODERATION.[UserId]`.
* **Trigger:** [SetRestrictions()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/users/moderation#mute-or-ban-users) methods on the `Channel`, `Chat`, and `User` objects
* **Listener:** Events for user moderation are sent to the user-specific moderation channel. Monitor the user moderation channel with [Connect()](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/watch) or use `GetEventsHistory()` (historical) on the `Chat` object
* **Sample use case:** [User moderation](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/users/moderation#mute-or-ban-users). You might want to notify users when they were muted, banned, or when you remove these restrictions from them.
* **Payload:**

```json
{
  "channelId": "PUBNUB_INTERNAL_MODERATION.String // ID of the channel on which the user's moderation restrictions were set or lifted preceded by the PUBNUB_INTERNAL_MODERATION. prefix",
  "restriction": "\"muted\" | \"banned\" | \"lifted\" // type of restriction: whether a user was muted, banned, or at least one of these restrictions was removed",
  "reason": "string // reason for muting or banning the user (optional)"
}
```

## Custom events

Chat SDK provides an additional type of events called `Custom`. As the type name suggests, they are meant to let you carry your custom payloads and use them to perform additional business logic in your chat app.

With Chat SDK, you can:

* Trigger such custom events using the `EmitCustomEvent()` method on a `Channel` object.
* Listen to them with the `StreamCustomEvents()` method.
* Get all historical events using the `GetEventsHistory()` method.

:::warning EmitEvent() is now internal
The `chat.EmitEvent()` method is no longer part of the public API. Use `channel.EmitCustomEvent()` to emit custom events on a specific channel.
:::

### Create and send events

`EmitCustomEvent()` handles (constructs and sends) custom events with your payload on a specific channel.

In its logic, you can compare this method to the [SendText() method](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/send-receive) used for sending new messages.

#### Method signature

This method takes the following parameters:

```csharp
channel.EmitCustomEvent(
    string payload,
    bool storeInHistory = true,
    string? type = null
)
```

##### Input

| Parameter | Description |
| --- | --- |
| `payload` *Type: `string`Default: n/a | Metadata in the form of key-value pairs you want to pass as custom events from your chat app. |
| `storeInHistory`Type: `bool`Default: `true` | Whether to store the event in history (using `Publish()`) or not (using `Signal()`). |
| `type`Type: `string?`Default: `null` | Optional custom type string for the event. When `null`, defaults to `"Custom"`. |

##### Output

An awaitable `Task<ChatOperationResult>`.

#### Sample code

You want to monitor a high-priority channel with a keyword spotter that identifies dissatisfaction words like "annoyed," "frustrated," or "angry." Suppose a message sent by any of the customers present on this channel contains any of these words. In that case, you want to resend it (with relevant metadata) to a separate technical channel (`CUSTOMER-SATISFACTION-CREW`) that's monitored by the team responsible for customer satisfaction.

```csharp
using System.Collections.Generic;
using System.Threading.Tasks;
using PubnubApi;
using PubnubApi.Unity;
using PubnubChatApi;
using UnityEngine;

// Configuration
PubnubChatConfig chatConfig = new PubnubChatConfig();
        
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize Unity Chat
var chatResult = await UnityChat.CreateInstance(chatConfig, pnConfiguration);
if (!chatResult.Error)
{
    chat = chatResult.Result;
}
var channelResult = await chat.GetChannel("CUSTOMER-SATISFACTION-CREW");
if (channelResult.Error)
{
    return;
}
var channel = channelResult.Result;
        
await channel.EmitCustomEvent(
        "{\"chatID\": \"chat1234\"," +
        "\"timestamp\": \"2022-04-30T10:30:00Z\"," +
        "\"customerID\": \"customer5678\"," + 
        "\"triggerWord\": \"frustrated\"}"
);
```

### Receive current events

`StreamCustomEvents()` lets you watch a selected channel for any new custom events emitted by your chat app. You can decide what to do with the incoming custom events and handle them using the callback function.

In its logic, you can compare this method to the [Connect() method](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/channels/watch) used for receiving new messages.

:::tip Method naming
Earlier versions used `SetListeningForCustomEvents()` to enable streaming. This method has been superseded by `StreamCustomEvents()`, though it remains available for backward compatibility.
:::

#### Method signature

This method takes the following parameters:

```csharp
// start listening
channel.StreamCustomEvents(bool stream)

// triggered custom event
public event Action<CustomEvent> OnCustomEvent;
// needs a corresponding event handler
void EventHandler(CustomEvent event)
```

##### Input

| Parameter | Description |
| --- | --- |
| `stream` *Type: `bool`Default: n/a | Whether to start (`true`) or stop (`false`) listening for custom events on the channel. |

##### Output

This method doesn't return anything.

#### Sample code

Monitor a channel for frustrated customer events. When such an event occurs, the `handleFrustratedEvent` function responds with a message acknowledging the customer's frustration and offering assistance.

```csharp
using System.Collections.Generic;
using System.Threading.Tasks;
using PubnubApi;
using PubnubApi.Unity;
using PubnubChatApi;
using UnityEngine;

// Configuration
PubnubChatConfig chatConfig = new PubnubChatConfig();
        
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize Unity Chat
var chatResult = await UnityChat.CreateInstance(chatConfig, pnConfiguration);
if (!chatResult.Error)
{
    chat = chatResult.Result;
}
var channelResult = await chat.GetChannel("CUSTOMER-SATISFACTION-CREW");
if (channelResult.Error) return;
var channel = channelResult.Result;
        
// simulated event data received
string eventData = 
    "\"chatID\":\"chat1234\"," +
    "\"timestamp\":\"2022-04-30T10:30:00Z\"," +
    "\"customerID\":\"customer5678\"," +
    "\"triggerWord\":\"frustrated\"";

// example function to handle the "frustrated" event and satisfy the customer
void HandleFrustratedEvent(string eventData) {
    //basic JSON parsing using the pluggable library
    var data = chat.PubnubInstance.JsonPluggableLibrary.DeserializeToDictionaryOfObject(eventData);
            
    // extract relevant information from the event data
    string customerID = data["customerID"].ToString();
    string timestamp = data["timestamp"].ToString();
    string triggerWord = data["triggerWord"].ToString();

    // create a response
    string response = "Thank you for reaching out. We're sorry to hear " +
        $"that you're {triggerWord}. Our team is here to help and will work to resolve your" +
        "concerns as quickly as possible. Your satisfaction is important to us.";

    // send the response back to the customer's chat
    SendResponseToCustomerChat(customerID, timestamp, response);
}

// example event listener using "StreamCustomEvents()" on some channel
channel.StreamCustomEvents(true);
channel.OnCustomEvent += customEvent => 
{
     if(customEvent.Payload.Contains("\"triggerWord\":\frustrated\""))
     {
         HandleFrustratedEvent(customEvent.Payload);
     }
};
```

### Get historical events

`GetEventsHistory()` lets you get historical events from a selected channel.

In its logic, you can compare this method to the [FetchHistory() method](https://www.pubnub.com/docs/chat/unity-chat-sdk/build/features/messages/history) used for receiving historical messages. Similarly to this method, you cannot filter the results by type, so you'll get all events emitted with the `Publish()` method that happened on a given channel in a given timeframe (not only `Custom` events).

#### Method signature

This method takes the following parameters:

```csharp
chat.GetEventsHistory(
    string channelId,
    string startTimeToken,
    string endTimeToken,
    int count
)
```

#### Input

| Parameter | Description |
| --- | --- |
| `channelId` *Type: `string`Default: n/a | Channel from which you want to pull historical messages. |
| `startTimeToken`Type: `string`Default: n/a | [Timetoken](https://www.pubnub.com/docs/sdks/unity/api-reference/misc#time) delimiting the start of a time slice (exclusive) to pull events from. For details, refer to the [Fetch History section](https://www.pubnub.com/docs/sdks/unity/api-reference/storage-and-playback#fetch-history). |
| `endTimeToken`Type: `string`Default: n/a | Timetoken delimiting the end of a time slice (inclusive) to pull events from. |
| `count`Type: `int`Default: `100` | Number of historical events to return for the channel in a single call. You can pull a maximum number of 100 events in a single call. |

#### Output

| Type | Description |
| --- | --- |
| `Task<ChatOperationResult<EventsHistoryWrapper>>` | An awaitable `Task` with the object containing the filtered, sorted, and paginated list of historical events. |

#### Sample code

Fetch the last `10` historical events from the `CUSTOMER-SATISFACTION-CREW` channel.

```csharp
using System.Collections.Generic;
using System.Threading.Tasks;
using PubnubApi;
using PubnubApi.Unity;
using PubnubChatApi;
using UnityEngine;

// Configuration
PubnubChatConfig chatConfig = new PubnubChatConfig();
        
PNConfiguration pnConfiguration = new PNConfiguration(new UserId("myUniqueUserId"))
{
    SubscribeKey = "demo",
    PublishKey = "demo",
    Secure = true
};

// Initialize Unity Chat
var chatResult = await UnityChat.CreateInstance(chatConfig, pnConfiguration);
if (!chatResult.Error)
{
    chat = chatResult.Result;
}
// define the required parameters
string channelId = "CUSTOMER-SATISFACTION-CREW";
int count = 10;

// fetch the last 10 historical events
var historyResult = await chat.GetEventsHistory(channelId, null, null, count);
if (historyResult.Error)
{
    // Handle error
    return;
}
var history = historyResult.Result;

// process the returned historical events
foreach (var eventItem in history.Events)
{
    Debug.Log($"Timestamp: {eventItem.TimeToken}, Event type: {eventItem.Type}");
}
```