Conversations

A conversation is a chat channel where messages can be sent. Users can participate in many conversations at once.

interface ConversationRef

References the conversation with a given conversation ID, from the perspective of the current user.

Used in all Data API operations affecting that conversation, such as fetching or updating conversation attributes. Created via Session.conversation().

Method Overview

createIfNotExists

Creates this conversation if it does not already exist. Adds you as a participant in this conversation, if you are not already a participant.

get

Fetches a snapshot of the conversation.

markAsRead

Marks the conversation as read.

markAsTyping

Marks the current user as typing in this conversation for 10 seconds.

markAsUnread

Marks the conversation as unread.

message

Get a reference to a message in this conversation

participant

Get a reference to a participant in this conversation

send

Sends a message in the conversation

set

Sets properties of this conversation and your participation in it.

subscribe

Subscribes to the conversation.

subscribeMessages

Subscribes to the messages in the conversation.

subscribeTyping

Subscribes to the typing status of the conversation.

Properties

id
: string

The ID of the referenced conversation.

Immutable: if you want to reference a different conversation, get a new ConversationRef instead.

createIfNotExists

conversationRef.createIfNotExists(params): Promise<void>

Creates this conversation if it does not already exist. Adds you as a participant in this conversation, if you are not already a participant.

If the conversation already exists or you are already a participant, this operation is still considered successful and the promise will still resolve.

Parameters

params (optional)
: CreateConversationParams
interface CreateConversationParams

Parameters you can pass to ConversationRef​.createIfNotExists.

Properties that are undefined will be set to the default.

access (optional)
: "Read" | "ReadWrite"

Your access to the conversation. Default = "ReadWrite" access.

custom (optional)
: Record<string, string>

Custom metadata you have set on the conversation. This value acts as a patch. Remove specific properties by setting them to null. Default = no custom metadata

notify (optional)
: boolean | "MentionsOnly"

Your notification settings. Default = true

photoUrl (optional)
: string

The URL for the conversation photo to display in the chat header. Default = no photo, show a placeholder image.

subject (optional)
: string

The conversation subject to display in the chat header. Default = no subject, list participant names instead.

welcomeMessages (optional)
: string[]

System messages which are sent at the beginning of a conversation. Default = no messages.

Returns

Promise<void>

A promise that resolves when the operation completes. The promise rejects if you are not already a participant and client-side conversation syncing is disabled.

get

conversationRef.get(): Promise<ConversationSnapshot | null>

Fetches a snapshot of the conversation.

This contains all of the information related to the conversation and the current user's participation in the conversation.

Returns

Promise<ConversationSnapshot | null>

A snapshot of the current user's view of the conversation, or null if the current user is not a participant (including if the conversation doesn't exist).

markAsRead

conversationRef.markAsRead(): Promise<void>

Marks the conversation as read.

Returns

Promise<void>

A promise that resolves when the operation completes. The promise rejects if you are not a participant in the conversation.

markAsTyping

conversationRef.markAsTyping(): Promise<void>

Marks the current user as typing in this conversation for 10 seconds.

This means that other users will see a typing indicator in the UI, from the current user.

The user will automatically stop typing after 10 seconds. You cannot manually mark a user as "not typing". Users are also considered "not typing" when they send a message, even if that message was sent from a different tab or using the REST API.

To keep the typing indicator visible for longer, call this function again to reset the 10s timer.

Returns

Promise<void>

Usage

Example
Example implementation
1let lastMarkedAsTyping = 0;
2
3inputElement.addEventListener("change", event => {
4 const text = event.target.value;
5
6 // Deleting your draft never counts as typing
7 if (text.length === 0) {
8 return;
9 }
10
11 const now = Date.now();
12
13 // Don't mark as typing more than once every 5s
14 if (now - lastMarkedAsTyping > 5000) {
15 lastMarkedAsTyping = now;
16 convRef.markAsTyping();
17 }
18});
19
20// When you send a message, you are no longer considered typing
21// So we need to send markAsTyping as soon as you type something
22function onSendMessage() {
23 lastMarkedAsTyping = 0;
24}

markAsUnread

conversationRef.markAsUnread(): Promise<void>

Marks the conversation as unread.

Returns

Promise<void>

A promise that resolves when the operation completes. The promise rejects if you are not a participant in the conversation.

message

conversationRef.message(id): MessageRef

Get a reference to a message in this conversation

Use this if you need to fetch, delete, or edit a specific message in this conversation, and you know its message ID. To fetch the most recent messages in this conversation, use subscribeMessages instead.

Parameters

id
: string

The ID of the user that you want to reference

Returns

MessageRef

A for the user with that ID

participant

conversationRef.participant(user): ParticipantRef

Get a reference to a participant in this conversation

Note that Participant is not the same as User. A Participant represents a user's settings related to a specific conversation.

