qb-target vs ox_target: convert AddBoxZone and fix targets not showing
Moving from qb-target to ox_target on FiveM: how to convert AddBoxZone and AddTargetModel calls, what the compatibility layer does, and why targets do not show.
You moved from qb-target to ox_target, or you downloaded a script written for one while running the other, and the interaction zones are gone or doubled. Here is how the two differ, how to convert the calls, and how to find why a target does not show.
The difference in one table
Both resources do the same job: a key opens a targeting eye and the player picks an option on an entity or in a zone. They differ in how you describe it.
| Idea | qb-target | ox_target |
|---|---|---|
| Box zone | AddBoxZone(name, center, length, width, options, targetOptions) |
addBoxZone({ coords, size, rotation, options }) |
| Model | AddTargetModel(models, options) |
addModel(models, options) |
| What to do | type, event, action |
onSelect, event, serverEvent |
| Job limit | job |
groups |
| Item limit | item |
items |
| Extra check | canInteract |
canInteract |
ox_target takes a single table for zones, and the options are a plain list, with no wrapper that holds options and distance together.
Convert a box zone
A typical qb-target zone:
exports['qb-target']:AddBoxZone('pd_armory', vector3(452.2, -980.0, 30.7), 1.5, 1.0, {
name = 'pd_armory',
heading = 90.0,
debugPoly = false,
minZ = 29.7,
maxZ = 31.7,
}, {
options = {
{
type = 'client',
event = 'my_script:openArmory',
icon = 'fas fa-gun',
label = 'Open armory',
job = 'police',
},
},
distance = 2.0,
})The same zone in ox_target:
exports.ox_target:addBoxZone({
coords = vec3(452.2, -980.0, 30.7),
size = vec3(1.0, 1.5, 2.0),
rotation = 90.0,
debug = false,
options = {
{
name = 'pd_armory',
event = 'my_script:openArmory',
icon = 'fa-solid fa-gun',
label = 'Open armory',
groups = 'police',
distance = 2.0,
},
},
})What moved:
centerbecomescoords, and it is the centre of the box in both, but the height now comes fromsize. qb-target usesminZandmaxZ, so putcoords.zhalfway between them and use their gap as the height.lengthandwidthbecome thexandyofsize. If the box ends up turned the wrong way, swap them or changerotation, and check withdebug = true.headingbecomesrotation.jobbecomesgroups, anddistancemoves into each option.type = 'client'witheventstays anevent. UseserverEventfortype = 'server', oronSelectwith a function instead of an event.
Convert a model target
qb-target:
exports['qb-target']:AddTargetModel({ `prop_atm_01`, `prop_atm_02` }, {
options = {
{
type = 'client',
event = 'my_script:openAtm',
icon = 'fas fa-credit-card',
label = 'Use ATM',
},
},
distance = 1.5,
})ox_target:
exports.ox_target:addModel({ `prop_atm_01`, `prop_atm_02` }, {
{
name = 'my_script_atm',
event = 'my_script:openAtm',
icon = 'fa-solid fa-credit-card',
label = 'Use ATM',
distance = 1.5,
},
})The options are now the second argument itself, a list of option tables. The full list of exports and fields is in ox_target: addBoxZone, addModel and addLocalEntity.
Keep an old script working
ox_target provides compatibility for many qb-target exports. A script that still calls exports['qb-target']:AddBoxZone(...) can keep working when only ox_target is running, as long as it uses the common exports.
Do not rely on it for everything. Less common exports and unusual option fields may not behave the same. Test each script, and when one misbehaves, convert its calls to the native ox_target exports as shown above. Native calls are also easier to read and debug.
Warning: do not start qb-target next to ox_target to "make sure". Keep one targeting resource only, and remove the other from
server.cfg.
Why targets do not show
Almost every "my target is invisible" case falls in this list.
Both resources are running. Two targeting resources fight over the same key. Check server.cfg and your resources list, and keep only one:
ensure ox_lib
ensure ox_target
# ensure qb-target <- remove or comment outThe distance is too small. The option shows only inside its distance. Try distance = 3.0 while you test. With qb-target, the distance sits next to options, not inside each option.
A job check fails. An option with job (qb-target) or groups (ox_target) is hidden for anyone without that job, with no error. Test with the right job, or remove the field for a moment. On ox_target a grade in the table ({ police = 2 }) means the player needs at least that grade.
A canInteract returns nothing. If the function has a code path that returns nil, the option is hidden. Make it return true or false on every path.
The zone is in the wrong place. Turn on debug = true on ox_target (or debugPoly = true on qb-target) and look at the shape. A box centred on the floor is half underground.
The script runs before the target. Start the target resource before your script in server.cfg, and add dependency 'ox_target' to your manifest.
Checklist
| Symptom | Fix |
|---|---|
| Options doubled or missing | Run only one of qb-target and ox_target |
job ignored after converting |
Rename it to groups |
| Zone is rotated or sized wrongly | heading becomes rotation; check size with debug = true |
| Option never shows | Increase distance, test the job and canInteract |
| Old script stops working | Convert its calls to native ox_target exports |
| Nothing shows at all | Start ox_target and ox_lib before your scripts |
Quick answers
Can I run qb-target and ox_target together?
No. Pick one. Both resources want the same targeting key and the same job, and running both gives you doubled or missing options.
Do my old qb-target scripts work with ox_target?
Often yes. ox_target provides compatibility for many qb-target exports, so scripts that call them can keep working. Test each script, and convert the ones that misbehave to the native ox_target exports.
What replaces the job field of qb-target?
ox_target uses groups. Set groups = 'police', or a table such as { police = 0 } to also require a grade.
Scripts that skip this problem
Shop CreatorBuild a shop in under a minute — owners, employees, vaults and robberies included.View script →
Quest CreatorA visual editor for quests and NPC dialogues, built node by node in game.View script →
Advanced BoostingTablet-driven vehicle boosting: contracts from class D to S+, crews and a live queue.View script →