Inventoryadvanced11 min readupdated 11 Sept 2026

Controlling inventory actions with ox_inventory hooks

The short answer

On the server, exports.ox_inventory:registerHook(event, function(payload) ... end, options) runs your function before an action. Events include swapItems, openInventory, openShop, buyItem, createItem, usingItem and craftItem. Return false to cancel (for createItem, return a table to set metadata). Narrow hooks with itemFilter, inventoryFilter (Lua patterns) and typeFilter, keep them fast, and remove them with removeHooks.

Sooner or later every server needs rules the inventory does not have: no weapons in the evidence locker, no drugs in vehicle gloveboxes, a Discord log for every high-value transfer. ox_inventory’s hooks let your resource inspect an action on the server and cancel it — without editing the inventory itself.

Controlling inventory actions with ox_inventory hooks — illustrated with a FiveM-compatible minimap render

#Hook events

EventRuns when
swapItemsItems move between slots or inventories (move, stack, swap, give)
openInventoryAn inventory (stash, trunk…) is opened
openShopA shop is opened
buyItemA shop purchase is made
createItemAn item is created (can return metadata)
usingItemAn item is about to be used
craftItemA crafting recipe is completed

#Example: no weapons in gloveboxes

server.lua
local WEAPONS = {}
for name in pairs(exports.ox_inventory:Items()) do
    if name:find('^WEAPON_') then WEAPONS[name] = true end
end

exports.ox_inventory:registerHook('swapItems', function(payload)
    if payload.toType == 'glovebox' then
        TriggerClientEvent('ox_lib:notify', payload.source, { type = 'error', description = 'Weapons do not fit in the glovebox' })
        return false
    end
end, {
    itemFilter = WEAPONS,
    print = false,
})

itemFilter is a set of item names; the hook only runs when one of them is involved, so everyday item moves cost nothing.

#Filters

OptionFormMatches
itemFilter{ water = true, WEAPON_PISTOL = true }Item names
inventoryFilter{ '^glove', '^trunk', 'evidence' }Inventory IDs by Lua pattern
typeFilter{ player = true, stash = true }Inventory or shop type
printtrueLog each time the hook triggers

#Example: logging high-value transfers

server.lua
exports.ox_inventory:registerHook('swapItems', function(payload)
    if payload.fromInventory ~= payload.toInventory and payload.count >= 10000 then
        print(('[inv] %s moved %s x%d from %s to %s'):format(
            payload.source, payload.fromSlot.name, payload.count, payload.fromInventory, payload.toInventory))
    end
end, { itemFilter = { money = true, black_money = true } })

#Performance and cleanup

  • Hooks run inside the action — no database calls or HTTP requests in them.
  • Use filters instead of if checks at the top of the function.
  • registerHook returns an ID; exports.ox_inventory:removeHooks(id) removes one, and all of a resource’s hooks are removed when it stops.

Related: stashes, shops and item metadata.

Share this guideXRedditFacebook

Questions

How do I stop players moving an item in ox_inventory?
Register a swapItems hook with an itemFilter and return false when the move is not allowed.
Which events can ox_inventory hooks use?
swapItems, openInventory, openShop, buyItem, createItem, usingItem and craftItem.
How do I set metadata when an item is created?
Return a metadata table from a createItem hook.
Do hooks slow down the inventory?
Only if they are slow or unfiltered. Keep them fast and use filters.

Ready to pick a map?

Twelve themes on three base map styles, $8 each, instant download.

Relevant to what you just read

The tool for this

Twenty theme pairs for ox_lib and ox_inventory From $15, built in the browser, exported as a drop-in resource.

Look it up while you work

The reference tables this guide leans on, free and without an account.