How to Create a Custom Chat Tag

Hey everyone! In this tutorial, I will show you how to create a Custom Chat Tag. What I mean by this is, a player will have a custom chat tag whenever they type! There is a screenshot of what this tutorial will be covering or you could say what you will be making! image

Step 1 : Open a new baseplate or a existing game. (Am considering you know how to do this)

Step 2 : Open your properties and explorer tabs.

This can be done by going to the view window, and clicking on explorer and properties.
image

Step 3 : Insert a script into ServerScriptService.
This can be done easily by clicking on the + when you hover/click on the ServerScriptService option or by doing CTRL+I (Insert)
image

Step 4 : The script will probably open itself unless if you closed it, but now just type the code down below. The script that is provided is fully editable, you can change the tag to anything you wish and this can be done to multiple users.

local chatService = require(game.ServerScriptService:WaitForChild("ChatServiceRunner"):WaitForChild("ChatService"))

local tags = {
	[0] = {TagText = "TUTORIAL", TagColor = Color3.fromRGB(255, 0, 0)}, -- The 0 must be changed to the the id of the user you want the tag to have
}

chatService.SpeakerAdded:Connect(function(playerName)
	local speaker = chatService:GetSpeaker(playerName)
	local player = game.Players[playerName]
	
	if tags[player.UserId] then
		speaker:SetExtraData("Tags",{tags[player.UserId]})
	end
end)