Calling ConversationRef.createIfNotExists or ConversationRef.set will automatically add the current user as a participant.

Parameters

user
: string | UserRef

Specifies which participant in the conversation you want to reference. Either the user's ID, or a reference to that user.

Returns

ParticipantRef

A for that user's participation in this conversation

Usage

Example 1
To add "Alice" to the conversation "Cats"
1session.conversation("Cats").participant("Alice").createIfNotExists();

The user "Alice" must exist before you do this.

Example 2
To remove "Alice" from the conversation "Cats"
1session.conversation("Cats").participant("Alice").delete();

The user "Alice" will still exist after you do this. This deletes the participant, not the user.

send

conversationRef.send(params): Promise<MessageRef>

Sends a message in the conversation

Parameters

interface SendTextMessageParams

Parameters you can pass to ConversationRef​.send.

Properties that are undefined will be set to the default.

This is a simpler version of SendMessageParams that only supports text messages.

text
: string

The text to send in the message.

This is parsed the same way as the text entered in the message field. For example, *hi* will appear as hi in bold.

See the message formatting documentation for more details.

custom (optional)
: Record<string, string>

Custom metadata you have set on the user. Default = no custom metadata

referencedMessage (optional)
: string | MessageRef

The message that you are replying to. Default = not a reply

interface SendMessageParams

Parameters you can pass to ConversationRef​.send.

Properties that are undefined will be set to the default.

This is the more advanced method for editing a message, giving full control over the message content. You can decide exactly how a text message should be formatted, edit an attachment, or even turn a text message into a location.

content
: [SendContentBlock]

The most important part of the message, either some text, a file attachment, or a location.

By default users do not have permission to send LinkNode, ActionLinkNode, or ActionButtonNode, as they can be used to trick the recipient.

Currently, each message can only contain a single SendContentBlock.

custom (optional)
: Record<string, string>

Custom metadata you have set on the user. Default = no custom metadata

referencedMessage (optional)
: string | MessageRef

The message that you are replying to. Default = not a reply

Returns

Promise<MessageRef>

A promise that resolves with a reference to the newly created message. The promise will reject if you do not have permission to send the message.

Usage

Example 1
Send a simple message with markup (bold in this example)
1conversationRef.send("*Hello*");
Example 2
Reply to a message and set custom message data
1conversationRef.send({
2 text: "Agreed",
3 referencedMessageId: "...",
4 custom: { priority: "HIGH" }
5});
Example 3
Send pre-formatted text with TextBlock
1conversationRef.send({
2 content: [{
3 type: "text",
4 children: [{
5 type: "bold",
6 children: ["Hello"]
7 }]
8 }]
9});
Example 4
Send a file with SendFileBlock
1// `file` is a File object from `<input type="file">`
2const fileToken = await session.uploadImage(
3 file, { filename: file.name, width: 640, height: 480 }
4);
5
6conversationRef.send({
7 content: [{ type: "file", fileToken }]
8});
Example 5
Send a location with LocationBlock
1// You can get the user's location with the browser's geolocation API
2const [latitude, longitude] = [42.43, -83.99];
3conversationRef.send({
4 content: [{ type: "location", latitude, longitude }]
5});

set

conversationRef.set(params): Promise<void>

Sets properties of this conversation and your participation in it.

The conversation is created if a conversation with this ID doesn't already exist. You are added as a participant if you are not already a participant in the conversation.

Parameters

interface SetConversationParams

Parameters you can pass to ConversationRef​.set.

Properties that are undefined will not be changed. To clear / reset a property to the default, pass null.

access (optional)
: "Read" | "ReadWrite" | null

Your access to the conversation. Default = "ReadWrite" access.

custom (optional)
: Record<string, string | null> | null

Custom metadata you have set on the conversation. This value acts as a patch. Remove specific properties by setting them to null. Default = no custom metadata

notify (optional)
: boolean | "MentionsOnly" | null

Your notification settings. Default = true

photoUrl (optional)
: string | null

The URL for the conversation photo to display in the chat header. Default = no photo, show a placeholder image.

subject (optional)
: string | null

The conversation subject to display in the chat header. Default = no subject, list participant names instead.

welcomeMessages (optional)
: string[] | null

System messages which are sent at the beginning of a conversation. Default = no messages.

Returns

Promise<void>

A promise that resolves when the operation completes. When client-side conversation syncing is disabled, you must already be a participant and you cannot set anything except the notify property. Everything else requires client-side conversation syncing to be enabled, and will cause the promise to reject.

subscribe

conversationRef.subscribe(onSnapshot): ConversationSubscription

Subscribes to the conversation.

Whenever Subscription.state.type is "active" and something about the conversation changes, onSnapshot will fire and Subscription.state.latestSnapshot will be updated. This includes changes to nested data. As an extreme example, onSnapshot would be called when snapshot.lastMessage.referencedMessage.sender.name changes.

