Create custom events
Before creating your own custom chat events, learn how Chat SDK handles PubNub and chat-specific events.
Event handling
PubNub events
If you were to use a standard PubNub SDK, such as the Swift SDK, to build a chat app, you would have to perform additional steps as part of your PubNub initialization:
- Explicitly subscribe to the chosen channel(s) to receive messages.
- Add event listeners for your app to receive and handle all messages, signals, and events sent to the channel(s) you are subscribed to.
Luckily, the Chat SDK does this work automatically for you as part of other methods you will run on various entities to build and work with your chat app.
All these methods also return a function you can invoke to stop receiving events of a given type and unsubscribe from the channel. Follow the links to method descriptions for details and examples.
| Entity | Method | Events handled | 
|---|---|---|
| Channel | streamUpdates()orstreamUpdatesOn() | (Un)Subscribe the current user to/from a channel and start/stop getting all objectsevents of typechannel. | 
| User | streamUpdates()orstreamUpdatesOn() | (Un)Subscribe the current user to/from a channel and start/stop getting all objectsevents of typeuuid. | 
| Message | streamUpdates()orstreamUpdatesOn() | (Un)Subscribe the current user to/from a channel and start/stop getting all messageActionevents (for message and message actions changes) of typeaddedorremoved. | 
| Membership | streamUpdates()orstreamUpdatesOn() | (Un)Subscribe the current user to/from a channel and start/stop getting all objectsevents of typemembership. | 
| Channel | connect() | (Un)Subscribe the current user to/from a channel and start/stop getting all messageevents of typetext. | 
| Channel | getTyping() | (Un)Subscribe the current user to/from a channel and start/stop getting all signalevents of typeTyping. | 
| Channel | streamPresence() | (Un)Subscribe the current user to/from a channel and start/stop getting all presenceevents of typeaction(responsible for monitoring when users join, leave the channels, or when their channel connection times out and they get disconnected). | 
Chat SDK wraps all events returned as HTTP responses from the server into meaningful and handy entities, like Channel, Message, User. These objects contain methods you can invoke to build your chat app and parameters you can display on your app's UI.
Chat events
Events, just like messages, are separate entities in the Chat SDK that carry data as a payload. Contrary to messages, however, events are not merely data transmitters but can trigger additional business logic. For example, in the Chat SDK, the Typing Indicator feature relies on events - based on whether a user is typing or not, the typing indicator starts or stops.
Chat SDK handles a few intrinsic types of such events that get emitted automatically 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)
All event types use underneath the PubNub Pub/Sub API and one of these methods:
- publish()- if event history is required, like for storing reported messages. For the purpose of the Chat SDK, history is always enabled when emitting an event with the- publish()method.
- signal()- if no event history is required, like in the case of the typing indicator that relies on short-lived signals.
Different 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, Chat SDK uses two methods:
- listenForEvents()for the current events that are emitted with the- signal()or- publish()method.
- getEventsHistory()to get historical events that were emitted with the- publish()method.
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 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}
- Trigger: report()method on theMessageobject
- Listener: streamMessageReports()(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:
1public class Report: EventContent {
2  public let text: String?
3  public let reason: String
4  public let reportedMessageTimetoken: Timetoken?
5  public let reportedMessageChannelId: String?
6  public let reportedUserId: String?
7}
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: getTyping()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:
1public class Typing: EventContent {
2  public let value: Bool
3}
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: listenForEvents()(current) 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:
1public class Mention: EventContent {
2  public let messageTimetoken: Timetoken
3  public let channel: String
4  public let parentChannel: String?
5}
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: streamReadReceipts()(current) on theChatobject
- 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:
1public class Receipt: EventContent {
2  public let messageTimetoken: Timetoken
3}
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: listenForEvents()(current) orgetEventsHistory()(historical) on theChatobject
- Sample use case: Channel invitations. You might want to notify users that they were invited to join a channel.
- Payload:
1public class Invite: EventContent {
2  public let channelType: ChannelType
3  public let channelId: String
4}
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 emitEvent()method.
- Listen to them with the listenForEvents()method.
- Get all historical events using the getEventsHistory()method.
Create and send events
emitEvent() handles (constructs and sends) events with your custom payload.
In its logic, you can compare this method to the sendText() method used for sending new messages.
Method signature
This method takes the following parameters:
1chat.emitEvent<T : EventContent>(
2    channelId: String,
3    payload: T,
4    mergePayloadWith otherPayload: [String: JSONCodable]? = nil
5) async throws -> Timetoken
Input
| Parameter | Description | 
|---|---|
| channelIdType:  StringDefault: n/a | Channel where you want to send the events. | 
| payload*Type:  TDefault: n/a | Type of events. Use customfor full control over event payload and emitting method. | 
| mergePayloadWith*Type:  [String: JSONCodable]Default: n/a | Metadata in the form of key-value pairs you want to pass as events from your chat app. Can contain anything in case of Customevents, but has a predefined structure for other types of events. | 
Output
| Parameter | Description | 
|---|---|
| Timetoken | 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.
1// Define a custom payload that conforms to EventContent
2class CustomEventPayload: EventContent, JSONCodable {
3  let chatID: String
4  let timestamp: String
5  let customerID: String
6  let triggerWord: String
7  
8  init(chatID: String, timestamp: String, customerID: String, triggerWord: String) {
9    self.chatID = chatID
10    self.timestamp = timestamp
11    self.customerID = customerID
12    self.triggerWord = triggerWord
13  }
14}
15
Receive current events
listenForEvents() 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 an async stream.
In its logic, you can compare this method to the connect() method used for receiving new messages.
Method signature
This method takes the following parameters:
1chat.listenForEvents<T: EventContent>(
2    type: T.Type,
3    channelId: String,
4    customMethod: EmitEventMethod = .publish
5  ) -> AsyncStream<EventWrapper<T>>
Input
| Parameter | Description | 
|---|---|
| type*Type:  T.TypeDefault: n/a | Type parameter allowing access to type information at runtime. | 
| channelId*Type:  StringDefault: n/a | Channel to listen for new events. | 
| customMethodType:  EmitEventMethodDefault: n/a | An optional custom method for emitting events. If not provided, defaults to .publish. Available values:.publishand.signal. | 
Output
| Parameter | Description | 
|---|---|
| AsyncStream<EventWrapper<T>> | An asynchronous stream that produces a value each time a new event of the specified type is emitted. | 
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.
- AsyncStream
- Closure
1// Define a custom payload that conforms to EventContent
2class CustomEventPayload: EventContent, JSONCodable {
3  let chatID: String
4  let timestamp: String
5  let customerID: String
6  let triggerWord: String
7  
8  init(chatID: String, timestamp: String, customerID: String, triggerWord: String) {
9    self.chatID = chatID
10    self.timestamp = timestamp
11    self.customerID = customerID
12    self.triggerWord = triggerWord
13  }
14}
15
1// Define a custom payload that conforms to EventContent
2class CustomEventPayload: EventContent, JSONCodable {
3  let chatID: String
4  let timestamp: String
5  let customerID: String
6  let triggerWord: String
7  
8  init(chatID: String, timestamp: String, customerID: String, triggerWord: String) {
9    self.chatID = chatID
10    self.timestamp = timestamp
11    self.customerID = customerID
12    self.triggerWord = triggerWord
13  }
14}
15
Get historical events
getEventsHistory() lets you get historical events from a selected channel.
In its logic, you can compare this method to the getHistory() method 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:
1chat.getEventsHistory(
2    channelId: String,
3    startTimetoken: Timetoken? = nil,
4    endTimetoken: Timetoken? = nil,
5    count: Int = 100
6) async throws -> (events: [EventWrapper<EventContent>], isMore: Bool)
Input
| Parameter | Description | 
|---|---|
| channelId*Type:  StringDefault: n/a | Channel from which you want to pull historical messages. | 
| startTimetokenType:  TimetokenDefault: n/a | Timetoken delimiting the start of a time slice (exclusive) to pull events from. For details, refer to the Fetch History section. | 
| endTimetokenType:  TimetokenDefault: n/a | Timetoken delimiting the end of a time slice (inclusive) to pull events from. For details, refer to the Fetch History section. | 
| 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 | 
|---|---|
| (events: [EventWrapper<EventContent>], isMore: Bool)Type:  object | Returned object containing two fields: eventsandisMore. | 
| → eventsType:  Set<Event<EventContent>> | Array listing the requested number of historical events objects. | 
| → isMoreType:  Bool | Info whether there are more historical events to pull. | 
Sample code
Fetch the last 10 historical events from the CUSTOMER-SATISFACTION-CREW channel.
1// Define the custom payload type conforming to EventContent
2class CustomEventContent: EventContent, JSONCodable {
3  let chatID: String
4  let timestamp: String
5  let customerID: String
6  let triggerWord: String
7  
8  init(chatID: String, timestamp: String, customerID: String, triggerWord: String) {
9    self.chatID = chatID
10    self.timestamp = timestamp
11    self.customerID = customerID
12    self.triggerWord = triggerWord
13  }
14}
15