This Roblox hat remover script was made to automatically delete the “biggest” and “flashiest” hats from players in a game. It targets large and annoying accessories that might cause annoyance or be too attention-grabbing. It works by checking different properties of the accessories, including their size, mesh ID, and texture. It can also filter out hats based on specific blacklisted words, descriptions, and creators.
The script is pretty configurable and you can adjust settings like removing layered clothing, checking asset descriptions, and only allowing hats from verified creators. The default settings and comments within the script pretty much explain everything needed to customise these options.
--!strict
--!optimize 1
-- optimization flag should get rid of debug prints if DebugPrints is set to false
-- If your game allows you to reload your avatar (for example your game has an Avatar Editor), export the Scan function
-- by making this a ModuleScript or put it into shared
-- and run it after reloading
-- Note that the Scan function will reset your HumanoidDescription if you have CheckAssetInfo enabled
-- This means, custom bundles / hats / accessories applied by the game will be gone
-- to fix this, pass your custom HumanoidDescription as second argument in Scan or as third argument in RemoveAccessoriesWithBlacklistedAssetInfo
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local DebugPrints = true
local Settings = {
RemoveLayeredClothing = false,
RemoveGlitchedBundles = { -- Remove bundles that fling you or are very small
Enabled = true,
Action = "Kick", -- "Kick" | "Fix" # Fix will make an attempt to remove the malicious parts
KickMessage = "You have a glitched bundle equipped. Take it off to be able to play this game"
},
CheckMeshIDs = true, -- See BlacklistedMeshes below
CheckTextures = true, -- See BlacklistedTextures below
CheckAccessorySize = true, -- Accessories that are bigger than 5 studs are deleted
CheckAssetInfo = { -- Will check ProductInfo for any matches, if found then the accessory is deleted
Enabled = true,
CheckDescription = true, -- Check description for mentions of blacklisted words? See DescriptionBlackist below
OnlyVerifiedHats = false, -- Will only keep hats made by players with the verified badge
RemoveOffSaleHats = false, -- Will only remove hats that were manually made off-sale, limiteds will still be wearable
WordBlacklist = {
-- Capitalization doesn't matter, it also doesn't have to be the full name
"Flashiest", -- epilepsy inducing accesories
"Biggest", -- large accessories
"/ugcs", -- ugc group where bypassed large hats are uploaded
"Freaky", -- inappropriate slang
} :: {string},
DescriptionBlackist = {
-- Capitalization doesn't matter, it also doesn't have to be the full name
} :: {string},
CreatorBlacklist = {
-- Can be group ids or userids
-- GROUP
34474186, -- makes "skybox" / large hats
16640808, -- makes "Biggest ___" hats
11130075, -- makes epilepsy inducing accessories
-- USER
485466993, -- makes epilepsy inducing accessories
} :: {number}
},
BlacklistedMeshes = {
"rbxassetid://18100307103",
"rbxassetid://17345242336",
"rbxassetid://14282144118",
"rbxassetid://15423734896",
"rbxassetid://17323421898",
"rbxassetid://11502882458",
"rbxassetid://17285248611",
"rbxassetid://17214242215",
"rbxassetid://15423734737",
"rbxassetid://18373548780",
"rbxassetid://18100088851",
},
BlacklistedTextures = {
-- Lot of the "flashiest" and "biggest" hats share the same
-- TextureID, this is a simple way to blacklist 3-4 hats with just one entry
"rbxassetid://17375589753",
"rbxassetid://11499419610",
"rbxassetid://17285296554",
"rbxassetid://15423775085",
"rbxassetid://18352649038",
"rbxassetid://18100098116",
}
}
local ProductInfoCache = {}
local function GetAccessoryMesh(Accessory: Accessory): SpecialMesh | MeshPart | nil
local Handle: BasePart | MeshPart | nil = Accessory:FindFirstChild("Handle") :: any
if not Handle then
return
end
if Handle:IsA("MeshPart") then
return Handle
end
local Mesh = Handle:FindFirstChildOfClass("SpecialMesh")
if Mesh then
return Mesh
end
return nil
end
local function GetTextureID(Mesh: SpecialMesh | MeshPart)
return if Mesh:IsA("SpecialMesh") then Mesh.TextureId else Mesh.TextureID
end
local function WaitForAppearance(Player: Player)
if not Player:HasAppearanceLoaded() then
Player.CharacterAppearanceLoaded:Wait()
end
end
local function RemoveBlacklistedAccessory(Player: Player, Accessory: Accessory)
if DebugPrints then
warn(`{Player.Name} had a blacklisted accessory equipped called {Accessory.Name}`)
end
if not (pcall(Accessory.Destroy, Accessory)) then
WaitForAppearance(Player)
pcall(Player.LoadCharacter, Player)
end
end
local function GetHatInfo(HatID: number)
local ProductInfo
if ProductInfoCache[HatID] then
ProductInfo = ProductInfoCache[HatID]
else
local Success, Response = pcall(MarketplaceService.GetProductInfo, MarketplaceService, HatID, Enum.InfoType.Asset)
if not Success then
warn(`MarketplaceService:GetProductInfo({HatID}, Enum.InfoType.Asset) errored: {Response}`)
return { Creator = 0, ByVerifiedPlayer = false, OffSale = false, Name = "", Description = "" }
end
ProductInfo = Response
ProductInfoCache[HatID] = Response
end
return {
Creator = ProductInfo.Creator.CreatorTargetId,
ByVerifiedPlayer = ProductInfo.Creator.HasVerifiedBadge,
OffSale = not ProductInfo.IsForSale and not ProductInfo.IsLimited and not ProductInfo.IsLimitedUnique,
Name = ProductInfo.Name,
Description = ProductInfo.Description
}
end
local function RemoveAccessoriesWithBlacklistedAssetInfo(Player: Player, Humanoid: Humanoid, CustomHumanoidDescription: HumanoidDescription?)
local HumanoidDescription = CustomHumanoidDescription or Players:GetHumanoidDescriptionFromUserId(Player.UserId)
local AccessoryList = HumanoidDescription:GetAccessories(true)
local NewAccessoryList = {}
type AccessoryEntry = {
AccessoryType: Enum.AccessoryType,
AssetId: number,
IsLayered: boolean,
}
type HatInfo = {
Creator: number,
ByVerifiedPlayer: boolean,
OffSale: boolean,
Name: string,
Description: string
}
for _, AccessoryEntry: AccessoryEntry in AccessoryList do
if AccessoryEntry.IsLayered and Settings.RemoveLayeredClothing then
continue
end
local Info: HatInfo = GetHatInfo(AccessoryEntry.AssetId)
if Settings.CheckAssetInfo.RemoveOffSaleHats and Info.OffSale then
if DebugPrints then
warn(`{Info.Name} is off-sale`)
end
continue
elseif Settings.CheckAssetInfo.OnlyVerifiedHats and not Info.ByVerifiedPlayer then
if DebugPrints then
warn(`{Info.Name} is not made by a verified player`)
end
continue
end
local DontIncludeHat = false; do
for _, BlacklistedWord in Settings.CheckAssetInfo.WordBlacklist do
if string.find(Info.Name:lower(), BlacklistedWord:lower(), nil, true) then
if DebugPrints then
warn(`{Info.Name} contains a blacklisted word in the name: {BlacklistedWord}`)
end
DontIncludeHat = true
break
end
end
if not DontIncludeHat and Settings.CheckAssetInfo.CheckDescription then
for _, BlacklistedWord in Settings.CheckAssetInfo.DescriptionBlackist do
if string.find(Info.Description:lower(), BlacklistedWord:lower(), nil, true) then
if DebugPrints then
warn(`{Info.Name} contains a blacklisted word in the description: {BlacklistedWord}`)
end
DontIncludeHat = true
break
end
end
end
if not DontIncludeHat and table.find(Settings.CheckAssetInfo.CreatorBlacklist, Info.Creator) then
if DebugPrints then
warn(`{Info.Name} is made by a blacklisted user/group: {Info.Creator}`)
end
DontIncludeHat = true
end
end
if DontIncludeHat then
continue
end
table.insert(NewAccessoryList, AccessoryEntry)
end
HumanoidDescription:SetAccessories(NewAccessoryList, true)
Humanoid:ApplyDescription(HumanoidDescription)
end
local function CheckVectors(Descendant: BasePart | Model, Size: Vector3): boolean
local TargetSize: Vector3; do
if Descendant:IsA("Model") then
TargetSize = Descendant:GetExtentsSize()
else
TargetSize = Descendant.Size
end
end
for _, Sizes in {
{ TargetSize.X, Size.X },
{ TargetSize.Y, Size.Y },
{ TargetSize.Z, Size.Z },
} do
if Sizes[1] <= Sizes[2] then
return true
end
end
return false
end
local function CheckAccessoryObjects(Player: Player, Humanoid: Humanoid)
local Accessories = Humanoid:GetAccessories()
if #Accessories > 25 then
return Player:Kick(">25 Hats")
end
for _, Accessory in Accessories do
local Handle = Accessory:FindFirstChild("Handle") :: BasePart
if not Handle then
continue
end
if Settings.CheckAccessorySize then
for _, AxisSize in { Handle.Size.X, Handle.Size.Y, Handle.Size.Z } do
if AxisSize > 5 then
RemoveBlacklistedAccessory(Player, Accessory)
return
end
end
end
local Mesh = GetAccessoryMesh(Accessory); do
if Mesh then
if Settings.CheckMeshIDs and table.find(Settings.BlacklistedMeshes, Mesh.MeshId) then
RemoveBlacklistedAccessory(Player, Accessory)
continue
elseif Settings.CheckTextures and table.find(Settings.BlacklistedTextures, GetTextureID(Mesh)) then
RemoveBlacklistedAccessory(Player, Accessory)
continue
end
end
end
end
end
local function Scan(Character: Model, CustomHumanoidDescription: HumanoidDescription?)
local Player = Players:GetPlayerFromCharacter(Character)
local Humanoid: Humanoid | nil = Character:WaitForChild("Humanoid") :: Humanoid
if not Humanoid then
return
end
if Settings.CheckAssetInfo.Enabled then
RemoveAccessoriesWithBlacklistedAssetInfo(Player, Humanoid, CustomHumanoidDescription)
end
WaitForAppearance(Player)
if Settings.RemoveGlitchedBundles.Enabled then
local Action = Settings.RemoveGlitchedBundles.Action
if CheckVectors(Character, Vector3.new(2, 4, 2)) and Action == "Kick" then
Player:Kick(Settings.RemoveGlitchedBundles.KickMessage)
end
for _, Descendant in ipairs(Character:GetDescendants()) do
if Descendant:IsA("MeshPart") then
if CheckVectors(Descendant, Vector3.new(0.1, 0.1, 0.1)) then
if Action == "Fix" then
Descendant:Destroy() -- Destroying the parts fixes the mass issue
elseif Action == "Kick" then
Player:Kick(Settings.RemoveGlitchedBundles.KickMessage)
break
end
end
if Descendant.Mass > 1e3 and Action == "Kick" then
Player:Kick(Settings.RemoveGlitchedBundles.KickMessage)
end
end
end
end
CheckAccessoryObjects(Player, Humanoid)
end
local function PlayerAdded(Player: Player)
Player.CharacterAdded:Connect(Scan)
if Player.Character then
Scan(Player.Character)
end
end
Players.PlayerAdded:Connect(PlayerAdded)
for _, Player in Players:GetPlayers() do
task.spawn(PlayerAdded, Player)
end