Configuration Reference
Complete configuration options for Oxide Chat.
Complete configuration options for oxide-chat.
How Settings Are Stored
Read this first — it changes how you edit the settings below. Most of Oxide Chat's settings live in your database, not in the config file.
There is a shared table named oxide_settings (created automatically the first time the resource starts) that holds one row per setting. Here is what that means in practice:
- The very first time the resource starts, everything currently in
config/main.luais copied into the database. From that point on, the database is in charge — it "wins" over the file. - After that first start, editing
config/main.luano longer changes a live server for settings that are already in the database. The file only supplies factory defaults: they are used for a brand-new install, and for any new settings added by a future update that the database hasn't seen yet. - To change settings on a running server, use the in-game panel. An admin types
/chat settingsto open it and edits everything live — no file editing, no restart. See the Admin Guide for the full walkthrough. - Every setting has a "reset to default" button in that panel. Resetting a field restores the value from
config/main.lua(the factory default). - To force a config-file value back onto an existing server, either use the per-field reset button in
/chat settings(easiest), or delete that setting's row from theoxide_settingstable in your database manager — on the next start, the resource re-imports the value fromconfig/main.lua.
Two things stay file-only and are not moved into the database: the command definitions in config/commands.lua and the suggestion blacklist in config/blacklist.lua. Edit those in the file as normal and restart the resource.
Setting up the table by hand (optional): the table is created for you automatically, but if you prefer, you can import sql/install.sql (or sql/migrations/0002_settings.sql) into your database. It is safe to import more than once.
Configuration Files
Configuration is split across multiple files in the config/ folder:
| File | Purpose |
|---|---|
main.lua | Core settings, proximity, chat types (factory defaults — see How Settings Are Stored) |
commands.lua | Command definitions with formatting (file-only) |
blacklist.lua | Commands to hide from suggestions (file-only) |
General Settings
Config.MaxMessages
Maximum messages kept in chat history.
Config.MaxMessages = 100Config.MaxMessageLength
Maximum characters per message.
Config.MaxMessageLength = 256Config.MessageFadeTime
Time in milliseconds before messages fade. Set to 0 to disable fading.
Config.MessageFadeTime = 10000 -- 10 secondsKeybinds
Config.OpenKey
The default key that opens chat input.
Config.OpenKey = 'T'Changing this only affects new players who have never rebound the key, and only after a resource restart. FiveM remembers each player's own keybind, so anyone who already changed their "Open Chat" key keeps their own choice. Players can rebind it any time in FiveM Settings under "Key Bindings".
Proximity Settings
Config.ProximityDistance
Distance in meters for each proximity chat type.
Config.ProximityDistance = {
me = 15.0, -- /me action range
['do'] = 15.0, -- /do description range
whisper = 3.0, -- /whisper range (very close)
shout = 50.0, -- /shout range (long distance)
local_ooc = 20.0, -- /looc range
}Choosing Ranges
| Range | Use Case |
|---|---|
| 3-5m | Intimate/whisper |
| 10-20m | Normal conversation |
| 30-50m | Shouting/yelling |
| 50m+ | Very loud events |
Line of Sight Settings
Config.RequireLOS
Whether each chat type requires line of sight.
Config.RequireLOS = {
me = true, -- /me requires seeing the player
['do'] = true, -- /do requires seeing the player
whisper = false, -- Whisper works through walls
shout = false, -- Shout works through walls
local_ooc = false, -- LOOC works through walls
}How LOS Works
- Uses raycasting from eye level to eye level
- Players in the same vehicle are always visible
- Client-side check for immersion (server handles security via distance)
Chat Types
Config.ChatChannels is a single list of every chat type on your server. There are two kinds of rows in it, and they live together in the one list.
Like all the settings above, this list is database-backed. The rows in config/main.lua are only the factory defaults used on a brand-new server; after the first start, the oxide_settings database wins and you edit the list live in the admin panel — /chat settings → Messaging → Chat Types — with no restart. See the Admin Guide for the full field-by-field walkthrough.
Built-in rows
The first rows in the list are the message kinds that are built into the resource — regular chat, system messages, announcements, OOC, /me, /do, whispers, shouts, and private messages. Each carries builtin = true. You can restyle these (change their label, prefix, color, and italics), but you cannot rename or remove them and you cannot change how they behave — their behavior (the /me and /do formatting, OOC, PMs, announcements, system messages) is part of the resource's code. In the admin panel they show only the four styling fields and can't be deleted.
| Built-in row | What it styles |
|---|---|
default | Regular chat messages |
system | System messages |
announcement | Server announcements (/chat announce and auto-broadcasts) |
ooc | Global out-of-character (/ooc) |
me | /me roleplay actions |
do | /do descriptions |
whisper | /whisper |
shout | /shout |
pm | Private messages (/msg, /reply) |
Custom rows
Every other row is a complete custom channel — a slash command with its own styling, scope, and access rules. Job radios, staff chat, business radios, and event channels are all custom rows. The three job radios (/lspd, /medic, /mechanic) ship as ready-made custom rows you can edit or delete.
A custom row can't reuse a built-in chat type ID (like me, do, ooc, or pm) — those belong to the built-in rows.
Config.ChatChannels = {
-- Built-in message styling (builtin = true) — restyle only, can't be removed.
{ builtin = true, id = 'default', label = 'Default Messages',
color = '#F4F5F7' },
{ builtin = true, id = 'system', label = 'System Messages',
prefix = 'SYSTEM', color = '#5F6670' },
{ builtin = true, id = 'announcement', label = 'Announcements',
prefix = 'ANNOUNCEMENT', color = '#9B2C2C' },
{ builtin = true, id = 'ooc', label = 'OOC',
prefix = 'OOC', color = '#C47A2C' },
{ builtin = true, id = 'me', label = '/me Actions',
color = '#F4F5F7', italic = true },
{ builtin = true, id = 'do', label = '/do Descriptions',
color = '#5F6670', italic = true },
{ builtin = true, id = 'whisper', label = 'Whispers',
prefix = 'WHISPER', color = '#C47A2C' },
{ builtin = true, id = 'shout', label = 'Shouts',
prefix = 'SHOUT', color = '#9B2C2C' },
-- PM content already reads "[PM from ...]", so no chip prefix
{ builtin = true, id = 'pm', label = 'Private Messages',
color = '#a78bfa' },
-- Custom channels (job radios, staff chat, ...) — full slash commands.
{
command = 'lspd', aliases = { 'pd', 'leo' },
id = 'police', label = 'LSPD Radio',
prefix = 'LSPD', color = '#3b82f6', italic = false,
scope = 'members', restrict = 'job', jobs = { 'police' },
minRank = 0, dutyOnly = false, cooldown = 0,
range = 15.0, requireLOS = false,
},
{
command = 'medic', aliases = { 'ambulance' },
id = 'ambulance', label = 'EMS Radio',
prefix = 'EMS', color = '#ef4444', italic = false,
scope = 'members', restrict = 'job', jobs = { 'ambulance' },
minRank = 0, dutyOnly = false, cooldown = 0,
range = 15.0, requireLOS = false,
},
{
command = 'mechanic', aliases = { 'mech' },
id = 'mechanic', label = 'Mechanic Radio',
prefix = 'MECHANIC', color = '#f97316', italic = false,
scope = 'members', restrict = 'job', jobs = { 'mechanic' },
minRank = 0, dutyOnly = false, cooldown = 0,
range = 15.0, requireLOS = false,
},
}Built-in row fields
Built-in rows expose only these four styling fields:
| Field | Type | Description |
|---|---|---|
label | string | Friendly name shown in the admin panel and the player Colors tab. |
prefix | string | Short tag shown before each message, e.g. SYSTEM. Optional. |
color | string | Message hex color, e.g. '#F4F5F7'. |
italic | boolean | Whether messages are italicized. |
Custom row fields
Custom rows have every field a full channel needs:
| Field | Type | Description |
|---|---|---|
command | string | The slash command (letters and numbers only), without the slash. lspd becomes /lspd. Must be unique and can't match a built-in command. |
aliases | table | Extra command names for the same channel, e.g. { 'pd', 'leo' }. |
label | string | Friendly name shown in command suggestions and the player Colors tab. |
id | string | The chat type the messages count as (drives color and category tabs). Blank = use the command name. Cannot be a built-in chat type ID. |
prefix | string | Short tag shown before each message, e.g. LSPD. |
color | string | Message hex color, e.g. '#3b82f6'. |
italic | boolean | Whether messages are italicized. |
scope | string | Who sends and sees: 'members' (only qualifying players send and see — a radio), 'global' (everyone sends and sees), 'broadcast' (only qualifying players send, everyone sees), 'proximity' (nearby players see). |
range | number | Range in metres, used only by the proximity scope. |
requireLOS | boolean | Require line of sight, used only by the proximity scope. |
restrict | string | Who may use it: 'none', 'job', or 'admin'. |
jobs | table | Job names allowed, when restrict = 'job'. |
minRank | number | Minimum job grade (rank). 0 = any grade. |
dutyOnly | boolean | Require the player to be on duty. Leave false on ESX (no built-in duty). |
cooldown | number | Milliseconds between messages per player. 0 = no cooldown. |
The restriction is always enforced on the server, so players can't bypass it. Job-restricted channels show messages as Name (Grade): message; all others show Name: message.
Chat Categories (Tabs)
Chat categories group your chat types into switchable tabs shown above the message list (for example an "All" tab, a "Local" tab, a "Job" tab). They are purely visual — a tab simply filters which messages are shown; it never changes who receives a message.
Config.CategoriesEnabled
Turn the tab bar on or off. When false, all messages appear in a single unfiltered list.
Config.CategoriesEnabled = trueConfig.Categories
The list of tabs, in the order they appear. Each entry has:
| Field | Type | Description |
|---|---|---|
id | string | Internal identifier for the tab |
label | string | The text shown on the tab |
types | table | A list of the chat type names this tab shows. A single entry of '*' (as in { '*' }) matches every type — that is the "All" tab |
Config.Categories = {
{ id = 'all', label = 'All', types = { '*' } },
{ id = 'local', label = 'Local', types = { 'me', 'do', 'whisper', 'shout' } },
{ id = 'global', label = 'Global', types = { 'default', 'ooc', 'announcement', 'system' } },
{ id = 'job', label = 'Job', types = { 'police', 'ambulance', 'mechanic' } },
{ id = 'pms', label = 'PMs', types = { 'pm' } },
}A chat type that isn't listed in any specific tab is still reachable under the "All" tab. You can add, remove, or reorder tabs freely.
Automatic Announcements
Automatic announcements broadcast a rotating list of messages to everyone on the server on a timer — handy for server rules, Discord links, or event reminders. Broadcasts are skipped while the server is empty, and admins can toggle them on or off at runtime with /chat autobroadcast on|off (see Commands).
Config.AutoBroadcastEnabled
Whether automatic announcements run when the server starts.
Config.AutoBroadcastEnabled = trueConfig.AutoBroadcastInterval
Seconds to wait between each announcement. The minimum is 30 seconds; any lower value is treated as 30.
Config.AutoBroadcastInterval = 600 -- 10 minutesConfig.AutoBroadcastOrder
The order announcements are shown in.
| Value | Behavior |
|---|---|
sequential | Cycles through the list in order |
random | Picks a random entry each time |
Config.AutoBroadcastOrder = 'sequential'Config.AutoBroadcasts
The list of messages to broadcast. Each entry has an optional title (a heading) and a required message (the body text).
Config.AutoBroadcasts = {
{ title = 'Server Rules', message = 'No RDM or VDM. Read the rules before playing.' },
{ title = 'Join our Discord', message = 'Connect with the community at discord.gg/yourserver' },
}Cooldowns
Config.Cooldowns
Rate limiting in milliseconds.
Config.Cooldowns = {
ooc = 5000, -- 5 seconds between OOC messages
announcement = 30000, -- 30 seconds between announcements
chat = 1000, -- 1 second between regular messages
pm = 1000, -- 1 second between private messages
proximity = 1500, -- 1.5 seconds between /me, /do, etc.
}Cooldown Behavior
- Cooldowns are enforced server-side
- Players receive notification with remaining time
- Console commands bypass cooldowns
Images & GIFs
Players can share pictures and GIFs directly in chat. There are two ways an image gets in:
- Pasting a link. A player pastes a direct image link (one ending in
.png,.jpg,.jpeg,.gifor.webp) into any message. If the link comes from an allowed website, the picture shows inline instead of the raw link. This works in every kind of message — normal chat, private messages, OOC, the RP commands and custom channels. - The GIF button. A GIF search button appears next to the emoji picker. Players search Giphy, click a GIF, and it posts to chat. The button only appears once you set up a Giphy API key (see Giphy API key below).
All of the settings in this section can also be changed live from the in-game panel (/chat settings → Images & GIFs).
Config.ImagesEnabled
The master switch. Turn it off and pasted image links stay as plain text and the GIF button disappears for everyone.
Config.ImagesEnabled = trueConfig.ImageHosts
The websites images are allowed to come from. A link from any other site stays plain text. An entry also covers its subdomains — giphy.com covers media0.giphy.com, i.giphy.com and so on.
Config.ImageHosts = { 'giphy.com', 'cdn.discordapp.com', 'media.discordapp.net' }Keep this list short and stick to well-known image hosts. Any site on the list can show pictures to your whole server.
Why isn't imgur on the list? imgur blocks requests coming from the FiveM game client, so imgur links can never actually display in-game — adding i.imgur.com would just show the link as text. Use Discord (upload the image to any Discord channel and copy its link) or Giphy instead. If a link from an allowed site still fails to load, it falls back to plain text rather than showing a broken image.
Config.ImageRestrict
Who is allowed to send images. By default everyone can. You can limit it to specific jobs (optionally with a minimum grade) or to admins only. Players outside the restriction can still chat normally — their pasted links just stay as text.
Config.ImageRestrict = {
restrict = 'none', -- 'none' (anyone), 'job' or 'admin'
jobs = {}, -- job names, when restrict = 'job'
minRank = 0, -- minimum job grade level (0 = any grade)
}Config.ImageCooldown
Minimum time between images per player, in milliseconds. This is separate from the normal chat cooldown.
Config.ImageCooldown = 5000 -- 5 seconds between imagesConfig.GifPickerEnabled
Shows or hides the GIF search button. Even when enabled, the button stays hidden until a Giphy API key is set.
Config.GifPickerEnabled = trueConfig.GiphyRating
The maximum content rating Giphy search results may have: 'g', 'pg', 'pg-13' or 'r'.
Config.GiphyRating = 'pg-13'Config.GiphyResultCount
How many GIFs one search returns in the picker (6–50).
Config.GiphyResultCount = 24Giphy API key
The GIF picker uses Giphy, which requires a free API key. Get one at developers.giphy.com (create an account, then create an "API" app — the key is shown on your dashboard).
The key is not stored in the config file or the database. Set it as a server convar (a server-side variable) in your server.cfg:
set oxide:chat:giphy_key your-giphy-api-keyUse set, not setr — setr replicates the value to every connected player and would leak your key. With set the key stays on the server only; GIF searches are performed by the server on the players' behalf, so the key is never sent to anyone.
After adding the key, restart the resource. If the button still doesn't show, see Troubleshooting.
Default Player Settings
Config.DefaultSettings
Default values for player-customizable settings. These are used when no saved settings exist.
Config.DefaultSettings = {
-- Position
position = 'top-left', -- 3x3 grid or 'custom'
customX = 24, -- Custom X position (px)
customY = 24, -- Custom Y position (px)
-- General
fontSize = 14, -- Font size (12-20)
fadeTime = 10, -- Fade time in seconds (0 = never)
timestampMode = 'hover', -- 'always', 'hover', 'never'
timestampFormat = '24h', -- '24h' or '12h'
suggestionsPosition = 'top', -- 'top' or 'bottom'
-- Per-type visibility and colors
chatTypes = {
ooc = { visible = true, color = '#C47A2C' },
me = { visible = true, color = '#F4F5F7' },
['do'] = { visible = true, color = '#5F6670' },
system = { visible = true, color = '#5F6670' },
whisper = { visible = true, color = '#C47A2C' },
shout = { visible = true, color = '#9B2C2C' },
announcement = { visible = true, color = '#9B2C2C' },
police = { visible = true, color = '#3b82f6' },
ambulance = { visible = true, color = '#ef4444' },
mechanic = { visible = true, color = '#f97316' },
pm = { visible = true, color = '#a78bfa' },
},
-- Appearance
appearance = {
stylePreset = 'bubbles', -- 'bubbles', 'discord', 'timeline', 'masonry', 'compact', 'cards', 'float', 'panel', 'retro', 'glass'
backgroundOpacity = 75, -- 0-100% (drives message + input opacity)
chatWidth = 480, -- 320-640px
chatHeight = 320, -- 160-600px (visible message area height)
animationsEnabled = true, -- Message animations
messageDensity = 'comfortable', -- 'compact', 'comfortable', 'spacious'
showTabBar = true, -- Show the category tab bar above messages
},
_version = 2, -- Settings schema version
}Position Options
| Value | Location |
|---|---|
top-left | Top left corner |
top-middle | Top center |
top-right | Top right corner |
left | Middle left |
right | Middle right |
bottom-left | Bottom left corner |
bottom-middle | Bottom center |
bottom-right | Bottom right corner |
custom | Uses customX/customY values |
Timestamp Modes
| Value | Description |
|---|---|
always | Always show timestamps |
hover | Show on message hover |
never | Never show timestamps |
Timestamp Format
| Value | Description |
|---|---|
24h | 24-hour clock (e.g. 18:30) |
12h | 12-hour clock (e.g. 6:30 PM) |
Message Density
| Value | Vertical Padding |
|---|---|
compact | Minimal spacing |
comfortable | Default spacing |
spacious | Extra spacing |
Command Blacklist
Config.BlacklistedPrefixes
Hide commands starting with these prefixes from suggestions.
Config.BlacklistedPrefixes = {
['_'] = true, -- Internal commands
['dev'] = true, -- Developer commands
['debug'] = true, -- Debug commands
['test'] = true, -- Test commands
}Config.BlacklistedCommands
Hide specific commands from suggestions.
Config.BlacklistedCommands = {
'toggleChat', -- Internal toggle
'chatResult', -- NUI callback
}Config.IsBlacklisted()
Helper function to check if a command is blacklisted.
if Config.IsBlacklisted('devCommand') then
-- Command won't appear in suggestions
endDebug Mode
Config.Debug
Enable extra debug logging. When on, server console prints are relayed into chat to help with troubleshooting.
Config.Debug = falseYou can also flip this live from the admin panel (/chat settings → Core → General → Debug logging), so you rarely need to touch the file.
Production
Leave this off on a live server:
Config.Debug = falseComplete Default Configuration
config/main.lua
These are the factory defaults (see How Settings Are Stored). On a running server, edit them live with /chat settings instead.
Config = Config or {}
-- General Settings
Config.MaxMessages = 100
Config.MaxMessageLength = 256
Config.MessageFadeTime = 10000
-- Keybinds
Config.OpenKey = 'T'
-- Proximity Settings
Config.ProximityDistance = {
me = 15.0,
['do'] = 15.0,
whisper = 3.0,
shout = 50.0,
local_ooc = 20.0,
}
-- Line of Sight
Config.RequireLOS = {
me = true,
['do'] = true,
whisper = false,
shout = false,
local_ooc = false,
}
-- Chat types & channels — the single list of every chat type (see the Chat Types
-- section above). Built-in rows (builtin = true) carry only styling and can't be
-- removed; custom rows are full channels with their own command and access rules.
Config.ChatChannels = {
-- Built-in message styling
{ builtin = true, id = 'default', label = 'Default Messages', color = '#F4F5F7' },
{ builtin = true, id = 'system', label = 'System Messages', prefix = 'SYSTEM', color = '#5F6670' },
{ builtin = true, id = 'announcement', label = 'Announcements', prefix = 'ANNOUNCEMENT', color = '#9B2C2C' },
{ builtin = true, id = 'ooc', label = 'OOC', prefix = 'OOC', color = '#C47A2C' },
{ builtin = true, id = 'me', label = '/me Actions', color = '#F4F5F7', italic = true },
{ builtin = true, id = 'do', label = '/do Descriptions', color = '#5F6670', italic = true },
{ builtin = true, id = 'whisper', label = 'Whispers', prefix = 'WHISPER', color = '#C47A2C' },
{ builtin = true, id = 'shout', label = 'Shouts', prefix = 'SHOUT', color = '#9B2C2C' },
{ builtin = true, id = 'pm', label = 'Private Messages', color = '#a78bfa' },
-- Custom channels (job radios, staff chat, ...)
{ command = 'lspd', aliases = { 'pd', 'leo' }, id = 'police', label = 'LSPD Radio',
prefix = 'LSPD', color = '#3b82f6', scope = 'members', restrict = 'job', jobs = { 'police' } },
{ command = 'medic', aliases = { 'ambulance' }, id = 'ambulance', label = 'EMS Radio',
prefix = 'EMS', color = '#ef4444', scope = 'members', restrict = 'job', jobs = { 'ambulance' } },
{ command = 'mechanic', aliases = { 'mech' }, id = 'mechanic', label = 'Mechanic Radio',
prefix = 'MECHANIC', color = '#f97316', scope = 'members', restrict = 'job', jobs = { 'mechanic' } },
}
-- Chat categories (switchable tabs above the message list)
Config.CategoriesEnabled = true
Config.Categories = {
{ id = 'all', label = 'All', types = { '*' } },
{ id = 'local', label = 'Local', types = { 'me', 'do', 'whisper', 'shout' } },
{ id = 'global', label = 'Global', types = { 'default', 'ooc', 'announcement', 'system' } },
{ id = 'job', label = 'Job', types = { 'police', 'ambulance', 'mechanic' } },
{ id = 'pms', label = 'PMs', types = { 'pm' } },
}
-- Automatic announcements
Config.AutoBroadcastEnabled = true
Config.AutoBroadcastInterval = 600 -- seconds between messages (minimum 30)
Config.AutoBroadcastOrder = 'sequential' -- 'sequential' (in order) or 'random'
Config.AutoBroadcasts = {
{ title = 'Server Rules', message = 'No RDM or VDM. Read the rules before playing.' },
{ title = 'Join our Discord', message = 'Connect with the community at discord.gg/yourserver' },
}
-- Cooldowns (milliseconds)
Config.Cooldowns = {
ooc = 5000,
announcement = 30000,
chat = 1000,
pm = 1000,
proximity = 1500,
}
-- Images & GIFs
Config.ImagesEnabled = true
Config.ImageHosts = { 'giphy.com', 'cdn.discordapp.com', 'media.discordapp.net' }
Config.ImageRestrict = { restrict = 'none', jobs = {}, minRank = 0 }
Config.ImageCooldown = 5000
Config.GifPickerEnabled = true
Config.GiphyRating = 'pg-13'
Config.GiphyResultCount = 24
-- Giphy API key: set in server.cfg, never here (see the Images & GIFs section):
-- set oxide:chat:giphy_key your-giphy-api-key
-- Debug Mode
Config.Debug = false
-- Default player settings (used when a player has no stored settings)
Config.DefaultSettings = {
position = 'top-left', -- 3x3 grid position
customX = 24, -- Custom X position (px)
customY = 24, -- Custom Y position (px)
fontSize = 14, -- Font size (12-20)
fadeTime = 10, -- Fade time in seconds (0 = never)
timestampMode = 'hover', -- 'always', 'hover', 'never'
timestampFormat = '24h', -- '24h' or '12h'
suggestionsPosition = 'top', -- 'top' or 'bottom'
-- Per-type visibility and colors
chatTypes = {
ooc = { visible = true, color = '#C47A2C' },
me = { visible = true, color = '#F4F5F7' },
['do'] = { visible = true, color = '#5F6670' },
system = { visible = true, color = '#5F6670' },
whisper = { visible = true, color = '#C47A2C' },
shout = { visible = true, color = '#9B2C2C' },
announcement = { visible = true, color = '#9B2C2C' },
police = { visible = true, color = '#3b82f6' },
ambulance = { visible = true, color = '#ef4444' },
mechanic = { visible = true, color = '#f97316' },
pm = { visible = true, color = '#a78bfa' },
},
-- Appearance
appearance = {
stylePreset = 'bubbles', -- 'bubbles', 'discord', 'timeline', 'masonry', 'compact', 'cards', 'float', 'panel', 'retro', 'glass'
backgroundOpacity = 75, -- 0-100 (percentage) - drives message + input opacity
chatWidth = 480, -- 320-640 (pixels)
chatHeight = 320, -- 160-600 (pixels) - visible message area height
animationsEnabled = true, -- Enable message animations
messageDensity = 'comfortable', -- 'compact', 'comfortable', 'spacious'
showTabBar = true, -- Show the category tab bar above messages
},
_version = 2, -- Settings schema version
}