---
source_url: https://www.pubnub.com/docs/chat/chat-sdk/build/features/custom-events
title: Create custom events
updated_at: 2026-06-26T11:03:06.869Z
---

> 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

With a standard PubNub SDK like the [JavaScript SDK](https://www.pubnub.com/docs/sdks/javascript/api-reference/configuration#event-listeners), building a chat app requires [additional steps](https://www.pubnub.com/docs/general/basics/receive-messages):

* Subscribe to channels to receive messages
* Add event listeners to handle messages, signals, and events

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

| Entity | Method | Events handled |
| --- | --- | --- |
| `Channel` | [onUpdated() or onDeleted()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/updates#get-channel-updates) (streamUpdates() deprecated; `streamUpdatesOn()` remains supported) | (Un)Subscribe the current user to/from a channel and start/stop getting all `objects` events of type `channel`. |
| `User` | [onUpdated() or onDeleted()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/users/updates#get-user-updates) (streamUpdates() deprecated; `streamUpdatesOn()` remains supported) | (Un)Subscribe the current user to/from a channel and start/stop getting all `objects` events of type `uuid`. |
| `Message` | [onUpdated()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/updates#get-message-updates) (streamUpdates() deprecated; `streamUpdatesOn()` remains supported) | (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() or onDeleted()](https://www.pubnub.com/docs/chat/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` | [onMessageReceived()](https://www.pubnub.com/docs/chat/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` | [onTypingChanged()](https://www.pubnub.com/docs/chat/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` | [onPresenceChanged()](https://www.pubnub.com/docs/chat/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). |
| `Channel` | [onCustomEvent()](#receive-current-events) | (Un)Subscribe the current user to/from a channel and start/stop getting all custom `message` events. |

Chat SDK wraps server responses into entities like `Channel`, `Message`, and `User` with methods and properties for building your app's UI.

### Chat events

Events are separate [entities](https://www.pubnub.com/docs/chat/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 the PubNub Pub/Sub API with one of these methods:

* [publish()](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#publish) - for events requiring history (always [enabled](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#methods) in Chat SDK)
* [signal()](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#signal) - for short-lived events without history (for example, typing indicators)

Listen to events with:

* `listenForEvents()` - for current events emitted via `signal()` or `publish()`
* `getEventsHistory()` - for historical events emitted via `publish()`

:::note
`getEventsHistory()` cannot filter by event type. It returns all events emitted via `publish()` on the channel within the specified timeframe.
:::

Each event type has a fixed payload structure documented below.

#### 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/chat-sdk/build/features/messages/moderation)
* **Trigger:** [report()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/moderation#flagreport-messages) method on the `Message` object
* **Listener:** [onMessageReported()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/moderation#listen-to-report-events) (current), streamMessageReports() (deprecated), and `getMessageReportsHistory` (historical)
* **Sample use case:** [Message moderation](https://www.pubnub.com/docs/chat/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:**

```ts
type ReportEventPayload = {
    // content of the flagged message
    text?: string
    // reason for flagging the message
    reason: string
    // timetoken of the flagged message
    reportedMessageTimetoken?: string
    // channel where message was flagged
    reportedMessageChannelId?: string
    // author of the flagged message
    reportedUserId?: string
}
```

#### 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/chat-sdk/build/features/channels/typing-indicator) methods on the `Channel` object
* **Listener:** `getTyping()` on the `Channel` object
* **Sample use case:** [Typing indicator](https://www.pubnub.com/docs/chat/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:**

```ts
type TypingEventPayload = {
    // value showing whether someone is typing or not
    value: boolean
}
```

#### 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/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 `currentUser` method on the `Chat` object.
* **Trigger:** [sendText()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/send-receive) method on the `Channel` object
* **Listener:** `listenForEvents()` (current) or `getEventsHistory()` (historical) on the `Chat` object
* **Sample use case:** [User mentions](https://www.pubnub.com/docs/chat/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:**

```ts
type MentionEventPayload = {
    // timetoken of the message where someone is mentioned
    messageTimetoken: string
    // channel on which the message with mention was sent
    channel: string
}
```

#### 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/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/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/chat-sdk/build/features/messages/unread#mark-messages-as-read-one-channel) method on the `Membership` object
* **Listener:** [onReadReceiptReceived()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/read-receipts#get-read-receipts) (current) on the `Channel` object, streamReadReceipts() (deprecated)
* **Sample use case:** [Read receipts](https://www.pubnub.com/docs/chat/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:**

```ts
type ReceiptEventPayload = {
    // timetoken of the read message
    messageTimetoken: string
}
```

#### 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/chat-sdk/build/features/channels/invite#invite-one-user) and [inviteMultiple](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/invite#invite-multiple-users) methods on the `Channel` object
* **Listener:** `listenForEvents()` (current) or `getEventsHistory()` (historical) on the `Chat` object
* **Sample use case:** [Channel invitations](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/invite). You might want to notify users that they were invited to join a channel.
* **Payload:**

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

#### 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 `PUBNUB_INTERNAL_MODERATION.[user_id]` channel, where `user_id` is the ID of the moderated user.
* **Trigger:** [setRestrictions()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/users/moderation#mute-or-ban-users) methods on the `Channel`, `Chat`, and `User` objects
* **Listener:** `listenForEvents()` (current) or `getEventsHistory()` (historical) on the `Chat` object
* **Sample use case:** [User moderation](https://www.pubnub.com/docs/chat/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:**

```ts
type ModerationEventPayload = {
  // ID of the channel on which the user's moderation restrictions were set or lifted
  channelId: PUBNUB_INTERNAL_MODERATION.[string]
  // type of restriction: whether a user was muted, banned, or at least one of these restrictions was removed
  restriction: "muted" | "banned" | "lifted"
  // reason for muting or banning the user
  reason?: string
}
```

## Custom events

The `custom` event type carries custom payloads for additional business logic. Methods:

* `channel.emitCustomEvent()` - create and send custom events on a channel
* `channel.onCustomEvent()` - listen for incoming custom events on a channel
* `getEventsHistory()` - retrieve historical events

The `CustomEventData` type has the following shape:

```ts
type CustomEventData = {
    timetoken: string
    userId: string
    payload: any
    type?: string
}
```

### Create and send events

`channel.emitCustomEvent()` constructs and sends a custom event on the channel, similar to [sendText()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/send-receive) for messages.

##### Under the hood

`channel.emitCustomEvent()` calls Pub/Sub API and the JavaScript SDK [publish()](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#publish) or [signal()](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#signal) method.

#### Method signature

This method takes the following parameters:

```ts
channel.emitCustomEvent(
    payload: any,
    options?: {
        messageType?: string
        storeInHistory?: boolean
    }
): Promise<PublishResponse>
```

##### Input

| Parameter | Description |
| --- | --- |
| `payload` *Type: `any`Default: n/a | Metadata in the form of key-value pairs you want to pass as a custom event from your chat app. |
| `options`Type: `object`Default: n/a | Optional configuration for the event. |
| `> messageType`Type: `string`Default: n/a | Optional type label to attach to the event payload for filtering on the receiving side. |
| `> storeInHistory`Type: `boolean`Default: `true` | If `true`, the event is stored in Message Persistence. |

##### Output

| Type | Description |
| --- | --- |
| `Promise<PublishResponse>` | Result of the PubNub Publish call. |

#### 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.

```ts
// reference the target channel
const satisfactionChannel = await chat.getChannel("CUSTOMER-SATISFACTION-CREW")

await satisfactionChannel.emitCustomEvent(
    {
        chatID: "chat1234",
        timestamp: "2022-04-30T10:30:00Z",
        customerID: "customer5678",
        triggerWord: "frustrated"
    },
    { messageType: "frustration-alert" }
)
```

#### Deprecated method

:::warning Deprecated
`chat.emitEvent()` is deprecated. Use [channel.emitCustomEvent()](#create-and-send-events) instead.
:::

```ts
chat.emitEvent({
    channel: string;
    type: "typing" | "report" | "receipt" | "mention" | "invite" | "moderation" | "custom";
    method?: "signal" | "publish";
    payload: EventPayloads["type"] | any;
}): Promise<PubNub.SignalResponse> | Promise<PubNub.PublishResponse>
```

### Receive current events

`channel.onCustomEvent()` watches a channel for new custom events and handles them via a callback, similar to [onMessageReceived()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/channels/watch) for messages.

##### Under the hood

`channel.onCustomEvent()` calls Pub/Sub API and the JavaScript SDK [subscribe()](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#subscribe) and [unsubscribe()](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe#unsubscribe) methods.

#### Method signature

This method takes the following parameters:

```ts
channel.onCustomEvent(
    callback: (event: CustomEventData) => void,
    options?: {
        messageType?: string
    }
): () => void
```

##### Input

| Parameter | Description |
| --- | --- |
| `callback` *Type: `(event: CustomEventData) => void`Default: n/a | Callback function invoked whenever a custom event is received on the channel. |
| `options`Type: `object`Default: n/a | Optional configuration for filtering events. |
| `> messageType`Type: `string`Default: n/a | When provided, only events with a matching `type` field are passed to the callback. |

##### Output

| Type | Description |
| --- | --- |
| `() => void` | Function you can call to disconnect (unsubscribe) from the channel and stop receiving events. |

#### 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.

```ts
// reference the channel to monitor
const satisfactionChannel = await chat.getChannel("CUSTOMER-SATISFACTION-CREW")

// example function to handle the "frustrated" event and satisfy the customer
function handleFrustratedEvent(eventData: CustomEventData) {
    const { customerID, timestamp, triggerWord } = eventData.payload

    const 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.`

    sendResponseToCustomerChat(customerID, timestamp, response)
}

// listen for custom events of type "frustration-alert"
const stopListening = satisfactionChannel.onCustomEvent(
    (event) => {
        if (event.payload.triggerWord === "frustrated") {
            handleFrustratedEvent(event)
        }
    },
    { messageType: "frustration-alert" }
)

// after some time...
stopListening()
```

#### Deprecated method

:::warning Deprecated
`chat.listenForEvents()` is deprecated. Use entity-level methods instead: `channel.onTypingChanged()`, `channel.onMessageReported()`, `channel.onReadReceiptReceived()`, `channel.onCustomEvent()`, `user.onMentioned()`, `user.onInvited()`, `user.onRestrictionChanged()`.
:::

```ts
chat.listenForEvents<"type">({
    channel: string;
    type: "typing" | "report" | "receipt" | "mention" | "invite" | "moderation" | "custom";
    method?: "signal" | "publish";
    callback: (event: Event<"type">) => unknown;
}): () => void
```

### Get historical events

`getEventsHistory()` retrieves historical events from a channel, similar to [getHistory()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/messages/history) for messages. Results cannot be filtered by type and include all events emitted via `publish()` in the specified timeframe.

##### Under the hood

`getEventsHistory()` calls Message Persistence API and the JavaScript SDK [fetchMessages()](https://www.pubnub.com/docs/sdks/javascript/api-reference/storage-and-playback#fetch-history) method.

#### Method signature

This method takes the following parameters:

```ts
chat.getEventsHistory({
    channel: string;
    startTimetoken?: string;
    endTimetoken?: string;
    count?: number;
}): Promise<{
    events: Event[];
    isMore: boolean;
}>
```

#### Input

| Parameter | Description |
| --- | --- |
| `channel` *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/javascript/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/javascript/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. For details, refer to the [Fetch History section](https://www.pubnub.com/docs/sdks/javascript/api-reference/storage-and-playback#fetch-history). |
| `count`Type: `number`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

| Parameter | Description |
| --- | --- |
| `Promise<>`Type: `object` | Returned object containing two fields: `events` and `isMore`. |
| `> events`Type: `Event[]` | Array listing the requested number of historical events objects. |
| `> isMore`Type: `boolean` | Info whether there are more historical events to pull. |

#### Sample code

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

```ts
chat.getEventsHistory(
    {
        channel: "CUSTOMER-SATISFACTION-CREW"
        count: 10
    }
)
```

## Events for reported users (deprecated)

* **Type:** `report`
* **PubNub method:** PubNub method used to send events you listen for. `publish()` (with history) is used for all events related to user reporting.
* **Target:** [PUBNUB_INTERNAL_ADMIN_CHANNEL](https://www.pubnub.com/docs/chat/chat-sdk/build/features/users/moderation)
* **Trigger:** [DEPRECATED_report()](https://www.pubnub.com/docs/chat/chat-sdk/build/features/users/moderation#flagreport-users-deprecated) method on the `User` object
* **Listener:** `listenForEvents()` (current) or `getEventsHistory()` (historical) on the `Chat` object
* **Sample use case:** [User moderation](https://www.pubnub.com/docs/chat/chat-sdk/build/features/users/moderation#listen-to-report-events-deprecated). You might want to create a UI for an operational dashboard to monitor and manage all reported users.
* **Payload:**

```ts
payload: {
    // reason for flagging the user
    reason: string;
    // flagged user
    reportedUserId: string;
}
```