Engineering
Logging FiveM server events to Discord
Log FiveM events to Discord webhooks: embed JSON (title, description, colour, fields, timestamp), sending from the server with PerformHttpRequest, keeping webhook URLs in server-only convars, Discord size limits and rate limiting, batching, what to log for staff, and privacy.
Overview
Staff cannot watch the console all day. Sending important events — bans, big money transfers, admin commands, suspicious activity — to Discord channels gives the team a searchable record. Done carelessly, it leaks webhook URLs, floods channels and exposes player data.
Sending an embed
local HOOK = GetConvar('logs_webhook_admin', '')
local function log(title, description, color, fields)
if HOOK == '' then return end
local body = json.encode({
username = 'Server Logs',
embeds = { {
title = title:sub(1, 256),
description = description:sub(1, 4096),
color = color or 3447003,
fields = fields,
timestamp = os.date('!%Y-%m-%dT%H:%M:%SZ'),
} },
})
PerformHttpRequest(HOOK, function(status)
if status == 429 then print('[logs] rate limited by Discord') end
end, 'POST', body, { ['Content-Type'] = 'application/json' })
end
log('Ban', 'Player banned for RDM', 15158332, {
{ name = 'Player', value = 'Name (license:abc…)', inline = true },
{ name = 'Admin', value = 'StaffName', inline = true },
})color is a decimal integer (15158332 is red). HTTP details: PerformHttpRequest.
Keep the webhook secret
Anyone with a webhook URL can post into your channel. Put it in server.cfg with set logs_webhook_admin "https://discord.com/api/webhooks/..." — set, not setr, so it never reaches clients — and never in shared or client scripts. If one leaks, delete the webhook in Discord and create a new one.
Limits and batching
- Discord rate-limits webhooks; on HTTP 429, wait before retrying.
- Queue frequent events (item moves, kills) and send one message every few seconds with several lines or embeds.
- Split channels by topic: admin actions, economy, anticheat, joins.
- Truncate long text to the documented field limits.
What to log
| Worth logging | Usually noise |
|---|---|
| Bans, kicks, warnings with reasons | Every chat message |
| Admin commands and spawns | Every item move |
| Large money and item transfers | Every join and leave on big servers |
| Anticheat detections | Routine job payouts |
IP addresses and identifiers are personal data; restrict those channels to senior staff. Detection ideas: anticheat basics.
Frequently asked questions
How do I send FiveM logs to Discord?
POST a JSON body with embeds to a webhook URL from the server using PerformHttpRequest.
Where should I store the webhook URL?
In a server-only convar (set) in server.cfg, never in client files.
Why are my Discord logs missing?
Often rate limiting (HTTP 429) or embeds that exceed Discord’s length limits. Batch and truncate.
What colour format do embeds use?
A decimal integer, for example 3447003 for blue.
Need this built, not just explained?
Ten years of FiveM work, from Lua to NUI
Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.
Related guides
- EngineeringCalling web APIs from FiveM scriptsPerformHttpRequest(url, function(statusCode, body, headers, errorData) ... end, method, data, headers) sends a request and calls back with the result. Encode JSON bodies with json.encode, set Content-Type and auth headers, and decode responses with json.decode. Wrap it in a promise and Citizen.Await to get a synchronous style. Keep API keys in server-only convars and make requests from the server.
- EngineeringProtecting a FiveM server against cheatersBuild in layers: make the server the authority for money, items and entities; validate every net event; enable sv_entityLockdown once scripts spawn server-side; filter dangerous game events (explosionEvent, weaponDamageEvent, clearPedTasksEvent) on the server; ban on several identifiers plus GetPlayerToken tokens; add honeypot events; and log everything. A commercial anticheat adds client-side detection on top — it does not replace the rest.
- EngineeringConvars in FiveM: configuration that lives in server.cfgset name value creates a server-only convar. sets name value also publishes it to the server list (for tags, locale, banners). setr name value replicates it to clients so client scripts can read it. Read convars with GetConvar(name, default) (strings) or GetConvarInt(name, default) (integers). Never use setr or sets for secrets.
- EngineeringWriting server events that cannot be abusedAny client can call any event you registered with RegisterNetEvent, with any arguments. In each handler: copy source into a local, check argument types and ranges, re-derive everything from server state (prices, amounts, rewards), verify the player can do this now (distance, job, item, cooldown), and log refusals. Events only other server scripts should use are registered with AddEventHandler alone, so clients cannot trigger them.