The snapshot is null if you are not a participant in the conversation (including when the conversation doesn't exist)

Parameters

onSnapshot (optional)
: (snapshot: ConversationSnapshot | null) => void

Returns

ConversationSubscription

subscribeMessages

conversationRef.subscribeMessages(onSnapshot): MessageSubscription

Subscribes to the messages in the conversation.

Initially, you will be subscribed to the 30 most recent messages and any new messages. Call loadMore to load additional older messages.

Whenever Subscription.state.type is "active" and a message is sent, edited, deleted, or you load more messages, onSnapshot will fire and Subscription.state.latestSnapshot will be updated. loadedAll is true when the snapshot contains all the messages in the conversation.

The snapshot is null if you are not a participant in the conversation (including when the conversation doesn't exist)

Parameters

onSnapshot (optional)
: ( snapshot: MessageSnapshot[] | null, loadedAll: boolean ) => void

Returns

MessageSubscription

subscribeTyping

conversationRef.subscribeTyping(onSnapshot): TypingSubscription

Subscribes to the typing status of the conversation.

Whenever Subscription.state.type is "active" and the typing status changes, onSnapshot will fire and Subscription.state.latestSnapshot will be updated. This includes changes to nested data, such as when a user who is typing changes their name.

The snapshot is null if you are not a participant in the conversation (including when the conversation doesn't exist)

Note that if there are "many" people typing and another person starts to type, onSnapshot will not be called. This is because your existing ManyTypingSnapshot is still valid and did not change when the new person started to type.

Parameters

onSnapshot (optional)
: (snapshot: TypingSnapshot | null) => void

Returns

TypingSubscription

interface ConversationSnapshot

A snapshot of a conversation's attributes at a given moment in time.

Also includes information about the current user's view of that conversation, such as whether or not notifications are enabled.

Snapshots are immutable and we try to reuse them when possible. You should only re-render your UI when oldSnapshot !== newSnapshot.

Properties

access
: "Read" | "ReadWrite"

The current user's permission level in this conversation.

createdAt
: number

The date that the conversation was created, as a unix timestamp in milliseconds.

custom
: Record<string, string>

Custom metadata you have set on the conversation

id
: string

The ID of the conversation

isUnread
: boolean

Whether the conversation should be considered unread.

This can be true even when unreadMessageCount is zero, if the user has manually marked the conversation as unread.

joinedAt
: number

The date that the current user joined the conversation, as a unix timestamp in milliseconds.

lastMessage
: MessageSnapshot | null

The last message sent in this conversation, or null if no messages have been sent.

notify
: boolean | "MentionsOnly"

The current user's notification settings for this conversation.

false means no notifications, true means notifications for all messages, and "MentionsOnly" means that the user will only be notified when they are mentioned with an @.

photoUrl
: string | null

Contains the URL of a photo to represent the topic of the conversation or null if the conversation does not have a photo specified.

readUntil
: number

Timestamp of when the current user read a message

subject
: string | null

Contains the conversation subject, or null if the conversation does not have a subject specified.

unreadMessageCount
: number

The number of messages in this conversation that the current user hasn't read.

welcomeMessages
: string[]

One or more welcome messages that will display to the user as a SystemMessage

interface ConversationSubscription

A subscription to a specific conversation.

Get a ConversationSubscription by calling ConversationRef​.subscribe

Method Overview

unsubscribe

Unsubscribe from this resource and stop receiving updates.

Properties

connected
: Promise<ConversationActiveState>

Resolves when the subscription starts receiving updates from the server.

state
: PendingState | ConversationActiveState | UnsubscribedState | ErrorState

The current state of the subscription

An object with the following fields:

type is one of "pending", "active", "unsubscribed", or "error".

When type is "active", includes latestSnapshot: ConversationSnapshot | null, the current state of the conversation. latestSnapshot is null when you are not a participant or the conversation does not exist.

When type is "error", includes the error field. It is a JS Error object explaining what caused the subscription to be terminated.

terminated
: Promise<UnsubscribedState | ErrorState>

Resolves when the subscription permanently stops receiving updates from the server.

This is either because you unsubscribed or because the subscription encountered an unrecoverable error.

unsubscribe

conversationSubscription.unsubscribe()

Unsubscribe from this resource and stop receiving updates.

If the subscription is already in the "unsubscribed" or "error" state, this is a no-op.

Returns

void

interface MessageSubscription

A subscription to the messages in a specific conversation.

Get a MessageSubscription by calling ConversationRef​.subscribeMessages

The subscription is 'windowed'. It includes all messages since a certain point in time. By default, you subscribe to the 30 most recent messages, and any new messages are sent after you subscribe.

You can expand this window by calling loadMore, which extends the window further into the past.

Method Overview

loadMore

Expand the window to include older messages

unsubscribe

Unsubscribe from this resource and stop receiving updates.

Properties

connected
: Promise<MessageActiveState>

Resolves when the subscription starts receiving updates from the server.

Wait for this promise if you want to perform some action as soon as the subscription is active.

The promise rejects if the subscription is terminated before it connects.

state
: PendingState | MessageActiveState | UnsubscribedState | ErrorState

The current state of the subscription

An object with the following fields:

type is one of "pending", "active", "unsubscribed", or "error".

When type is "active", includes latestSnapshot and loadedAll.

- latestSnapshot: MessageSnapshot[] | null the current state of the messages in the window, or null if you're not a participant in the conversation

- loadedAll: boolean true when latestSnapshot contains all the messages in the conversation

When type is "error", includes the error field. It is a JS Error object explaining what caused the subscription to be terminated.

terminated
: Promise<UnsubscribedState | ErrorState>

Resolves when the subscription permanently stops receiving updates from the server.

This is either because you unsubscribed or because the subscription encountered an unrecoverable error.

loadMore

messageSubscription.loadMore(count): Promise<void>

Expand the window to include older messages

Calling loadMore multiple times in parallel will still only load one page of messages.

Parameters

count (optional)
: number

The number of additional messages to load. Must be between 1 and 100

Returns

Promise<void>

A promise that resolves once the additional messages have loaded

unsubscribe

messageSubscription.unsubscribe()

Unsubscribe from this resource and stop receiving updates.

If the subscription is already in the "unsubscribed" or "error" state, this is a no-op.

Returns

void

type TypingSnapshot

A snapshot of the typing indicators in a conversation at a given moment in time. Will be either FewTypingSnapshot when only a few people are typing, or ManyTypingSnapshot when many people are typing.

Currently FewTypingSnapshot is used when there are 5 or less people typing in the conversation, and ManyTypingSnapshot is used when more than 5 people are typing. This limit may change in the future, which will not be considered a breaking change.

Example
Converting a TypingSnapshot to text
1function formatTyping(snapshot: TypingSnapshot): string {
2 if (snapshot.many) {
3 return "Several people are typing";
4 }
5
6 const names = snapshot.users.map(user => user.name);
7
8 if (names.length === 0) {
9 return "";
10 }
11
12 if (names.length === 1) {
13 return names[0] + " is typing";
14 }
15
16 if (names.length === 2) {
17 return names.join(" and ") + " are typing";
18 }
19
20 // Prefix last name with "and "
21 names.push("and " + names.pop());
22 return names.join(", ") + " are typing";
23}

interface FewTypingSnapshot

The TypingSnapshot variant used when only a few people are typing.

Properties

many
: false

Check this to differentiate between FewTypingSnapshot (false) and ManyTypingSnapshot (true).

When false, you can see the list of users who are typing in the users property.

users
: UserSnapshot[]

The users who are currently typing in this conversation.

The list is in chronological order, starting with the users who have been typing the longest. The current user is never contained in the list, only other users.

interface ManyTypingSnapshot

The TypingSnapshot variant used when many people are typing.

Properties

many
: true

Check this to differentiate between FewTypingSnapshot (false) and ManyTypingSnapshot (true).

When true, you do not receive a list of users who are typing. You should show a message like "several people are typing" instead.

interface TypingSubscription

A subscription to the typing status in a specific conversation

Get a TypingSubscription by calling ConversationRef​.subscribeTyping.

When there are "many" people typing (meaning you received ManyTypingSnapshot), the next update you receive will be FewTypingSnapshot once enough people stop typing. Until then, your ManyTypingSnapshot is still valid and doesn not need to changed, so onSnapshot will not be called.

Method Overview

unsubscribe

Unsubscribe from this resource and stop receiving updates.

Properties

connected
: Promise<TypingActiveState>

Resolves when the subscription starts receiving updates from the server.

Wait for this promise if you want to perform some action as soon as the subscription is active.

The promise rejects if the subscription is terminated before it connects.

state
: PendingState | TypingActiveState | UnsubscribedState | ErrorState

The current state of the subscription

An object with the following fields:

type is one of "pending", "active", "unsubscribed", or "error".

When type is "active", includes latestSnapshot: TypingSnapshot | null. It is the current state of the typing indicators, or null if you're not a participant in the conversation

When type is "error", includes the error: Error field. It is a JS Error object explaining what caused the subscription to be terminated.

terminated
: Promise<UnsubscribedState | ErrorState>

Resolves when the subscription permanently stops receiving updates from the server.

This is either because you unsubscribed or because the subscription encountered an unrecoverable error.

unsubscribe

typingSubscription.unsubscribe()

Unsubscribe from this resource and stop receiving updates.

If the subscription is already in the "unsubscribed" or "error" state, this is a no-op.

Returns

void