Pepper Chat
Free chat with tabs for All, OOC and Staff – with tools your staff uses right in the chat window.
Free and open source: https://github.com/PepperScripts/pepper_chat
Overview
Pepper Chat replaces the default chat. Your players switch between the tabs All, OOC and Staff, and your staff mutes with a right-click, deletes messages and sends announcements right in the chat window – without typing commands. Spam protection and the word filter check every message on the server, mutes are stored in the database and survive a restart, and everything ends up in the daily log.
Features
- Tabs: All, OOC and Staff (the staff tab is visible to staff only)
- Staff tools right in the chat window, no commands needed:
- Right-click a message: mute the player (10 min, 1 h, 24 h, permanent) or delete the message
- Buttons: announcement to everyone, slow mode, list of muted players, clear chat
- Announcements appear in chat and as a banner at the top of the screen
- Staff badge in front of the name (Admin, Mod), colours and labels set in the config
- Spam protection: cooldown, duplicate check and flood mute; word filter that censors or blocks
- Mutes are stored in the database and survive a restart
- Log to a daily file and, if you want, to a Discord webhook
- Command suggestions while typing, input history (arrow keys), character counter
- Replaces the default chat (
provide 'chat'):chat:addMessage,chat:addSuggestion, templates andexports.chatkeep working - English and German included
Requirements
| Dependency | Required/optional | What for | Link |
|---|---|---|---|
FiveM server (fx_version 'cerulean', Lua 5.4) |
required | Runs the resource | https://docs.fivem.net/docs/server-manual/setting-up-a-server/ |
| oxmysql | required | Table pepper_chat_mutes for mutes |
https://github.com/overextended/oxmysql |
| MySQL/MariaDB database | required | Accessed through oxmysql; the script creates the table itself | – |
| ESX Legacy, QBCore or Qbox | optional | Staff roles from the group (ESX) or permissions (QBCore/Qbox); without a framework via ACE | – |
| OneSync | not needed | – | – |
Installation
- Put the
pepper_chatfolder into yourresourcesfolder. Do not rename the folder – exports and NUI calls depend on the namepepper_chat. - In your
server.cfg, removeensure chat(the default chat) and start Pepper Chat afteroxmysql:ensure oxmysql # ensure chat ← remove ensure pepper_chat - Restart the server. The table
pepper_chat_mutesis created automatically on first start. If you want to create it by hand, importinstall/pepper_chat.sqlinto your database. - Set
Config.Localeand your staff groups (Config.Staff) inconfig.lua.
First test
- In game press T – the chat window with the tabs opens. Type a message and send it with Enter.
- Tab switches the tab (when no suggestions are open),
/ooc Hellowrites to the OOC channel. - As staff: right-click a message – the menu to mute and delete appears, plus the Staff tab and the tool buttons.
- Type
say Testin the server console – the line appears in everyone's chat. - Check that a file
chat-YYYY-MM-DD.logwas created in thelogs/folder.
Configuration
| File | Controls |
|---|---|
config.lua |
Language, key, channels, display, look, banner, staff roles, command names, shown name (sent to players) |
config_server.lua |
Log and webhook, spam protection, word filter (server only, never sent to players) |
locales/de.json, locales/en.json |
All texts in the chat and the UI |
html/style.css |
Look of the chat window |
Basics and display
| Option | Default | Description |
|---|---|---|
Config.Locale |
'en' |
Language 'de' or 'en' |
Config.OpenKey |
't' |
Key to open; players change it under Settings → Key Bindings → FiveM |
Config.Channels |
{ global = true, ooc = true, team = true } |
Channels on/off |
Config.DefaultChannel |
'global' |
Which channel the "All" tab writes to |
Config.ShowIds |
true |
Server ID behind the name |
Config.ShowTime |
true |
Time in front of the message |
Config.MaxLength |
200 |
Max message length |
Config.MaxMessages |
100 |
Messages kept in the history |
Config.FadeAfter |
12 |
Seconds until the chat fades out, 0 = never |
Config.JoinLeaveMessages |
false |
"joined / left the server" in chat |
Look and banner
Config.UI = { left = 1.2, top = 4.0, width = 31, height = 17, scale = 1.0, accent = '#E5484D' }
Config.AnnouncementBanner = { enabled = true, duration = 8 }
| Option | Default | Description |
|---|---|---|
Config.UI.left / top |
1.2 / 4.0 |
Position in percent of the screen |
Config.UI.width / height |
31 / 17 |
Size in text-line units |
Config.UI.scale |
1.0 |
Overall size, 1.0 = normal |
Config.UI.accent |
'#E5484D' |
Accent colour (active tab, buttons) |
Config.AnnouncementBanner |
enabled = true, duration = 8 |
Announcement also as a banner at the top, duration in seconds |
Staff roles
Config.Staff = {
{ key = 'admin', label = 'Admin', color = '#E5484D', groups = { 'superadmin', 'admin', 'god' } },
{ key = 'mod', label = 'Mod', color = '#4C9AFF', groups = { 'mod', 'moderator', 'support' } },
}
The first matching role wins (top = higher). Checked are the ACE permission pepperchat.<key>, the ESX group
(getGroup), QBCore permissions (HasPermission) and ACE groups of the same name (Qbox). label and color form the
badge in front of the name.
| Option | Default | Description |
|---|---|---|
Config.SlowModeSteps |
{ 0, 5, 10, 30, 60 } |
Choices in the staff menu for slow mode (seconds) |
Config.MuteSteps |
{ 10, 60, 1440, 0 } |
Choices in the right-click menu (minutes, 0 = permanent) |
Config.Commands |
see "Commands and permissions" | Command names without the slash |
Config.GetName |
GetPlayerName(source) |
Which name the chat shows – query your framework here for the character name |
Log, spam protection and word filter (config_server.lua)
| Option | Default | Description |
|---|---|---|
ServerConfig.Log.file |
true |
Daily file logs/chat-YYYY-MM-DD.log in the resource folder |
ServerConfig.Log.webhook |
'' |
Discord webhook URL, '' = off (@ mentions are defused) |
ServerConfig.Spam.cooldown |
1000 |
Milliseconds between two messages |
ServerConfig.Spam.duplicateWindow |
10 |
Same message again only after this many seconds |
ServerConfig.Spam.floodCount / floodWindow |
6 / 10 |
This many messages in this many seconds count as flood |
ServerConfig.Spam.floodMute |
60 |
Then muted for this many seconds |
ServerConfig.Filter.mode |
'censor' |
'censor' (asterisks), 'block' (drop the message) or 'off' |
ServerConfig.Filter.words |
empty | List of filtered words (case-insensitive) |
Spam protection and slow mode do not apply to staff, the word filter does not apply to the staff channel.
For developers
-- client
exports.pepper_chat:setVisible(false) -- hide the chat, e.g. for a cutscene
TriggerEvent('chat:addMessage', { color = { 255, 196, 107 }, args = { 'Bank', 'You received $500.' } })
-- server
TriggerClientEvent('chat:addMessage', source, { args = { 'Server', 'Welcome!' } })
exports.pepper_chat:addMessage(-1, { args = { 'Server', 'Restart at 6 pm.' } })
Like with the default chat, other resources on the server can catch the chatMessage event (CancelEvent()) or change
and cancel messages with registerMessageHook. Colour codes ^0–^9 work in messages from scripts; they are removed
from player messages.
Commands and permissions
| Command | Who | What it does |
|---|---|---|
/ooc [text] |
everyone | Message to the OOC channel |
/team [text] |
staff | Message to the staff chat |
/announce [text] |
staff | Announcement to everyone (chat + banner) |
/chatclear |
staff | Clears the chat for everyone |
/chatmute [id] [minutes] [reason] |
staff | Mutes a player, 0 = permanent |
/chatunmute [id] |
staff | Unmutes a player (player must be online) |
/chatslow [seconds] |
staff | Slow mode, 0 = off (at most 600) |
say [text] |
server console only | Line as "Console" in the chat |
All names can be changed in Config.Commands. The staff commands also work from the server console.
Who is staff? The first matching role in Config.Staff:
- ESX: the player's group (
admin,superadmin,mod…) - QBCore / Qbox: the player's permission (
god,admin,mod) - No framework: add to your
server.cfgadd_ace group.admin pepperchat.admin allow add_ace group.moderator pepperchat.mod allow
Keys in the chat window: T open (changeable), Enter send, Esc close, Tab take a suggestion or switch tabs, Arrow up/down input history or suggestions, Page up/down scroll the history, right-click (staff only) menu for message and player.
Exports and events
| Side | Name | Effect |
|---|---|---|
| Client | exports.pepper_chat:setVisible(bool) |
Show/hide the chat |
| Client | exports.pepper_chat:addMessage(msg) / addSuggestion(name, help, params) |
Like the default chat |
| Client | Events chat:addMessage, chatMessage, chat:addSuggestion(s), chat:removeSuggestion, chat:addTemplate, chat:clear |
Compatible with the default chat |
| Server | exports.pepper_chat:addMessage(target, msg) |
Message to one player or -1 = everyone |
| Server | exports.pepper_chat:registerMessageHook(fn) |
Change or cancel player messages before they are sent out |
| Server | Event chatMessage(source, name, text) |
Read along, cancel with CancelEvent() |
FAQ
The chat opens twice or not at all – what now?
Usually the default chat or another chat is still running. Remove ensure chat (and other chat resources) from your
server.cfg. Pepper Chat registers as the replacement via provide 'chat'; only one may run.
Does my other script that depends on chat keep working?
Yes. Through provide 'chat' dependencies on chat are met, and the events chat:addMessage, chat:addSuggestion,
chatMessage and templates (chat:addTemplate) are understood.
Do I need a database?
Yes, for the mutes via oxmysql. The script creates the table pepper_chat_mutes on start; by hand you can use
install/pepper_chat.sql.
I am an admin but do not see the staff tab?
Check that your group (ESX) or permission (QBCore/Qbox) is listed in groups of a role in Config.Staff, or without
a framework set add_ace group.admin pepperchat.admin allow. The role is cached for up to 30 seconds – reconnect after
a change.
How do I show the character name instead of the FiveM name?
Change Config.GetName in config.lua: the function runs on the server and receives the source. Query your
framework there and return the name (at most 40 characters are shown).
How do I change colours and position?
Accent colour, position, size and scale are in Config.UI, the staff badge colours in Config.Staff (color). For
deeper changes edit html/style.css.
How do I change the texts?
All texts are in locales/de.json and locales/en.json. Config.Locale picks the language.
Do mutes survive a restart?
Yes. They are stored in the database, tied to the player's Rockstar license. Expired ones are deleted on start. If a player has no license identifier, the mute only lasts for the current session.
How do I unmute a player who is offline?
Through the staff menu in the chat: the list of muted players shows all active entries, you lift them there.
/chatunmute [id] only works for players who are online.
How do I set up the Discord webhook?
Put the webhook URL into config_server.lua at ServerConfig.Log.webhook. Lines are collected and sent in batches
about every 5 seconds. The file stays on the server and is never sent to players.
Why do player messages arrive without colour?
Colour codes ^0–^9 and control characters are removed from player messages on the server. In messages from your
scripts (chat:addMessage) they still work.
A player types a command that does not exist – does it end up in the chat?
No. Unknown commands are not sent to everyone as a message; the player gets a hint.
How do I update Pepper Chat?
Replace the folder and back up config.lua, config_server.lua and changed language files first. The database stays.
Changes are listed in the CHANGELOG.md in the resource folder.
Support
Questions or bugs? Open a ticket in our Discord: https://discord.gg/6NaFJWKDYu – link your purchase with /verify
first. The source code is on GitHub: https://github.com/PepperScripts/pepper_chat
Permanently tested on the Pepper Scripts dev server.
Changelog
Current version 1.0.0 (first version). All changes are listed in the CHANGELOG.md in the resource folder.
Found a mistake? Report it on Discord.