Filtered Chat Logs

I’m trying to filter the chat because Roblox…is Roblox. But the code I’m using either shows nothing or shows it unfiltered.
Filter:

local HttpService = game:GetService("HttpService")
local WebhookURL = ""
local TextService = game.TextService
local function log(Message)
	local Data = {
		["content"] = Message
	}
	Data = HttpService:JSONEncode(Data)
	local success, errorMessage = pcall(function()
		textObject = TextService:FilterStringAsync(Data)
	end)
	if success then
		HttpService:PostAsync(WebhookURL, textObject)
	end

end

game.Players.PlayerAdded:Connect(function(Player)
	Player.Chatted:Connect(function(Message)
		log("**"..Player.Name.."-"..Player.UserId.."** : "..Message)
	end)
end)

No filter:

local HttpService = game:GetService("HttpService")
local WebhookURL = ""

local function log(Message)
	local Data = {
		["content"] = Message
	}
	Data = HttpService:JSONEncode(Data)
	HttpService:PostAsync(WebhookURL, Data)
end

game.Players.PlayerAdded:Connect(function(Player)
	Player.Chatted:Connect(function(Message)
		log("**"..Player.Name.."-"..Player.UserId.."** : "..Message)
	end)
end)


Try using FilterStringForBroadcast(), learn more here!

1 Like

Yep, that works, also is there a reason why filtering isn’t a thing in studio?

No idea, I’ve also noticed this, it’s just kind of annoying to have to go in-game to test.

Please read documentation, you would get an answer. FilterStringAsync returns a TextFilterResult instance, not a string of your filtered text. There are three methods provided by this object which further configure how the text should be filtered before giving it back: GetChatForUserAsync, GetNonChatStringForBroadcastAsync and GetNonChatStringForUserAsync.

FilterStringForBroadcast as recommended earlier is archaic, as are the other filter methods from the Chat and should ideally not be used for new work. I don’t know the specifics on how they differ but TextService is the option that’s actively maintained for new work, therefore using it also allows you to work with the latest filtering updates.

Additionally, you should be filtering your message before putting it in the data table, not filtering the JSON string. The extra symbols change the filter context and can result in unintended filtering. Filter first, then pass it to a table and JSONEncode it.

What do you mean by “extra symbols”? like the userid and the name?
Edit: also it’s making things unfiltered in chat, filtered in the message, this cuz of the <13 filter?

No. JSONEncode turns your table into a JSON object, so it accordingly adds text to format the object and make it acceptable for external services that parse JSON. If you filter the string returned by JSONEncode instead of the message, the context of your filter changes.

Say for example someone says “foobar” in the chat. If you filter before adding the text to your table, then the filter is only acting on this phrase:

foobar

If you filter after passing the table through JSONEncode, the filter is acting on this phrase:

{"content":"foobar"}

This results in inaccuracies with how your text gets filtered because that extra text is changing the context to which the filter needs to read from. Instead of just the exact message you want filtered, it is also now reading part of the JSON object formatting. By inaccuracies, I mean that the way your text gets read and filtered will differ and in some cases, significantly.

So, what would the script look like, this?

local HttpService = game:GetService("HttpService")
local WebhookURL = ""



game.Players.PlayerAdded:Connect(function(Player)
	Player.Chatted:Connect(function(Message)
		-- Filter the string and store the result in the 'FilteredString' variable
		FilteredString = game:GetService("Chat"):FilterStringForBroadcast(Message, Player)
		log("**"..Player.Name.."-"..Player.UserId.."** : "..FilteredString)
	end)
end)

local function log(FilteredString)
	local Data = {
		["content"] = FilteredString
	}
	Data = HttpService:JSONEncode(Data)
	HttpService:PostAsync(WebhookURL, Data)
end

Your original code was fine, you just need to pass the message in and use a method of the TextFilterResult instead of passing in the string returned from JSONEncode.

-- In Player.Chatted where you call log, add Player.UserId as a second argument
local function log(message, fromPlayerId)
    local filterSuccess, filterResult = pcall(function ()
        return TextService:FilterStringAsync(message, fromPlayerId)
    end)
    if not filterSuccess then error("Could not filter message: " .. filterResult, 2) end

    local chatSuccess, filteredChat = pcall(function ()
        return filterResult:GetNonChatStringForBroadcastAsync()
    end
    if not chatSuccess then error("Could not filter message: " .. filteredChat, 2) end

    -- Might as well skip the step and immediately encode the content table
    local data = HttpService:JSONEncode({
        ["content"] = filteredChat
    })

    -- Are you sure this is how you send webhook messages?
    HttpService:PostAsync(WebhookURL, data)
end

Uhh, nothing is showing up, no messages, no errors.
Edit, im dumb I didnt put the player.chatted

Using that, it’s showing:
########################### : #########
The 1st part would be the name/id, and 2nd is the message, which isn’t tagged in-game

Please read documentation. GetNonChatStringForBroadcastAsync filters at the highest available restriction. If you’d like to use other methods, you’ll have to tweak the code in order to get that down. My post is only intended to show you how to properly use TextService and explain the original issue.

So how is it possible to make it show with 13+ filter? (And I figured out how to make the user not tag.)

Chat filters are based on a user’s age and their privacy settings. There is no blanket toggle between a “13+”/"<13" filter that you can access or use. Again, please read documentation!!! This will help you see how each method can be used and what it’s used for. There is also an article on the Developer Hub for help with how to filter appropriately in your game.

I read it but I can’t find a function for it that is based on their privacy settings, I think I’m missing something.