Realtime
Realtime keeps your UI in sync by delivering events (new messages, edits, typing indicators, reactions, member changes, …) as soon as they happen.
Prerequisite: the client must be authenticated (JWT set via signIn(...) or setAuth(...)). See Authentication.
Events are sent to all connected user even the sender. This means that when a user sends a message and recieves it back over the realtime connection the UI can mark it as "persisted in the backend / delivered".
Connect / Disconnect
realtime.connect()
Connect and start receiving events.
await whisp.realtime.connect();
Typical lifecycle:
- Connect after login (or app startup if you restore auth).
- Disconnect on logout.
- In UI frameworks, clean up event listeners when your chat screen unmounts.
realtime.disconnect()
Disconnect and stop receiving realtime events.
whisp.realtime.disconnect();
Listening to events
Use whisp.realtime.on(eventName, handler) to subscribe to events. The method returns an unsubscribe() function.
const unsubscribe = whisp.realtime.on("message", (event) => {
console.log(event.chatId, event.message);
});
// later
unsubscribe();
If you want to remove everything at once (e.g. on logout), you can also use:
whisp.realtime.removeAllListeners();
Event reference
Below are all currently supported SDK event names.
New message
- SDK event:
message - Description: Fired when a new message is sent in a chat the current user is a member of.
const unsubscribe = whisp.realtime.on("message", (event) => {
console.log("new message", event.chatId, event.messageId, event.message);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is SEND_MSG. |
timeStamp |
string (date-time) | When the message was created. |
chatId |
string (uuid) | Chat the message belongs to. |
message |
string | Message text/content. |
messageId |
string (uuid) | Unique message id. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | Sender user id. |
Example
{
"type": "SEND_MSG",
"timeStamp": "2024-01-15T10:30:00Z",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"message": "Hello, world!",
"messageId": "770e8400-e29b-41d4-a716-446655440002",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004"
}
Message edited
- SDK event:
messageEdited - Description: Fired when an existing message is edited.
const unsubscribe = whisp.realtime.on("messageEdited", (event) => {
console.log("message edited", event.chatId, event.messageId, event.message);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is EDIT_MSG. |
chatId |
string (uuid) | Chat the message belongs to. |
message |
string | Updated message content. |
messageId |
string (uuid) | Edited message id. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who edited the message. |
editedAt |
string (date-time) | When the edit happened. |
Example
{
"type": "EDIT_MSG",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"message": "Hello, world! (edited)",
"messageId": "770e8400-e29b-41d4-a716-446655440002",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004",
"editedAt": "2024-01-15T10:35:00Z"
}
Message deleted
- SDK event:
messageDeleted - Description: Fired when a message is deleted.
const unsubscribe = whisp.realtime.on("messageDeleted", (event) => {
console.log("message deleted", event.chatId, event.messageId);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is DELETE_MSG. |
chatId |
string (uuid) | Chat the deleted message belonged to. |
messageId |
string (uuid) | Deleted message id. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who deleted the message. |
timeStamp |
string (date-time) | When deletion happened. |
Example
{
"type": "DELETE_MSG",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"messageId": "770e8400-e29b-41d4-a716-446655440002",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004",
"timeStamp": "2024-01-15T10:40:00Z"
}
Reply to a message
- SDK event:
reply - Description: Fired when a user replies to a specific message.
const unsubscribe = whisp.realtime.on("reply", (event) => {
console.log("reply", event.chatId, event.messageId, event.replyTo?.messageId);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is REPLY. |
messageId |
string (uuid) | The reply message id. |
message |
string | Reply content. |
chatId |
string (uuid) | Chat where the reply happened. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who replied. |
replyTo |
object | Snapshot of the original message. |
timeStamp |
string (date-time) | When the reply was created. |
Example
{
"type": "REPLY",
"messageId": "bb0e8400-e29b-41d4-a716-446655440006",
"message": "I agree!",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004",
"replyTo": {
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"timeStamp": "2024-01-15T10:30:00Z",
"messageId": "770e8400-e29b-41d4-a716-446655440002",
"senderId": "550e8400-e29b-41d4-a716-446655440000",
"content": "Hello, world!",
"edited": false,
"editedAt": null
},
"timeStamp": "2024-01-15T10:33:00Z"
}
Typing indicator
- SDK event:
typing - Description: Fired when a chat participant starts typing.
const unsubscribe = whisp.realtime.on("typing", (event) => {
console.log("typing", event.chatId, event.senderId);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is TYPING. |
chatId |
string (uuid) | Chat where typing happened. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who is typing. |
Example
{
"type": "TYPING",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004"
}
Reaction added
- SDK event:
reaction - Description: Fired when a reaction (emoji) is added to a message.
const unsubscribe = whisp.realtime.on("reaction", (event) => {
console.log("reaction", event.chatId, event.parentMessageId, event.message);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is REACT. |
messageId |
string (uuid) | Reaction id (use it to delete the reaction). |
message |
string | Reaction emoji. |
chatId |
string (uuid) | Chat where the reaction happened. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who reacted. |
parentMessageId |
string (uuid) | Message id that was reacted to. |
timeStamp |
string (date-time) | When the reaction was created. |
Example
{
"type": "REACT",
"messageId": "880e8400-e29b-41d4-a716-446655440003",
"message": "\ud83d\udc4d",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004",
"parentMessageId": "770e8400-e29b-41d4-a716-446655440002",
"timeStamp": "2024-01-15T10:32:00Z"
}
Reaction removed
- SDK event:
reactionDeleted - Description: Fired when a reaction is removed.
const unsubscribe = whisp.realtime.on("reactionDeleted", (event) => {
console.log("reaction deleted", event.chatId, event.messageId);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is DELETE_REACT. |
messageId |
string (uuid) | Reaction id that was removed. |
chatId |
string (uuid) | Chat where the reaction was removed. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who removed the reaction. |
Example
{
"type": "DELETE_REACT",
"messageId": "880e8400-e29b-41d4-a716-446655440003",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004"
}
You can find reactionId on message history (reactions[].reactionId) or in the realtime reaction event (messageId).
Read receipt
- SDK event:
messageRead - Description: Fired when a user marks a message as read.
const unsubscribe = whisp.realtime.on("messageRead", (event) => {
console.log("read receipt", event.chatId, event.messageId, event.senderId);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is READ_MSG. |
chatId |
string (uuid) | Chat where the read happened. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who read the message. |
messageId |
string (uuid) | Last read message id (for that read action). |
Example
{
"type": "READ_MSG",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004",
"messageId": "770e8400-e29b-41d4-a716-446655440002"
}
Member joined
- SDK event:
userJoined - Description: Fired when a user is added to a chat.
const unsubscribe = whisp.realtime.on("userJoined", (event) => {
console.log("user joined", event.chatId, event.message, event.username);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is USER_JOIN. |
chatId |
string (uuid) | Chat that was joined. |
message |
string (uuid) | New user’s id. |
username |
string | New user’s username. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who triggered the join (e.g. inviter). |
Example
{
"type": "USER_JOIN",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"message": "aa0e8400-e29b-41d4-a716-446655440005",
"username": "newuser",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004"
}
Member left
- SDK event:
userLeft - Description: Fired when a user leaves (or is removed from) a chat.
const unsubscribe = whisp.realtime.on("userLeft", (event) => {
console.log("user left", event.chatId, event.senderId);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is USER_LEAVE. |
chatId |
string (uuid) | Chat that was left. |
message |
string | Leave message (human-readable). |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
timeStamp |
string (date-time) | When the leave happened. |
senderId |
string (uuid) | User who left (or was removed). |
Example
{
"type": "USER_LEAVE",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"message": "johndoe left the Chat",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"timeStamp": "2024-01-15T11:00:00Z",
"senderId": "990e8400-e29b-41d4-a716-446655440004"
}
New chat
- SDK event:
chatCreated - Description: Fired when a new chat is created that the current user is a member of.
const unsubscribe = whisp.realtime.on("chatCreated", (event) => {
console.log("chat created", event.chatId, event.message);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is NEW_CHAT. |
timeStamp |
string (date-time) | When the chat was created. |
chatId |
string (uuid) | New chat id. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who created the chat. |
message |
string | Chat name. |
Example
{
"type": "NEW_CHAT",
"timeStamp": "2024-01-15T09:00:00Z",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004",
"message": "Project Discussion"
}
Chat deleted
- SDK event:
chatDeleted - Description: Fired when a chat is deleted.
const unsubscribe = whisp.realtime.on("chatDeleted", (event) => {
console.log("chat deleted", event.chatId);
});
Event object
| Field | Type | Notes |
|---|---|---|
type |
string | Event type. Here it is DELETE_CHAT. |
chatId |
string (uuid) | Deleted chat id. |
recipientId |
string (uuid) | ID of current user. Can be ignored. |
senderId |
string (uuid) | User who deleted the chat. |
Example
{
"type": "DELETE_CHAT",
"chatId": "660e8400-e29b-41d4-a716-446655440001",
"recipientId": "550e8400-e29b-41d4-a716-446655440000",
"senderId": "990e8400-e29b-41d4-a716-446655440004"
}
Reconnection & backfill
Realtime is for immediate updates. If your client was offline, you may need to backfill with REST after reconnect.
After you reconnect, load the latest messages again (or load older messages using a cursor):
// latest messages
const { messages } = await whisp.getMessages(chatId, 50);
// older messages (cursor-based pagination)
const older = await whisp.getMessages(chatId, 50, oldestMessageId);