roblox-text-chat
Skill92 starsChanged 47 days agoMITView on GitHub
Chat and text safety - TextChatService (channels, SendAsync, ShouldDeliverCallback, OnIncomingMessage, commands, bubbles, custom UI, platform-integrated chat and TextChannelWindow migration due May 2027), mandatory TextService filtering of any player-authored text, rate limits, privacy checks, PolicyService restrictions, legacy Chat migration. Use when adding chat features or commands, or any feature that shows one player's text to others (names, signs, notes).
In this repository25 other files it gives its agents.
- AGENTS.mdAGENTS.md
- docs/agents.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- roblox-analytics-liveopsSkill
- roblox-architectureSkill
- roblox-audioSkill
- roblox-characters-animationSkill
- roblox-code-reviewSkill
- roblox-data-storesSkill
- roblox-game-systemsSkill
- roblox-inputSkill
- roblox-luauSkill
- roblox-monetizationSkill
- roblox-networkingSkill
- roblox-npc-aiSkill
- roblox-open-cloudSkill
- roblox-performanceSkill
- roblox-physicsSkill
- roblox-securitySkill
- roblox-studio-mcpSkill
- roblox-teleport-matchmakingSkill
- roblox-testingSkill
- roblox-toolingSkill
- roblox-uiSkill
- roblox-world-buildingSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 20
Not chat (no filtering needed): your own UI text, game status messages, admin announcements you write.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Chat and text safety
Non-negotiable rules (Roblox Community Standards)
- Player-to-player conversation must go through TextChatService
TextChannels (handles filtering, privacy/parental settings, and abuse reporting). The legacyChatservice/ChatServiceLua modules are gone —TextChatServiceis the only chat system. - Any text authored by one player and shown to another (pet names, signs, guild names, trade notes,
custom UI) must be filtered with
TextService:FilterStringAsyncon the server before display — and re-filtered when loaded from a DataStore later. - Editable text others can see (signs, bulletin boards) needs a rate limit of at least 1 minute.
- Respect privacy settings with
CanUserChatAsync/CanUsersChatAsync/CanUsersDirectChatAsyncand mark direct-message channels withTextChannel:SetDirectChatRequester().
Not chat (no filtering needed): your own UI text, game status messages, admin announcements you write.
Filtering player-authored text
--!strict
local TextService = game:GetService("TextService")
-- Broadcast (e.g. a sign everyone sees). Returns nil if filtering failed: then show nothing.
local function filterForEveryone(text: string, fromUserId: number): string?
local ok, result = pcall(function()
local filterResult = TextService:FilterStringAsync(text, fromUserId, Enum.TextFilterContext.PublicChat)
return filterResult:GetNonChatStringForBroadcastAsync()
end)
return if ok then result else nil
end
-- Per-recipient (respects each viewer's age/settings; e.g. a private note).
local function filterForUser(text: string, fromUserId: number, toUserId: number): string?
local ok, result = pcall(function()
local filterResult = TextService:FilterStringAsync(text, fromUserId, Enum.TextFilterContext.PrivateChat)
return filterResult:GetNonChatStringForUserAsync(toUserId)
end)
return if ok then result else nil
end
return { forEveryone = filterForEveryone, forUser = filterForUser }- Filter on the server, after the player submits (not per keystroke); rate-limit and length-cap first.
- On failure, fail closed (show nothing / a placeholder), never the raw text.
- Store the raw text if you must, but always filter at display time (filters and viewer settings change).
- Numbers-only or short strings can still be filtered (hashtags
###); design UI for that.
TextChatService essentials
- Defaults:
CreateDefaultTextChannelscreatesRBXGeneralandRBXSystem;CreateDefaultCommandsadds built-ins (/whisper,/team,/mute, ...). Configure look viaChatWindowConfiguration,ChatInputBarConfiguration,BubbleChatConfiguration(or disable and build your own UI withTextChannel:SendAsyncandTextChatService.MessageReceived). - Flow: client
TextChannel:SendAsync(text)→ serverTextChannel.ShouldDeliverCallback(message, textSource)per recipient → filtering → clients'OnIncomingMessagecallbacks → display. - Callbacks must not yield.
ShouldDeliverCallbackis server-only;TextChatService.OnIncomingMessageandTextChannel.OnIncomingMessageare client-only (formatting). - System messages:
channel:DisplaySystemMessage(text)on the client (local only). - Custom channels (team, party, proximity): create
TextChannels underTextChatServiceon the server,channel:AddUserAsync(userId)to add members; check the returnedTextSource'sCanSend.
--!strict
-- Client: chat tags and colors via OnIncomingMessage (formatting only; never yields).
local Players = game:GetService("Players")
local TextChatService = game:GetService("TextChatService")
TextChatService.OnIncomingMessage = function(message: TextChatMessage)
local properties = Instance.new("TextChatMessageProperties")
local source = message.TextSource
if source then
local player = Players:GetPlayerByUserId(source.UserId)
if player and player:GetAttribute("VIP") then
properties.PrefixText = `<font color="#F5CD30">[VIP]</font> {message.PrefixText}`
end
end
return properties
end--!strict
-- Server: a /spawn command, restricted to admins.
local Players = game:GetService("Players")
local TextChatService = game:GetService("TextChatService")
local ADMINS: { [number]: boolean } = { [123456] = true }
local command = Instance.new("TextChatCommand")
command.Name = "SpawnCommand"
command.PrimaryAlias = "/spawn"
command.Parent = TextChatService
command.Triggered:Connect(function(source: TextSource, unfilteredText: string)
if not ADMINS[source.UserId] then
return
end
local player = Players:GetPlayerByUserId(source.UserId)
print(`{player and player.Name} ran: {unfilteredText}`)
end)Platform-integrated chat (required May 2027)
Roblox is making chat native. Opt in to test now: select TextChatService in Studio and set
PlatformIntegratedChat = Enabled (Studio only, not scriptable). When enabled:
- Roblox renders all chat, in the default window or
TextChannelWindows you place in UI (one perTextChannelviaTarget; works inSurfaceGuis). Custom chat UIs can no longer render messages. - Message text is hidden from code:
TextChatMessage.Text/Translation/PrefixText,OnIncomingMessage,Player.Chatted, andTextChannel:SendAsyncstop working (return""+ warning). No chat logging. - Commands must be
TextChatCommands; preset phrases → Quick Words; chat tags/prefixes → role badges (planned Feb 2027 — don't opt in yet if you rely on prefixes).DisplaySystemMessageandBubbleChatConfiguration/OnBubbleAddedstyling still work. - New code: build on
TextChatCommand,TextChannelWindow, and system messages; avoid reading message text. TheOnIncomingMessagetag example above only works until migration.
More: proximity chat, team channels, custom UI, and migrating from legacy chat: references/chat-recipes.md.
Quick Words (preset safe phrases for all ages, for coordinating where free chat is limited): add game-specific ones in Creator Hub → game → Configure → Chat → Quick Words — up to 3 categories of 3–10 phrases, in English (auto-translated), reviewed before going live. They replace the default categories; General stays.
PolicyService (per-user restrictions)
PolicyService:GetPolicyInfoForPlayerAsync(player) (server, pcall) returns flags such as
ArePaidRandomItemsRestricted, IsPaidItemTradingAllowed, AreAdsAllowed, AllowedExternalLinkReferences,
IsSubjectToChinaPolicies, IsContentSharingAllowed. Gate loot boxes, trading, ads, and links to
social media (only show platforms listed in AllowedExternalLinkReferences) per player.
Related skills
roblox-security (rate limits, validation), roblox-ui (text input UI), roblox-monetization
(paid random items), roblox-data-stores (storing user text).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

