First off, just a general tip. You’re creating the scamWebsitesTable
table every time a new player joins, and that’s not needed 
Secondly, you’re hardcoding when checking if the player chats something, you’re checking if the message is exactly like the 150 first characters, again not needed.
Thirdly, you’re creating a BoolValue and a Folder when you can do it by using tables.
Fourthly, you’re doing string concatenation, in your example, it does no harm, but it’s:
- Ugly
- Bad way / habit
Fifthly, you’re doing this on the client, I think I know what you think, since the bots are just bots, they’re not exploiters. But, this also results in the kick message to be redundant, bots don’t read error messages!
Well, now I’ve talked about the points I feel are the most important ones. Well, what can we do about it? Yes, we can rethink the whole process and this time, do it on the server and write code that looks better!
Okay, now you have to decide if you want to use Bayes’ theorem to find out if a string is very similar to something else, or if you just want to block certain keywords. I will show you both, for your convenience.
Blocking keywords
Blocking keywords
First off, just have the table in a ModuleScript or at the top of the script. For the sake of this tutorial, I’m using a standard table in the script. I also renamed the table to be blockedWords
, because that makes sense, right?
local blockedWords = {
"link1",
"robux"
};
Great, our keyword table. Now, what we would like to do next, is to check if anyone says one of these keywords, and then you can choose an action of your liking.
local Players = game:GetService("Players");
Players.PlayerAdded:Connect( function (newPlayer)
newPlayer.Chatted:Connect( function (newMessage)
-- Go through each blocked keyword and see if it matches the message
for index, word in pairs(blockedKeywords) do
if newMessage:lower():match(word) then
-- // Found keyword, do something!
end
end
end)
end)
Combining the script it pretty much looks like this:
Code
-- // Services
local Players = game:GetService("Players");
-- // Misc. variables
local blockedWords = {
"link1",
"robux"
};
Players.PlayerAdded:Connect( function (newPlayer)
newPlayer.Chatted:Connect( function (newMessage)
-- Go through each blocked keyword and see if it matches the message
for index, word in pairs(blockedKeywords) do
if newMessage:lower():match(word) then
-- // Found keyword, do something!
end
end
end)
end)
Using Bayes' theorem
Library: GitHub - leafo/lapis-bayes: Naive Bayes classifier for use in Lua
You can use Bayes’ to “categorize” strings, the downside with this is that you have to “train” it to do so. It’s not necessarily difficult, but it takes time.
Taking point from the “Blocking keywords” section of this post, after a player has chatted, you can categorize the message.
Example:
.Chatted:Connect( function (newMessage)
local category = bayes.classify_text(newMessage:lower());
-- // Depending on what you trained it to:
--> Spam / Ham
end)
It explains pretty much everything on the GitHub page, but for the “lazy” people, you train it using bayes.train_text
.
Examples:
(Please note this is hardcoding, the best would be to use a table and iterate through it and “feed” it)
bayes.train_text("spam", "i just got tons of robux, visit this site");
bayes.train_text("spam", "free robux, no account needed");
bayes.train_text("spam", "giving away tons of robux, visit this page");
bayes.train_text("ham", "this game is amazing");
bayes.train_text("ham", "this game sucks");
bayes.train_text("ham", "tow do I play this game, i can't find the tutorial");
As far as I understand how this theorem works, is that it goes through each word in the strings you feed it, and sort of maps them and counts how many times it is used. Then once you want it to categorize, it does the same, but just checks and then “weighs” the string.
You might also see that I entered all the strings as lowercase letters, that’s because it is case-sensitive.