TextChatService Overview

Roblox offers text-based messaging between players in live sessions through TextChatService. This service has its standard functionality, but also provides a set of methods and events for extending and customizing chat, such as delivering messages based on customized requirements, adding special permissions or moderation to specific players, and creating custom commands to execute specific actions.

Text Chat Instances

The following sections summarize the primary classes and instances that you can use to customize the chat system.

Top-Level Configuration

Default UI Configuration

TextChatService provides a default UI that can be customized to fit your experience's needs. Each of these configurations can be disabled to hide the associated UI element and can be replaced with custom interfaces if desired.

Channels, Messages, and Commands

  • TextChannel - Represents a text chat channel that passes user-sent chat messages from the client to the server, which then displays them to other users based on permissions. These instances must be parented to TextChatService in order to function. If TextChatService.CreateDefaultTextChannels is set to true, the service automatically creates two text channels, RBXGeneral and RBXSystem. You can manually create additional TextChannel instances and parent them to TextChatService, as well.

    • TextSource - Represents a user in a TextChannel. These instances are directly parented to the TextChannel when TextChannel:AddUserAsync() is used. Text sources contains detailed permissions of a user in the channel, such as their ability to send messages. A single user can be associated with multiple text sources if they have been added to multiple text channels.
  • TextChatMessage - Represents a single chat message in a text channel, with basic information such as the sender of the message, the original message, the filtered message, and the creation timestamp.

  • TextChatCommand - Allows users to invoke specific actions or behaviors by sending messages that match TextChatCommand.PrimaryAlias or TextChatCommand.SecondaryAlias. These instances must be parented to TextChatService in order to function. Chat commands are helpful for adding additional functionality and interactivity to the chat experience. If TextChatService.CreateDefaultCommands is set to true, default chat commands will be created automatically. You can manually create additional TextChatCommand instances and parent them to TextChatService, as well.

Chat Flowchart

Text chat uses the client‑server model, with a sending client, the server, and receiving clients.

A flowchart for in-experience text chat.
  1. A player sends a message from their local device, triggering the TextChannel:SendAsync() method. This method processes the message and determines whether it's a chat command or a regular chat message.

  2. The server fires TextChannel.ShouldDeliverCallback to determine whether to deliver the message to other players based on permissions and Roblox community filtering requirements.

  3. If TextChannel.ShouldDeliverCallback determines that message is eligible to deliver to other players, the server applies any filters and fires TextChannel.OnIncomingMessage twice:

    1. The first time is on the sending client and signals that the server is processing the message through the TextChatService.MessageReceived event. This event replaces the local message on the sending client with the processed message from the server. The message is identical if the original didn't require filtering.

    2. The second time is on the receiving clients, which triggers the TextChatService.MessageReceived event to display the message to other players.

Text Chat Hooks and Callbacks

The TextChatService API encourages a clear separation on the appearance and delivery of chat messages. Multiple instances of the text chat system provide hooks and callbacks to format in centralized, clear locations.

A flowchart of the TextChatService callbacks order

Conditionally Delivering Messages

  • TextChannel.ShouldDeliverCallback - This callback should be defined on the server only. The callback is fired for each TextSource child of the text channel when a message is sent to determine whether the message should be delivered. This callback can be used to implement custom message delivery logic that may depend on additional gameplay context, such as:

    • Proximity-based chat where users can only send messages to those close to them.
    • Preventing users with certain attributes from sending messages to others.

Customizing Message Display

The default TextChatService UI relies on rich text to format and customize how messages are displayed. You can use the following callbacks to format messages before they are displayed to users. You might want to add colors or chat tags to user's names or format message content.

The following callbacks are called on every TextChatMessage that is about to be displayed, which lets you customize chat window appearance based on the TextChannel, TextSource, or TextChatMessage content.

When a client sends a message, these callbacks are called once when the message is sent to the server and the TextChatMessage.Status value will be Enum.TextChatMessageStatus.Sending. Once the message is received by the server and is being delivered to other users, the sender client receives the message again with an updated Enum.TextChatMessageStatus value.

  • TextChatService.OnIncomingMessage - This callback should be defined on the client only. The callback is fired when a message is received, either from the server or if the local client has just sent a message. The callback is called on every TextChatMessage received from all TextChannel instances and is the first to process the message before it is displayed to the user.
  • TextChannel.OnIncomingMessage - This callback should be defined on the client only. The callback is fired when a message is received from the server. The callback is called on every TextChatMessage received from the TextChannel. Default TextChannel instances created from TextChatService.CreateDefaultTextChannels have this callback defined and can be overwritten.
  • TextChatService.OnBubbleAdded - This callback should be defined on the client only. Use it to customize the appearance of chat bubbles independent of the appearance of the message in the chat window UI.
  • TextChatService.OnChatWindowAdded - This callback should be defined on the client only. Use it to customize the appearance of chat messages in the chat window UI independent of the appearance of the message in chat bubbles.

Migrating From Legacy Chat

This section assists you in migrating from the legacy chat system by providing alternative methods for implementing common chat functionalities and behaviors using TextChatService.