-- On line 5, change the numbers after fromRGB( to any colour you desire for the tag to be.
-- Again on line 5, change the text that is in "" which it is displayed as TUTORIAL right now, just change that to what you want the tag name to be that will be displayed in the chat.
-- Made by xontez! No credit needed.

Now just test the game, it should work! Did this help you? Let me know! :smiley: What tutorial should I do next?

Was this tutorial useful?

  • Yes
  • No
  • For Future Use

0 voters

159 Likes

Thank you so much! I was actually looking how to do this.

12 Likes

No problem! If you have any future requests for tutorials, let me know! Have a great day. :smiley:

7 Likes

was useful, but there are tons of open sourced chat tag scripts that allow for different customization options, thanks for the post though.

2 Likes

Useful
But there are tutorials on youtube how to do that.

2 Likes

Hey there, cool tutorial!

There’s some feedback I would like to provide about this tutorial to better the experience of using the Lua Chat System to accomplish chat tags, primarily in the realm of API usage. I would encourage you to take a look at some of the docs, since they do have some very useful functions that you can use to your advantage. You can also avoid being dependent on things you don’t need.


GetService

Please use GetService to remain consistent in how you get services. As some services can be renamed, do not have proper names (e.g. RunService has a space in it) or cannot be accessed through direct indexing, GetService is your friend for remaining consistent in how you fetch services.

WaitForChild use

ChatService does not need a WaitForChild chained off of ChatServiceRunner. When ChatServiceRunner is available, ChatService will also be. I don’t know where the guarantee lies here or if there is one, but I believe it comes from Clone. You can directly access ChatService when its parent is available, like so:

local ServerScriptService = game:GetService("ServerScriptService")
local ChatService = require(ServerScriptService:WaitForChild("ChatServiceRunner").ChatService)

Contain your function in a variable

ChatSpeakers can represent both players and non-player entities. You can also have unexpected cases in which you need to account for existing speakers, but cannot due to the way the code is set up. For any added event, there will typically always be a get event, so contrast that where possible.

-- speakerAdded fires with the name of the speaker, not players
local function speakerAdded(speakerName)
    doCodeOnSpeaker()
end

ChatService.SpeakerAdded:Connect(speakerAdded)
for _, speaker in ipairs(ChatService:GetSpeakerList()) do
    speakerAdded(speaker)
end

Use the API available to you

ChatSpeaker objects contain a GetPlayer method to fetch an associated player object. You need this, because your code currently assumes that all new speakers are players. If you do not account for the case of a non-player speaker, your code will error. You should almost never have to use the Players service when working with the ChatService.

local speaker = ChatService:GetSpeaker(speakerName)
local player = speaker:GetPlayer()

if player and TAGS[player.UserId] then
    -- SetExtraData
end

Putting the feedback all together

With this feedback in mind, you can have a renewed code sample that allows you to set chat tags for players without any added bulk and you can also account for overlooked cases, such as the aforementioned non-player speaker case. Putting it all together, you can have a code sample that looks a bit like the following:

--- Allow a player to occupy a single chat tag
-- @author colbert2677

local ServerScriptService = game:GetService("ServerScriptService")
local ChatService = require(ServerScriptService:WaitForChild("ChatServiceRunner").ChatService)

local TAGS = {
    [0] = {TagText = "TUTORIAL", TagColor = Color3.new(1, 0, 0)},
}

--- Call on chat speakers to apply their tags
-- For player speakers only
local function speakerAdded(speakerName)
    local speaker = ChatService:GetSpeaker(speakerName)
    local player = speaker:GetPlayer()

    -- Safe, as if statement fails if first condition is falsy
    if player and TAGS[player.UserId] then
        -- Wrap tag in table, as Tags expects a table value worth of tags
        speaker:SetExtraData("Tags", {TAGS[player.UserId]})
    end
end

ChatService.SpeakerAdded:Connect(speakerAdded)
for _, speaker in ipairs(ChatService:GetSpeakerList()) do
    speakerAdded(speaker)
end

If you wanted to add multiple tags, you could change the structure of the dictionary but you would also have to reflect that in the SetExtraData call so that it isn’t creating a table for something that has already been wrapped in a table.


I hope this feedback will prove useful towards improving the way you work with the chat system. :slight_smile:

59 Likes

Thank you so much for the reply! This will really help me out in future development. Again, thank you.

2 Likes

Slightly change code to fix it

local ServerScriptService = game:GetService("ServerScriptService")

local ChatService = require(ServerScriptService:WaitForChild("ChatServiceRunner").ChatService)

local tags = {

[0] = {TagText = "TUTORIAL", TagColor = Color3.new(1, 0, 0)},

}

--- Call on chat speakers to apply their tags

-- For player speakers only

local function speakerAdded(speakerName)

local speaker = ChatService:GetSpeaker(speakerName)

local player = speaker:GetPlayer()

-- Safe, as if statement fails if first condition is falsy

if player and tags[player.UserId] then

-- Wrap tag in table, as Tags expects a table value worth of tags

speaker:SetExtraData("Tags", {tags[player.UserId]})

end

end

ChatService.SpeakerAdded:Connect(speakerAdded)

for _, speaker in ipairs(ChatService:GetSpeakerList()) do

speakerAdded(speaker)

end
1 Like

Huh, did I break it somewhere? What changes did you make to the code?

2 Likes
local TAGS 

was changed to

local tags

not much

Oops, didn’t catch that, thank you! I’ve been playing around with my naming conventions this year and I didn’t notice that I used the wrong case when looking for the player’s tags.

I will update the original code sample to match.

1 Like

I don’t think this is even a tutorial. You’re just telling everyone to copy and paste without explaining what each code line does.

2 Likes

What other data can you set using speaker:SetExtraData?

Is there a way to find this out?

Hey since you were looking for something like this.
You probably might be looking for a chat icon as well. In that case check out this post. How to Add Custom Player Icons to Chat You can use both this post and his post in the same game.

There is no documentation for this because extra data is freeform. You can use extra data in any way you want to extend the Lua Chat System, like making your own modules (command or filter functions) that rely on certain extra data keys to modify how a chat will get processed. Name and chat colours are implemented this same way, just that they come with the default modules.

There are only three natively supported keys, as in if you didn’t fork or make any changes to the Lua Chat System then these keys will be set by the default modules injected at run time. Those keys are NameColor, ChatColor and Tags (a blank mutable table).

It’s worth noting that these extra data keys are set on a speaker-level as well; you can set it on a message-level if you’d like (as in, you could make a player’s chat appear as a different colour under a specific condition without making every chat they send that separate colouring).

2 Likes

Be careful as this could freeze the entire thread.
I rebuilt the system on a separate thread (useful in case you want use it and other things in a single script).

local function SetTag(Speaker, Player, Tag, Color)
	if Speaker then
		Speaker:SetExtraData("Tags", {{TagText = Tag, TagColor = Color}})
	end
end

spawn(function() -- Initialize ChatService in another thread because yielding
	local ChatService = require(game:GetService("ServerScriptService"):WaitForChild("ChatServiceRunner"):WaitForChild("ChatService"))
	ChatService.SpeakerAdded:Connect(function(PlayerName)
		local Player = game:GetService("Players")[PlayerName]
		local Speaker = ChatService:GetSpeaker(PlayerName)
		if Player and Speaker then
			SetTag(Speaker, Player, "Admin", Color3.new(1, 0, 0))
		end
	end)
end)
5 Likes

I really like this but do you know how to make it rainbow using uiGradients where the gradients moves and not just change color

Really nice tutorial! I just have question

How do I make it an image?

1 Like

You don’t. you can only have text and emojis in it.

How would you go about doing it per-message? Obviously I can’t find any information on it haha