Callbacks
How ESX Legacy callbacks work: TriggerServerCallback, AwaitServerCallback, RegisterServerCallback and client callbacks, with timeouts and limits.
Callbacks let one side ask the other side for data and get an answer back. The client asks the server with ESX.TriggerServerCallback or ESX.AwaitServerCallback, and the server answers through a handler registered with ESX.RegisterServerCallback. The reverse direction works the same way with client callbacks.
Overview
| Resource | es_extended (implemented by esx_lib) |
| Side | Client and server |
| Source | client/modules/callback.lua, server/modules/callback.lua |
In ESX Legacy 1.16 the ESX callback functions are thin wrappers around xLib.callback from esx_lib. The ESX signatures (cb as first or second argument) still work, so old scripts do not need changes.
| Direction | Register on | Trigger with |
|---|---|---|
| Client asks server | Server: ESX.RegisterServerCallback | Client: ESX.TriggerServerCallback, ESX.AwaitServerCallback |
| Server asks client | Client: ESX.RegisterClientCallback | Server: ESX.TriggerClientCallback, ESX.AwaitClientCallback |
Client functions
ESX.TriggerServerCallback
ESX.TriggerServerCallback(eventName, callback, ...)Calls a server callback and passes the response to callback. Does not block.
| Name | Type | Description |
|---|---|---|
eventName | string | Callback name. |
callback | function | Receives the values the server passed to cb. |
... | any | Arguments sent to the server handler. |
Returns: nothing
ESX.TriggerServerCallback('garage:getVehicles', function(vehicles)
for i = 1, #vehicles do
print(vehicles[i].plate)
end
end, 'pillbox')ESX.AwaitServerCallback
ESX.AwaitServerCallback(eventName, ...)Calls a server callback and waits for the answer. Must run inside a thread (command handler, CreateThread, event handler).
| Name | Type | Description |
|---|---|---|
eventName | string | Callback name. |
... | any | Arguments sent to the server handler. |
Returns: every value the server passed to cb.
RegisterCommand('mygarage', function()
local vehicles = ESX.AwaitServerCallback('garage:getVehicles', 'pillbox')
print(('You own %d vehicles here'):format(#vehicles))
end, false)ESX.AwaitServerCallback throws an error when the callback does not exist or times out. Wrap it in pcall if your code must continue in that case.
ESX.RegisterClientCallback
ESX.RegisterClientCallback(eventName, callback)Registers a callback the server can call on this client. The handler gets cb first, then the server's arguments. It is removed when your resource stops.
| Name | Type | Description |
|---|---|---|
eventName | string | Callback name (max. 200 characters). |
callback | function | function(cb, ...). Call cb(...) once with the response. |
Returns: nothing
ESX.RegisterClientCallback('police:getStreetName', function(cb)
local coords = GetEntityCoords(ESX.PlayerData.ped)
local street = GetStreetNameFromHashKey(GetStreetNameAtCoord(coords.x, coords.y, coords.z))
cb(street)
end)ESX.DoesClientCallbackExist
ESX.DoesClientCallbackExist(eventName)Returns: boolean, whether a callback with this name is registered in the local esx_lib registry.
Server functions
These are listed here so both halves are in one place. The full server reference is in Server functions.
ESX.RegisterServerCallback
ESX.RegisterServerCallback(eventName, callback)| Name | Type | Description |
|---|---|---|
eventName | string | Callback name (max. 200 characters). |
callback | function | function(source, cb, ...). Call cb(...) once with the response. |
Returns: nothing
ESX.RegisterServerCallback('garage:getVehicles', function(source, cb, garage)
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer or type(garage) ~= 'string' then
return cb({})
end
local vehicles = MySQL.query.await(
'SELECT plate, vehicle FROM owned_vehicles WHERE owner = ? AND parking = ?',
{ xPlayer.identifier, garage }
)
cb(vehicles or {})
end)ESX.TriggerClientCallback
ESX.TriggerClientCallback(player, eventName, callback, ...)| Name | Type | Description |
|---|---|---|
player | number | Server id of the target player. |
eventName | string | Client callback name. |
callback | function | Receives the client's response. |
... | any | Arguments for the client handler. |
Returns: nothing
ESX.TriggerClientCallback(source, 'police:getStreetName', function(street)
print(('Player %s is on %s'):format(source, street))
end)ESX.AwaitClientCallback
ESX.AwaitClientCallback(player, eventName, ...)Blocking version of ESX.TriggerClientCallback. Returns: the values the client passed to cb.
ESX.DoesServerCallbackExist
ESX.DoesServerCallbackExist(eventName)Returns: boolean
Timeouts and limits
| Setting | Default | Description |
|---|---|---|
esx:callbackTimeout / xLib:callbackTimeout | 300000 ms | How long the caller waits. 0 disables the timeout. Set on the server; it is replicated to clients. |
xLib:callbackValidationGrace | 15000 ms | How long an unknown callback name is given to appear before the caller gets "does not exist". |
xLib:callbackBurst / xLib:callbackRate | 60 / 30 per second | Per-player rate limit for client to server callbacks. |
xLib:callbackMaxInFlight | 8 | Open client to server callbacks per player. |
xLib:callbackMaxPayloadBytes | 65536 | Max size of the arguments a client may send. |
setr esx:callbackTimeout 30000If a client exceeds the rate limit or payload size, or a server handler takes longer than the receiver timeout (30 s unless esx:callbackTimeout is set), the client gets false as the response.
Built-in callbacks
| Name | Side | Returns |
|---|---|---|
esx:getPlayerData | Server | Identifier, accounts, inventory, job, loadout, money, position and metadata of the caller. |
esx:getOtherPlayerData | Server | Same data for another player id. Admins only, otherwise nil. |
esx:isUserAdmin | Server | true if the caller is an admin. |
esx:getGameBuild | Server | Value of sv_enforceGameBuild (default 1604). |
esx:getPlayerNames | Server | Character names for a table of player ids. |
esx:spawnVehicle | Server | Deprecated. Admin-only vehicle spawn, prints a warning. |
esx:GetVehicleType | Client | Vehicle type string for a model. Used by the server-side ESX.GetVehicleType. |
local isAdmin = ESX.AwaitServerCallback('esx:isUserAdmin')Security
Never trust callback arguments
Everything a client sends to ESX.RegisterServerCallback can be faked by a cheater. Validate types and ranges, look the player up with ESX.GetPlayerFromId(source), and check permissions and distances on the server. Never let a callback give money or items based on a value the client sent.
Common issues
- Old code calls
cbtwice. Only the first call is used. - Server handler never calls
cb. After the receiver timeout (30 s by default) the server answers withfalse, so the client getsfalseinstead of your data. - "callback 'x' is already owned by resource 'y'". Two resources use the same name. Prefix names with your resource name.
Related
Frequently asked questions
Independent documentation
Last updated on
Client UI
ESX Legacy client UI functions for notifications, help text, TextUI, progress bars, the context menu and ESX.UI.Menu, with parameters and examples.
ESX.Game
ESX.Game client reference for ESX Legacy - spawn and delete vehicles and objects, find the closest player or vehicle, and get or set vehicle properties.