Create custom events
Learn how Chat SDK handles events before creating your own custom chat events.
Event handling
PubNub events
With a standard PubNub SDK, building a chat app requires additional steps:
- 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() | Start/stop getting all objects events of type channel. |
User | onUpdated() or onDeleted() | Start/stop getting all objects events of type uuid. |
Message | onUpdated() | Start/stop getting all messageAction events (for message and message reactions changes) of type added or removed. |
Membership | onUpdated() or onDeleted() | Start/stop getting all objects events of type membership. |
Channel | onMessageReceived() | Start/stop getting all message events of type text. |
Channel | onTypingChanged() | Start/stop getting all signal events of type typing. |
Channel | onPresenceChanged() | Start/stop getting all presence events of type action (monitoring when users join, leave, or disconnect from channels). |
Channel | onMessageReported() | Start/stop getting report events for moderation. |
Channel | onReadReceiptReceived() | Start/stop getting individual receipt events. |
Channel | onCustomEvent() | Start/stop getting custom events. |
User | onMentioned() | Start/stop getting mention events. |
User | onInvited() | Start/stop getting invite events. |
User | onRestrictionChanged() | Start/stop getting moderation 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 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 (
reportevent type) - Starts/Stops typing a message on a channel (
typingevent type) - Mentions someone else in the message (
mentionevent type) - Reads a message published on a channel (
receiptevent type) - Invites another user to join a channel (
inviteevent type) - Mutes a user, bans them, or removes these restrictions (
moderationevent type)
All event types use the PubNub Pub/Sub API with one of these methods:
publish()- for events requiring history (always enabled in Chat SDK)signal()- for short-lived events without history (for example, typing indicators)
Listen to events with entity-level methods on Channel and User objects (for example, channel.onTypingChanged(), user.onMentioned(), channel.onMessageReported()). For historical events, use getEventsHistory().
Deprecated methods
listenForEvents() is deprecated. Use entity-level methods instead:
- Typing →
channel.onTypingChanged() - Reports →
channel.onMessageReported() - Read receipts →
channel.onReadReceiptReceived() - Mentions →
user.onMentioned() - Invites →
user.onInvited() - Moderation →
user.onRestrictionChanged() - Custom events →
channel.onCustomEvent()
History limitations
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} - Trigger:
report()method on theMessageobject - Listener:
onMessageReported()(current) andgetMessageReportsHistory(historical) - Sample use case: Message moderation. You might want to create a UI for an operational dashboard to monitor and manage all reported messages.
- Payload:
1@SerialName("report")
2 class Report(
3 // content of the flagged message
4 val text: String? = null,
5 // reason for flagging the message
6 val reason: String,
7 // timetoken of the flagged message
8 val reportedMessageTimetoken: Long? = null,
9 // channel where message was flagged
10 val reportedMessageChannelId: String? = null,
11 // author of the flagged message
12 val reportedUserId: String?,
13 ) : EventContent()
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()andstopTyping()methods on theChannelobject - Listener:
onTypingChanged()on theChannelobject - Sample use case: Typing indicator. You might want to show graphically on the channel that another channel member is typing or has stopped typing a message.
- Payload:
1@SerialName("typing")
2 class Typing(
3 // value showing whether someone is typing or not
4 val value: Boolean
5 ) : EventContent()
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
Userobject, 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 thecurrentUsermethod on theChatobject. - Trigger:
sendText()method on theChannelobject - Listener:
onMentioned()(current) on theUserobject, orgetEventsHistory()(historical) on theChatobject - Sample use case: User mentions. You might want to receive notifications for all events emitted when you are mentioned in a parent or thread channel.
- Payload:
1@SerialName("mention")
2 class Mention(
3 // timetoken of the message where someone is mentioned
4 val messageTimetoken: Long,
5 // channel on which the message with mention was sent
6 val channel: String,
7 // parent channel on which the message with mention was sent
8 val parentChannel: String? = null
9 ) : EventContent()
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 theMembershipobject) is used for all events related to message read receipts. - Target: The same channel where messages are published.
- Trigger:
markAllMessagesAsRead()method on theChatobject, thesetLastReadMessageTimetoken()method on theMembershipobject, and thesetLastReadMessage()method on theMembershipobject - Listener:
onReadReceiptReceived()(current) on theChannelobject, orfetchReadReceipts()to get all current read statuses - Sample use case: 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:
1@SerialName("receipt")
2 class Receipt(
3 // timetoken of the read message
4 val messageTimetoken: Long
5 ) : EventContent()
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()andinviteMultiplemethods on theChannelobject - Listener:
onInvited()(current) on theUserobject, orgetEventsHistory()(historical) on theChatobject - Sample use case: Channel invitations. You might want to notify users that they were invited to join a channel.
- Payload:
1@SerialName("invite")
2 class Invite(
3 // type of a channel to which a user was invited (direct or group)
4 val channelType: ChannelType,
5 // ID of the channel to which a user was invited
6 val channelId: String
7 ) : EventContent()
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, whereuser_idis the ID of the moderated user. - Trigger:
setRestrictions()methods on theChannel,Chat, andUserobjects - Listener:
onRestrictionChanged()(current) on theUserobject, orgetEventsHistory()(historical) on theChatobject - Sample use case: User moderation. You might want to notify users when they were muted, banned, or when you remove these restrictions from them.
- Payload:
1@SerialName("moderation")
2 class Moderation(
3 // ID of the channel on which the user's moderation restrictions were set or lifted
4 val channelId: String,
5 // type of restriction: whether a user was muted, banned, or at least one of these restrictions was removed ("lifted")
6 val restriction: RestrictionType,
7 // reason for muting or banning the user
8 val reason: String? = null
9 ) : EventContent()
Custom events
The custom event type carries custom payloads for additional business logic. Methods:
channel.emitCustomEvent()- create and send custom events on a channelchannel.onCustomEvent()- listen for incoming custom events on a channelgetEventsHistory()- retrieve historical events
Deprecated methods
chat.emitEvent() and chat.listenForEvents() are deprecated. Use channel.emitCustomEvent() and channel.onCustomEvent() instead.
Create and send events
emitCustomEvent() sends custom events on a channel with your custom payload.
Method signature
This method takes the following parameters:
1channel.emitCustomEvent(
2 payload: Map<String, Any?>,
3 messageType: String? = null,
4 storeInHistory: Boolean = true,
5): PNFuture<PNPublishResult>
Input
| Parameter | Description |
|---|---|
payload *Type: Map<String, Any?>Default: n/a | Arbitrary key-value payload to publish. |
messageTypeType: StringDefault: null | Optional custom message type used for filtering. |
storeInHistoryType: BooleanDefault: true | If true, the event is stored in Message Persistence (if enabled). |
Output
| Type | Description |
|---|---|
PNFuture<PNPublishResult> | Result of the PubNub Publish or Signal 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.
1val channel: Channel
2// ...
3
4channel.emitCustomEvent(
5 payload = mapOf(
6 "chatID" to "chat1234",
7 "timestamp" to "2022-04-30T10:30:00Z",
8 "customerID" to "customer5678",
9 "triggerWord" to "frustrated"
10 )
11).async { result ->
12 result.onSuccess { pnPublishResult ->
13 println("Event emitted with timetoken: ${pnPublishResult.timetoken}")
14 }.onFailure { ex ->
15 println("Failed to emit event: ${ex.message}")
show all 17 linesReceive current events
onCustomEvent() watches a channel for new custom events and handles them via a callback.
Method signature
This method takes the following parameters:
1channel.onCustomEvent(
2 messageType: String? = null,
3 callback: (event: CustomEvent<Map<String, Any?>>) -> Unit,
4): AutoCloseable
Input
| Parameter | Description |
|---|---|
messageTypeType: StringDefault: null | Optional custom message type filter. If null, all custom events are accepted. |
callback *Type: (event: CustomEvent<Map<String, Any?>>) -> UnitDefault: n/a | Function invoked for each matching custom event. |
The CustomEvent object contains:
| Property | Description |
|---|---|
timetokenType: Long | When the event was published. |
userIdType: String | ID of the user who emitted the event. |
typeType: String? | The custom message type. |
payloadType: Map<String, Any?> | The custom event payload data. |
Output
| Type | Description |
|---|---|
AutoCloseable | Interface that lets you stop receiving custom events by invoking the close() method. |
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.
1val channel: Channel
2// ...
3
4val subscription = channel.onCustomEvent { event ->
5 if (event.payload["triggerWord"] == "frustrated") {
6 val customerID = event.payload["customerID"]
7 println("Frustrated customer detected: $customerID at ${event.timetoken}")
8 }
9}
10
11// stop listening:
12// subscription.close()
Get historical events
getEventsHistory() retrieves historical events from a channel, similar to getHistory() for messages. Results cannot be filtered by type and include all events emitted via publish() in the specified timeframe.
Method signature
This method takes the following parameters:
1chat.getEventsHistory(
2 channelId: String,
3 startTimetoken: Long? = null,
4 endTimetoken: Long? = null,
5 count: Int = 100
6
7): PNFuture<GetEventsHistoryResult>
Input
| Parameter | Description |
|---|---|
channelId *Type: StringDefault: n/a | Channel from which you want to pull historical messages. |
startTimetokenType: LongDefault: n/a | Timetoken delimiting the start of a time slice (exclusive) to pull events from. For details, refer to Message Persistence. |
endTimetokenType: LongDefault: n/a | Timetoken delimiting the end of a time slice (inclusive) to pull events from. For details, refer to Message Persistence. |
countType: IntDefault: 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 |
|---|---|
PNFuture<GetEventsHistoryResult>Type: object | Returned object containing two fields: events and isMore. |
→ eventsType: Set<Event<EventContent>> | Array listing the requested number of historical events objects. |
→ isMoreType: Boolean | Info whether there are more historical events to pull. |
Sample code
Fetch the last 10 historical events from the CUSTOMER-SATISFACTION-CREW channel.
1chat.getEventsHistory(
2 channelId = "CUSTOMER-SATISFACTION-CREW",
3 count = 10
4).async { result ->
5 // ...
6}