Message threads
The message threads feature organizes conversations into threads, making it easier to follow and respond to specific topics.
Users need threads to:
-
Set topic-specific discussions - within group chats or 1:1 conversations, you can initiate or participate in separate threads dedicated to specific topics, ensuring focused and structured discussions.
-
Clarify and resolve issues - message threads let you address specific problems or questions within a conversation, allowing you to provide relevant input and ensure clarity and efficient problem-solving.
-
Reduce confusion - by allowing you to focus the conversation in a separate thread, you minimize cross-talk and make the conversation easier to follow.
In the Unity Chat SDK, a thread is a separate channel created for a selected message. Such a thread channel gets the ID starting with PUBNUB_INTERNAL_THREAD followed by the channel ID and message ID (separated by underscores). The message for which you create a thread channel has the hasThread parameter set to true to distinguish it from other messages. All messages in a thread (thread messages) are ordered by timetokens containing info on when messages were published.
Each thread message (threadMessage) and thread channel (threadChannel) are separate entities in the Unity Chat SDK that extend the message and channel entities. This means that they offer separate methods for handling threads but also let you use all methods under the message and channel entities (for example, for editing or deleting).
Create thread
CreateThread() creates a thread channel for a selected message.
Method signature
This method has the following signature:
message.CreateThread()
Input
This method doesn't take any parameters.
Output
| Type | Description |
|---|---|
Task<ThreadChannel> | An awaitable Task with the created ThreadChannel object. |
Sample code
Create a thread for the last message on the support channel.
// retrieve the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
Console.WriteLine($"Found channel with name {channel.Name}");
// fetch the last message from the "support" channel
// fetch only the last message
int count = 1;
var messageHistory = await channel.GetMessageHistory(null, null, count); // Omitting unnecessary time tokens
var lastMessage = messageHistory.FirstOrDefault();
// check if there are any messages
if (lastMessage != null)
{
show all 31 linesSend thread message
Reply to a message in a thread by calling the SendText() method from the previously created threadChannel object.
Method signature
Head over to the SendText() method section for details.
Sample code
Send a message in a thread created for the last message on the support channel.
// retrieve the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
Console.WriteLine($"Found channel with name {channel.Name}");
// fetch the last message from the "support" channel
// fetch only the last message
int count = 1;
var messageHistory = await channel.GetMessageHistory(null, null, count); // omitting unnecessary timetokens
var lastMessage = messageHistory.FirstOrDefault();
// check if there are any messages
if (lastMessage != null)
{
show all 36 linesGet thread
Get the thread channel on which the thread message is published using one of these methods:
TryGetThread()andGetThreadAsynccalled on theMessageobjectTryGetThreadChannel()andGetThreadChannelAsynccalled on theChatobject.
Method signature
- Sync
- Async
-
TryGetThread()message.TryGetThread(out ThreadChannel threadChannel) -
TryGetThreadChannel()chat.TryGetThreadChannel(Message message, out ThreadChannel threadChannel)
Input
| Parameter | Required in TryGetThread() | Required in TryGetThreadChannel() | Description |
|---|---|---|---|
messageType: MessageDefault: n/a | No | Yes | Message object for which you want to get the related thread channel. |
Output
| Parameter | Description |
|---|---|
threadChannelType: out ThreadChannel | The threadChannel to populate with the appropriate ThreadChannel object if the method returns true. If it returns false, the threadChannel remains uninitialized. |
Sample code
Get the thread channel created from the message with the 16200000000000001 timetoken.
-
TryGetThread()
show all 25 lines// reference the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
// get the message with the specific timetoken
if (channel.TryGetMessage("16200000000000001", out var message))
{
// get the thread channel created from the message
if (message.TryGetThread(out var threadChannel))
{
Console.WriteLine($"Thread channel successfully retrieved: {threadChannel.Name}");
}
else
{
Console.WriteLine("No thread channel associated with this message.");
} -
TryGetThreadChannel()
show all 25 lines// reference the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
// get the message with the specific timetoken
if (channel.TryGetMessage("16200000000000001", out var message))
{
// get the thread channel created from the message
if (chat.TryGetThreadChannel(message, out var threadChannel))
{
Console.WriteLine($"Thread channel successfully retrieved: {threadChannel.Name}");
}
else
{
Console.WriteLine("No thread channel associated with this message.");
}
-
GetThreadAsync()message.GetThreadAsync() -
GetThreadChannelAsync()chat.GetThreadChannelAsync(Message message)
Input
| Parameter | Required in GetThreadAsync() | Required in GetThreadChannelAsync() | Description |
|---|---|---|---|
messageType: MessageDefault: n/a | No | Yes | Message object for which you want to get the related thread channel. |
Output
An awaitable Task<ThreadChannel?> with the fetched ThreadChannel object or null if there wasn't one.
Sample code
Get the thread channel created from the message with the 16200000000000001 timetoken.
-
GetThreadAsync()
show all 26 lines// reference the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
// get the message with the specific timetoken
if (channel.TryGetMessage("16200000000000001", out var message))
{
// get the thread channel created from the message
var threadChannel = await message.GetThreadAsync();
if (threadChannel != null)
{
Console.WriteLine($"Thread channel successfully retrieved: {threadChannel.Name}");
}
else
{
Console.WriteLine("No thread channel associated with this message."); -
GetThreadChannelAsync()
show all 26 lines// reference the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
// get the message with the specific timetoken
if (channel.TryGetMessage("16200000000000001", out var message))
{
// get the thread channel created from the message
var threadChannel = await chat.GetThreadChannelAsync(message);
if (threadChannel != null)
{
Console.WriteLine($"Thread channel successfully retrieved: {threadChannel.Name}");
}
else
{
Console.WriteLine("No thread channel associated with this message.");
Check if message starts thread
You can use the HasThread() method to check if a given message starts a thread.
Method signature
This method has the following signature:
message.HasThread()
Properties
This method doesn't take any parameters.
Output
| Type | Description |
|---|---|
bool | Specifies if the message has started a thread (true) or not (false). |
Sample code
Check if the message with the 16200000000000001 timetoken starts a thread.
// reference the channel object
if (chat.TryGetChannel("support", out var channel))
{
// get the message history that includes the message with the specific time token
var messages = await channel.GetMessageHistory(startTimetoken: "16200000000000000", count: 1);
// assuming we get exactly one message in response
if (messages.Count > 0)
{
var message = messages[0];
// check if the message starts a thread
if (message.HasThread())
{
Console.WriteLine("The message starts a thread.");
show all 30 linesGet thread channel updates
You can receive updates when specific thread channels are edited or removed on other clients.
Method signature
Head over to OnChannelUpdate section for details.
Sample code
Get updates for the thread channel created from the message with the 16200000000000001 timetoken.
// reference the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
// get the message with the specific timetoken
if (channel.TryGetMessage("16200000000000001", out var message))
{
// get the thread channel created from the message
if (message.TryGetThread(out var threadChannel))
{
Console.WriteLine($"Thread channel successfully retrieved: {threadChannel.Name}");
// subscribe to updates on the thread channel
threadChannel.OnChannelUpdate += OnThreadChannelUpdateHandler;
}
else
show all 34 linesGet historical thread message
GetThreadHistory() called on the threadChannel object fetches historical thread messages from that thread channel.
Method signature
This method takes the following parameters:
threadChannel.GetThreadHistory(
string startTimeToken,
string endTimeToken,
int count
)
Input
| Parameter | Description |
|---|---|
startTimetoken *Type: stringDefault: n/a | Timetoken delimiting the start of a time slice (exclusive) to pull thread messages from. For details, refer to the Fetch History section. |
endTimetoken *Type: stringDefault: n/a | Timetoken delimiting the end of a time slice (inclusive) to pull messages from. For details, refer to the Fetch History section. |
count *Type: intDefault: 25 | Number of historical messages to return for the channel in a single call. Since each call returns all attached message reactions by default, the maximum number of returned messages is 25. For more details, refer to the description of the IncludeMessageActions parameter in the Unity SDK docs. |
Output
This method returns an awaitable Task<List<ThreadMessage>> with thread messages sent within the given timeframe.
By default, each call returns all message reactions and metadata attached to the retrieved thread messages.
Sample code
From the thread created for the last message in the support channel, fetch 10 historical thread messages that are older than the timetoken 15343325214676133.
// reference the "channel" object
if (chat.TryGetChannel("support", out var channel))
{
Console.WriteLine($"Found channel with name {channel.Name}");
// get the last message in the channel
var lastMessage = await channel.GetMessageHistory(count: 1)?.FirstOrDefault();
if (lastMessage != null)
{
Console.WriteLine($"Found last message with timetoken {lastMessage.TimeToken}");
// check if the last message has a thread and fetch its thread channel
if (lastMessage.TryGetThreadChannel(out var threadChannel))
{
// fetch 10 historical thread messages older than the timetoken '15343325214676133'
show all 19 linesRemove thread
RemoveThread() removes a thread channel for a selected message.
Method signature
This method has the following signature:
message.RemoveThread()
Input
This method doesn't take any parameters.
Output
An awaitable Task.
Sample code
Remove a thread for the last message on the support channel.
// reference the "channel" object
if (chat.TryGetChannel("support", out var channel))
{
Console.WriteLine($"Found channel with name {channel.Name}");
// get the last message in the channel
var lastMessage = await channel.GetMessageHistory(count: 1)?.FirstOrDefault();
if (lastMessage != null)
{
Console.WriteLine($"Found last message with timetoken {lastMessage.TimeToken}");
// remove the thread for the last message
await lastMessage.RemoveThread();
Console.WriteLine("Thread removed for the last message.");
}
show all 24 linesPin thread message to thread channel
To pin a selected thread message to the thread channel, use the PinMessage() method.
This method is available on the Channel object, but you can call it from the ThreadChannel object as ThreadChannel inherits all public methods from the Channel object.
Method signature
Head over to the PinMessage() section for details.
Sample code
A thread was created for the last message in the support parent channel. Pin the last message from this thread to the thread channel.
// reference the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
Console.WriteLine($"Found channel with name {channel.Name}");
// get the last message on the channel, which is the root message for the thread
var channelMessageHistory = await channel.GetMessageHistory(null, null, 1);
var message = channelMessageHistory.FirstOrDefault();
// get the thread channel
if (message != null && message.TryGetThread(out ThreadChannel threadChannel))
{
// get the last message on the thread channel
var threadMessageHistory = await threadChannel.GetMessageHistory(null, null, 1);
var threadMessage = threadMessageHistory.FirstOrDefault();
show all 36 linesPin thread message to parent channel
You can pin a selected thread message to the parent channel with PinMessageToParentChannel() methods. They give the same output, and the only difference is that you call a given method either on the ThreadChannel or the ThreadMessage object. Depending on the object, these methods take different input parameters - you have to specify the thread message you want to pin or not because it's already known.
Method signature
These methods take the following parameters:
-
PinMessageToParentChannel()(onthreadChannelobject)threadChannel.PinMessageToParentChannel(Message message) -
PinMessageToParentChannel()(onthreadMessageobject)threadMessage.PinMessageToParentChannel()
Input
| Parameter | Required in the threadChannel object method | Required in the threadMessage object method | Description |
|---|---|---|---|
messageType: MessageDefault: n/a | Yes | No | Message object you want to pin to the selected parent channel. |
Output
An awaitable Task.
Sample code
A thread was created for the last message in the support parent channel. Pin the last message from this thread to the parent channel.
-
PinMessageToParentChannel()
show all 29 lines// reference the "support" channel where the root message for the thread is published
if (chat.TryGetChannel("support", out var channel))
{
Console.WriteLine($"Found channel with name {channel.Name}");
// get the last message on the channel, which is the root message for the thread
var channelMessageHistory = await channel.GetMessageHistory(null, null, 1);
var message = channelMessageHistory[0];
// get the thread channel
if (message.TryGetThread(out ThreadChannel threadChannel))
{
// get the last message on the thread channel
var threadMessageHistory = await threadChannel.GetMessageHistory(null, null, 1);
var threadMessage = threadMessageHistory[0]; -
PinToParentChannel()
show all 29 lines// reference the "support" channel where the root message for the thread is published
if (chat.TryGetChannel("support", out var channel))
{
Console.WriteLine($"Found channel with name {channel.Name}");
// get the last message on the channel, which is the root message for the thread
var channelMessageHistory = await channel.GetMessageHistory(null, null, 1);
var message = channelMessageHistory[0];
// get the thread channel
if (message.TryGetThread(out ThreadChannel threadChannel))
{
// get the last message on the thread channel
var threadMessageHistory = await threadChannel.GetMessageHistory(null, null, 1);
var threadMessage = threadMessageHistory[0];
Unpin thread message from thread channel
To unpin a selected thread message from the thread channel, use the UnpinMessage() method.
This method is available on the Channel object, but you can call it from the ThreadChannel object as ThreadChannel inherits all public methods from the Channel object.
Method signature
Head over to the UnpinMessage() section for details.
Sample code
Unpin the thread message from the thread (channel) created for the last message on the support channel.
// reference the "support" channel
if (chat.TryGetChannel("support", out var channel))
{
Console.WriteLine($"Found channel with name {channel.Name}");
// get the last message on the channel, which is the root message for the thread
var channelMessageHistory = await channel.GetMessageHistory(null, null, 1);
var message = channelMessageHistory.FirstOrDefault();
// get the thread channel
if (message != null && message.TryGetThread(out ThreadChannel threadChannel))
{
// unpin the last message from the thread channel
await threadChannel.UnpinMessage();
Console.WriteLine("Unpinned a message from the thread channel.");
show all 25 linesUnpin thread message from parent channel
You can unpin the previously pinned thread message from the parent channel with UnpinMessageFromParentChannel() methods. They give the same output, and the only difference is that you call a given method either on the ThreadChannel or the ThreadMessage object.
Method signature
These methods have the following signatures:
-
UnpinMessageFromParentChannel()(on thethreadChannelobject)threadChannel.UnPinMessageFromParentChannel() -
UnpinMessageFromParentChannel()(on thethreadMessageobject)threadMessage.UnPinMessageFromParentChannel()
Input
These methods don't take any parameters.
Output
An awaitable Task.
Sample code
Unpin the thread message from the support parent channel.
-
UnpinMessageFromParentChannel()(on thethreadChannelobject)
show all 34 lines// reference the "support" channel
if (chat.TryGetChannel("support", out var supportChannel))
{
Console.WriteLine($"Found channel with name {supportChannel.Name}");
// retrieve the message history
var messageHistory = await supportChannel.GetMessageHistory(1);
// get the last message from the returned list
var lastMessage = messageHistory.Messages.FirstOrDefault();
// unpin the last message if it exists
if (lastMessage != null)
{
// Now we use the correct method to get the thread channel -
UnPinMessageFromParentChannel()(on thethreadMessageobject)
show all 27 lines// reference the "support" channel
if (chat.TryGetChannel("support", out var supportChannel))
{
Console.WriteLine($"Found channel with name {supportChannel.Name}");
// retrieve the message history with the desired count
var messageHistory = await supportChannel.GetMessageHistory(1);
// get the last message from the returned list
var lastMessage = messageHistory.Messages.FirstOrDefault();
// unpin the last message if it exists
if (lastMessage != null)
{
// Here we unpin the message using threadMessage's instance method