Picture a player typing a quick warning to a friend: there's a monster right behind you. They throw in a swear word, because it's urgent. Their friend sees ###########.
That's not my example. It's Roblox's own, from a post its safety team published in March 2026 about why it's moving away from hash marks. And it's the best summary I've seen of what goes wrong when a game filters chat badly: the rule gets enforced, and the conversation dies. (Drafted with AI, sources checked by hand.)
If you've played or built a game with chat, you've probably run into these. What does ### mean in Roblox? Why can't I say Discord? Why did Kahoot rename me? So I went through what Roblox and Kahoot actually say their filters do, case by case, and what each one teaches you if you're building chat for your own game.
What ### means
Roblox's help center answers it in one line: when you see hashtags in place of words, the word or phrase "was blocked by our filters."
The filter isn't one list. In the March post, Roblox describes three parts:
- Rules, which can block new terms within minutes when something happens in the real world.
- Small specialized models, trained to catch the words Roblox doesn't allow. Roblox says these are good at that task but "can't reason very well," so they miss language that changes fast.
- Large models, added this year. When the small ones aren't sure, the text goes to a bigger model that can weigh more context.
Roblox says the combination catches more leetspeak (letters swapped for numbers or symbols) and cut missed attempts to share personal information, like phone numbers and social handles, by 20 times.

Screenshot: Roblox's Experience Chat help article
Where it goes wrong, case by case
1. The whole line disappears
The monster example is the problem in one picture. The filter found something it didn't allow, and the reader lost the entire message, including the part that mattered for the game.
Roblox's fix, since March, is to rephrase instead of hash, starting with profanity. Its example: "Hurry tf up!" becomes "Hurry up!" Everyone in the chat is told the message was rephrased, and the swearing still counts against the sender. More serious messages still go through the rest of its safety system.

Roblox's monster example as it hid it, then masked and rephrased by me
You don't need a language model to do better than hiding the whole line. Masking only the words that broke a rule keeps the warning readable. Rephrasing is nicer, but it's a bigger build, and Roblox itself says it "won't always rephrase things perfectly."
2. Nobody says why
A row of hash marks doesn't tell the sender which word was the problem, or whether they're in trouble. Roblox's answer was real-time warnings, added in May 2025, that tell players when they've broken a rule. In its experiments, warnings and time-outs cut filtered messages by 5% and consequences from abuse reports by 6%.
That's the cheapest fix on this list. If your filter blocks something, tell the sender what kind of thing it was.
3. "Discord" isn't a swear word
This one confuses players the most. Roblox's filter isn't only about language. Its Community Standards say you may not share links to outside sites except through the Social Links feature on a game, group or profile page, which needs an age check and an age of at least 16. Any other effort "to direct users off of Roblox" is prohibited. Its safety page says filtered chat blocks personal information "and instructions on how to move off the platform."
So "add me on Discord" isn't blocked because Discord is rude. It's blocked because it's directions off the platform, which the rules forbid.
The lesson for your game: decide what you're filtering for, and write it down. Swearing, slurs, threats, personal information and off-platform contact are different rules, and players accept them better when they can tell them apart.
4. The list catches innocent words
Kahoot's nickname filter is a classic word list. Kahoot keeps a list of words it deems universally inappropriate, checks every nickname against it, and changes a match to something neutral. Its help page even warns teachers that a group of players joining with names like "router" may be the filter at work.
To its credit, Kahoot gives teachers a way back: they can ask support to allow a wrongly filtered nickname, or add a missed one to the deny list. It also offers a nickname generator in Classic mode, where players spin for a friendly two-word name like "kind tiger" instead of typing one.
That's the honest trade-off. A list will always block some innocent names, so you need a path to fix it, and for young players, picking from safe names beats filtering typed ones.
5. Everyone gets the same filter
A ten-year-old and an adult shouldn't see the same chat. Roblox's safety page says players 12 and younger also have personal information filtered out, and that in restricted games marked for strong language, users 18 and older may be allowed to swear, as long as it isn't used to harass, threaten or discriminate.
If your players span ages, make the strictness a setting, per server or per player.
6. Banter isn't abuse
This is the hardest one. In a game, "nice try loser" is usually a taunt, and "I know where you live" never is. A word list can't tell them apart, because the difference isn't in the words. It's in whether the line is about the game or about a person.
Full disclosure, I build Unprofane, and this is the problem its gaming context was made for: in its docs, gg ez, uninstall and nice try loser are allowed there, while kys noob and I know where you live are blocked.
If you're building on Roblox
Roblox filters its own chat for you, but not everything else. Its creator docs say you're responsible for filtering any text you display that you don't control, like signs players write on, pet names saved in data stores, words your game generates at random, or content fetched from an outside server. If Roblox finds a game that doesn't filter, it removes the game until you add filtering.
The call is TextService:FilterStringAsync, run on the server with the text and the UserId of whoever wrote it:
local TextService = game:GetService("TextService")
local function filterForEveryone(text, fromUserId)
local ok, result = pcall(function()
return TextService:FilterStringAsync(text, fromUserId)
end)
if not ok then
return nil -- show nothing when the filter fails
end
local ok2, filtered = pcall(function()
return result:GetNonChatStringForBroadcastAsync()
end)
return ok2 and filtered or nil
end
Use GetNonChatStringForBroadcastAsync for text everyone sees and GetNonChatStringForUserAsync for text shown to one player, which filters for that player's age. And the docs ask you not to filter on every keystroke: filter once the player submits.
If you're building your own
Here's the short version of everything above:
- Mask the word, not the line. Keep the rest of the message readable.
- Tell the sender why. A category is enough: swearing, personal info, a link.
- Keep the rules separate. Language, threats and off-platform contact are different checks with different answers.
- Give players a way back. A report button for wrong blocks, and an allow list you actually update.
- Set strictness by age. Stricter for kids, looser for adults in adult spaces.
- Decide what happens when the check fails. Show nothing, like Roblox's sample does, or hold the message for a moment. Don't let a timeout quietly turn the filter off.
- Offer safe choices for the youngest players. Kahoot's nickname generator is a good model.
None of this needs a big team. Most of it is a decision you write down before launch instead of after the first angry thread.
Have fun building, and may your players never see ########### again :)
I work on Unprofane, a profanity and abuse filter for user text, including game chat.
Top comments (0)