FilterStringAsync
This is a yielding function. When called, it will pause the Lua thread that called the function until a result is ready to be returned, without interrupting other scripts.
The FilterStringAsync function filters a string being received from a user, using the TextService
, and returns a TextFilterResult
which can be used to distribute the correctly filtered text accordingly.
Usage
This method should be called once each time a user submits a message. Do not cache the results of this function and re-use them for separate messages. If a user submits the same text multiple times this method must be called again each time the message is sent. If the results are cached and reused spam detection and many forms of context-aware filtering will be broken and potentially put user safety at risk. Games that improperly use cached results may face moderation.
However, it is encouraged to keep these result objects to display the same message to users who join the server later. For example: this can be used to safely and efficiently implement a server chat log that always uses the least restrictive filtering for users who join later, or for efficiently displaying text like a pet name to a user who joins the game after the pet was first spawned and name filtered.
The optional Enum/TextFilterContext
parameter will not impact the filtered result of the query. This value will be used to improve Roblox’s text filtering.
Private text is anything that is seen only by specific players, rather than every player. For example, if the chat is seen by a single player, or by a selected group of players, then the chat is considered private. Chat for teams or chat that is potentially visible to a wider group, such as the server, is considered public. If you are unsure what your text qualifies as, leave the optional field blank.
Notes
- This method always yields to make a text filtering service call
- This method may throw if there is a service error that can not be resolved. If this function throws an error please do not retry the request; this method implements it’s own retry logic internally. If this method fails do not display the text to any user.
- This method currently throws if fromUserId is not online on the current server. We plan to support users who are offline or on a different server in the future.
Parameters
Name | Type | Default | Description |
---|---|---|---|
|
The text to be filtered. |
||
|
The userId of the player filtering the text. |
||
PrivateChat
|
The context that the filtered message will be used in. The default is PrivateChat. |
Returns
Return Type | Summary |
---|---|
Can be used to distribute the correctly filtered text accordingly. |
Code Samples
Pet Name Filter Example
This code sample includes a simple demonstration of how TextService/FilterStringAsync
should be implemented in a system where players are allowed to name their pets.
Note, this code sample includes the server-side implementation only (to be placed in a Script
). Examples of how to implement the client-side of this system are included under the RemoteEvent
and RemoteFunction
examples.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TextService = game:GetService("TextService")
local Players = game:GetService("Players")
-- Define remotes for communication with client
local Remotes = Instance.new("Folder", ReplicatedStorage)
Remotes.Name = "PetNamingRemotes"
local UserNamedPet = Instance.new("RemoteEvent", Remotes)
UserNamedPet.Name = "UserNamedPet"
--[[
RemoteEvent UserNamedPet
Paramaters: petName (string)
To be fired by the client when the user has picked a name for their pet.
Example:
local userNamedPet = ReplicatedStorage:WaitForChild("PetNamingRemotes"):WaitForChild("UserNamedPet")
userNamedPet:FireServer("Max")
]]
local SendPetName = Instance.new("RemoteEvent", Remotes)
SendPetName.Name = "SendPetName"
--[[
RemoteEvent SendPetName
Paramaters: userId (int), petName (string)
Fired by the server when a user changes their pet's name
Example:
local sendPetName = ReplicatedStorage:WaitForChild("PetNamingRemotes"):WaitForChild("SendPetName")
sendPetName.OnClientEvent:Connect(function(userId, petName)
local player = Players:GetPlayerByUserId(userId)
if player then
print(player.Name.." has named their pet ".. petName)
end
end)
]]
local RequestAllPetNames = Instance.new("RemoteFunction", Remotes)
RequestAllPetNames.Name = "RequestAllPetNames"
--[[
RemoteEvent SendPetName
Paramaters: n/a
Fetches the names of every player's pet. To be invoked by the client when a user joins the game.
Example:
local requestAllPetNames = ReplicatedStorage:WaitForChild("PetNamingRemotes"):WaitForChild("RequestAllPetNames")
local petNames = requestAllPetNames:InvokeServer()
for userId, petName in pairs(petNames or {}) do
local player = Players:GetPlayerByUserId(userId)
if player then
print(player.Name.." has a pet named ".. petName)
end
end
]]
local filterResults = {}
local function broadcastPetName(userId)
local filterResult = filterResults[userId]
if filterResult then
for _, player in pairs(Players:GetPlayers()) do
if player then
-- spawn a new thread so as to not yield the update
spawn(function()
-- grab the filtered string for this user
local toUserId = player.UserId
local filteredString = filterResult:GetNonChatStringForUserAsync(toUserId)
filteredString = filteredString or ""
-- send the remote event
SendPetName:FireClient(player, userId, filteredString)
end)
end
end
end
end
UserNamedPet.OnServerEvent:Connect(function(player, petName)
local fromUserId = player.UserId
-- pcall to catch errors
local success, result = pcall(function()
return TextService:FilterStringAsync(
petName,
fromUserId
)
end)
if success then
filterResults[fromUserId] = result
broadcastPetName(fromUserId)
else
print("Could not filter pet name")
end
end)
RequestAllPetNames.OnServerInvoke = (function(player)
local toUserId = player.UserId
local petNames = {}
-- go through filter results and filter the pet name to be sent
for fromUserId, filterResult in pairs(filterResults) do
local filteredString = filterResult:GetNonChatStringForUserAsync(toUserId)
filteredString = filteredString or ""
-- need to convert userId to string so it can't be sent via a remote function
petNames[tostring(fromUserId)] = filteredString
end
return petNames
end)
-- Listen for players being removed, and clean up old filter results
Players.PlayerRemoving:Connect(function(oldPlayer)
local userId = oldPlayer.UserId
filterResults[userId] = nil
end)