Skip to main content
TRACK B·BUILD REAL PRODUCTS·Verified June 2026 · Lua 5.4 · ox_lib 3.x
Learning with an AI assistant?
Copies this lesson plus 2026 ground rules (no lua54 'yes', Cfx.re Portal, correct callback signatures) as a ready-to-paste mentor prompt.

ox_target: "press E to interact", done right

Most FiveM servers have things players can interact with: NPCs, doors, trunks, registers, ATMs. Before ox_target, building those interactions meant lots of repeated distance checks and prompt code. With ox_target, most of that becomes one small options table. ox_target is an Overextended community resource, the successor to qtarget and bt-target, not an official Cfx.re resource. This lesson teaches its one core pattern slowly, then uses it three different ways.

You'll learn
addModel for peds and props -> addGlobalPlayer for other players -> addBoxZone for world regions -> canInteract -> the shared option schema
Time
~25 minutes
Prereqs
ox_lib and Qbox. ox_target installed after ox_lib, with OneSync enabled.
Outcome
A merchant ped, an ATM zone, and a server-validated $100 transfer request on other players, all using the same target system.
BEFORE YOU START

Build it

Make the resource folder

The server has one folder for this lesson.

Inside your server's resources folder, create this folder:

code
resources/qu_ox_target_interactions

Create the files

Every file named in the manifest exists.

Create this exact file layout. This lesson has a client file (the interactions live where the player is) and a server file (giving cash is a server decision):

code
resources/qu_ox_target_interactions/
fxmanifest.lua
client.lua
server.lua

Write fxmanifest.lua

FiveM knows which files to load and what to wait for.

Open fxmanifest.lua and paste this:

code
fx_version 'cerulean'
game 'gta5'

client_script 'client.lua'
server_script 'server.lua'

dependencies {
'ox_lib',
'ox_target',
'/onesync'
}

The canonical manifest key is the plural dependencies { ... } with a table. The singular dependency 'ox_target' is tolerated by FiveM, but the plural form is the form you should write and the form you will see in real resources. We list both ox_lib and ox_target because ox_target itself depends on ox_lib being running first. Older tutorials add a lua54 'yes' line here. As of June 2025 that setting is deprecated and ignored, since Lua 5.4 is now the only Lua runtime, so you leave it out.

Write the client code

Three interactions register the moment the resource starts.

Open client.lua and paste this:

code
-- 1. A box zone over the ATM spot at Legion Square.
exports.ox_target:addBoxZone({
coords = vec3(215.76, -810.12, 30.73),
size = vec3(2.0, 2.0, 2.0),
rotation = 0.0,
debug = true,
options = {
    {
        name = 'qu_atm_use',
        icon = 'fa-solid fa-money-bill',
        label = 'Use ATM',
        distance = 2.0,
        canInteract = function(entity, distance)
            return distance <= 2.0
        end,
        onSelect = function()
            print('[qu_ox_target_interactions] ATM used')
        end
    }
}
})

-- 2. A merchant ped: any ped using this model gets a Talk option.
exports.ox_target:addModel('a_m_y_business_03', {
{
    name = 'qu_merchant_talk',
    icon = 'fa-solid fa-comment',
    label = 'Talk to merchant',
    distance = 2.5,
    onSelect = function()
        print('[qu_ox_target_interactions] merchant talked to')
    end
}
})

-- 3. A give cash option on every OTHER player ped.
exports.ox_target:addGlobalPlayer({
{
    name = 'qu_give_cash',
    icon = 'fa-solid fa-hand-holding-dollar',
    label = 'Give $100',
    distance = 2.0,
    onSelect = function(data)
        local serverId = GetPlayerServerId(NetworkGetPlayerIndexFromPed(data.entity))
        TriggerServerEvent('qu_ox_target_interactions:giveCash', serverId)
    end
}
})

Write the server code

The server fixes the amount, validates the target and distance, and rate-limits the request.

Open server.lua and paste this:

code
local TRANSFER_AMOUNT = 100
local MAX_DISTANCE = 3.0
local lastRequestAt = {}

RegisterNetEvent('qu_ox_target_interactions:giveCash', function(targetId)
local fromId = source
targetId = tonumber(targetId)

if not targetId or targetId == fromId or not GetPlayerName(targetId) then
    print(('[qu_ox_target_interactions] rejected invalid target from %s'):format(fromId))
    return
end

local now = os.time()
if now - (lastRequestAt[fromId] or 0) < 1 then
    print(('[qu_ox_target_interactions] rate-limited %s'):format(fromId))
    return
end
lastRequestAt[fromId] = now

local fromPed = GetPlayerPed(fromId)
local targetPed = GetPlayerPed(targetId)
if fromPed == 0 or targetPed == 0 then return end

local distance = #(GetEntityCoords(fromPed) - GetEntityCoords(targetPed))
if distance > MAX_DISTANCE then
    print(('[qu_ox_target_interactions] rejected distant target from %s'):format(fromId))
    return
end

-- Proof only. A real transfer must also read the sender's balance on the
-- server and use the installed framework's server-side money functions.
print(('[qu_ox_target_interactions] validated %s -> %s for $%s'):format(
    fromId, targetId, TRANSFER_AMOUNT
))
end)

AddEventHandler('playerDropped', function()
lastRequestAt[source] = nil
end)

Start and test it

The expected proof appears in the correct consoles.

Open server.cfg and add this line. It must come after the lines that ensure ox_lib and ox_target:

code
ensure qu_ox_target_interactions

Save, then run:

code
restart qu_ox_target_interactions

Join the server. You will see a translucent debug box floating at the ATM spot. Walk into it, aim at it, and select Use ATM. Then aim at any other player nearby and select Give $100.

The ATM line prints in F8 because onSelect runs on the client. The give cash line prints in the server console (and txAdmin's Live Console mirrors it) because that work was sent to the server. FiveM also forwards server prints back to the triggering player's F8, so you may see the give cash line there too. The numbers 1 and 2 are server ids, so they will match whoever is actually connected.

Keep reading the full lesson

Sign in to start, then unlock every step of this lesson and the full FiveM School with a membership.

Still ahead in this lesson
  • How it works
  • If something went wrong
  • What you can do now
  • Try it yourself

The remainder of ox_target: interact with anything is available to FiveM School members.