To switch the chat system of an existing experience from the legacy chat system to TextChatService:

  1. In the Explorer window, select TextChatService.

  2. In the Properties window, find the ChatVersion dropdown and select TextChatService.

Basic Functionalities

Though both systems share the same basic chat functionalities, TextChatService implementations are in general more sustainable and easier to iterate on.

FunctionalityLegacy ChatTextChatServiceDifferences
Send a chat messagePlayers:Chat()TextChannel:SendAsync()The TextChatService:SendAsync() method supports more advanced chat features, such as rich text formatting and message priority. It also includes built-in filtering to help prevent inappropriate messages from being sent.
Implement messaging callbacksChat:InvokeChatCallback()
Chat:RegisterChatCallback()
TextChatService.SendingMessage
TextChatService.OnIncomingMessage
The legacy chat system binds a function to chat system events for delivering messages. The two methods of TextChatService offer better flexibility and customization.
Add custom chat commandsChatService/ChatCommand moduleTextChatCommandTextChatService has a dedicated class for text commands rather than using a legacy chat module.
Display a system messageStarterGui:SetCore() using ChatMakeSystemMessageTextChannel:DisplaySystemMessage()The TextChannel.OnIncomingMessage callback can return a TextChatMessageProperties instance to customize the message appearance.
Disable chatGame Settings in Studio and ChatWindow/ChatSettings module for hiding the chat windowChatWindowConfiguration.Enabled

Message Filtering

TextChatService automatically filters chat messages based on each player's account information, so you don't need to manually implement text filtering for all kinds of chat messages.

FunctionalityLegacy ChatTextChatService
Filter chat message for individual playerChat:FilterStringAsync()Automatic
Filter broadcasting messagesChat:FilterStringForBroadcast()Automatic

Window and Bubble Chat

Both the chat window and bubble chat behavior and customization options of TextChatService are identical to those of the legacy chat system. As the legacy chat system only allows customization using chat modules or the Players container, TextChatService provides dedicated classes (ChatWindowConfiguration and BubbleChatConfiguration) to manage all chat window and bubble chat properties. Additionally, you can easily adjust and preview your bubble chat appearance and behavior properties using Studio settings instead of having to script them all.

Migrating Speaker "Extra Data"

The legacy Lua chat system allowed devleopers to use SetExtraData on the Speaker class. This data was used to format the name color, chat color, or to apply name tags for a given speaker.

Legacy Chat System SetExtraData

-- An example of setting extra data on a speaker in the legacy chat system
ChatService.SpeakerAdded:Connect(function(playerName)
local speaker = ChatService:GetSpeaker(playerName)
speaker:SetExtraData("NameColor", Color3.fromRGB(255, 255, 55))
speaker:SetExtraData("ChatColor", Color3.fromRGB(212, 175, 55))
speaker:SetExtraData("Tags", {{TagText = "YourTagName", TagColor = Color3.fromRGB(0, 255, 0)}, {TagText = "OtherTagName", TagColor = Color3.fromRGB(255, 0, 0)}})
end)

TextChatService does not have a direct equivalent to SetExtraData. Instead, use TextChatService callbacks such as TextChatService.OnWindowAdded to customize the appearance of messages using rich text based on the TextSource of the message.

The following is an example of emulating legacy Lua chat's "extra data" by access attributes on the TextSource's Player:

TextChatService SetAttributes

local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
player:SetAttribute("NameColor", Color3.fromRGB(255, 255, 55))
player:SetAttribute("ChatColor", Color3.fromRGB(212, 175, 55))
player:SetAttribute("isYourTag", true)
player:SetAttribute("isOtherTag", true)
end)

Then you can use the OnChatWindowAdded callback to customize the appearance of the chat window based on the attributes set on the player:

TextChatService OnChatWindowAdded

local TextChatService = game:GetService("TextChatService")
local Players = game:GetService("Players")
TextChatService.OnChatWindowAdded = function(textChatMessage)
local textSource = textChatMessage.TextSource
if textSource then
local player = Players:GetPlayerByUserId(textSource.UserId)
if player then
local overrideProperties = TextChatService.ChatWindowConfiguration:DeriveNewMessageProperties()
overrideProperties.PrefixText = textChatMessage.PrefixText
overrideProperties.Text = textChatMessage.Text
local nameColor = player:GetAttribute("NameColor")
if nameColor and typeof(nameColor) == "Color3" then
overrideProperties.PrefixTextProperties.TextColor3 = nameColor
end
local chatColor = player:GetAttribute("ChatColor")
if chatColor and typeof(chatColor) == "Color3" then
overrideProperties.TextColor3 = chatColor
end
local isYourTag = player:GetAttribute("isYourTag")
if isYourTag == true then
overrideProperties.PrefixText = `<font color='rgb(0, 255, 0)'>[YourTag]</font> {overrideProperties.PrefixText}`
end
local isOtherTag = player:GetAttribute("isOtherTag")
if isOtherTag == true then
overrideProperties.PrefixText = `<font color='rgb(255, 0, 0)'>[OtherTag]</font> {overrideProperties.PrefixText}`
end
return overrideProperties
end
end
return nil
end