# Showing weapons on a player's back in FiveM

> Show rifles and shotguns slung on a player's back in FiveM: attach weapon props to the spine bone, sync them with state bags and make ox_inventory work.

Source: https://fam-tools.com/guides/fivem-weapons-on-back · FAM Tools · published 2026-09-19 · updated 2026-09-19 · about 13 min

**Short answer.** Get the weapon's world model with `GetWeapontypeModel(hash)`, create it with `CreateObject` and attach it to the spine bone (`SKEL_Spine3`, bone id `24818`, resolved with `GetPedBoneIndex`) using `AttachEntityToEntity`. Hide the prop while that weapon is in the player's hands. On ox_inventory the ped only holds the equipped weapon, so ask the inventory (`GetItemCount`) what the player carries. The cleanest sync is to publish the list in a player state bag and let every client draw local props for nearby players.

## Key points

- The prop is the weapon's world model: `GetWeapontypeModel` returns it for vanilla and add-on weapons alike.
- Attach to `SKEL_Spine3` (`24818`) through `GetPedBoneIndex`, never to the raw bone id.
- On ox_inventory and qb-inventory, `HasPedGotWeapon` only sees the equipped gun; query the inventory instead.
- Publish the carried list in a state bag and render local props per client; it survives entity lockdown and never leaves orphaned objects.
- Cap it at one or two props per player and hide them in vehicles.

A rifle that simply vanishes when you holster it is one of the small things that makes GTA feel like GTA rather than a roleplay world. Slinging long guns on the player's back tells everyone nearby what a person is carrying before a word is said, and it is only a prop, a bone and an offset. The hard parts are knowing which weapons the player really owns on an inventory server, and making sure other players see the same thing you do.

## How a back-weapon script works

A back weapon is not a weapon at all. It is an ordinary object using the same model the game draws when a gun lies on the ground, glued to a bone on the ped's skeleton. The game has no idea it represents a rifle, which is exactly what you want: it cannot be fired, dropped or picked up, and it costs roughly what any small prop costs.

Every script that does this, from the old weapons-on-back releases to the ones bundled with modern frameworks, does the same four things:

1. Work out which long weapons the player is carrying.
2. For each one that is not currently in their hands, load the weapon's world model and create a prop.
3. Attach the prop to a spine bone with a position and rotation offset so it sits across the back.
4. Delete the prop the moment the weapon is drawn, and recreate it when it is put away.

*The natives involved*

| Job | Native |
| --- | --- |
| Model for a weapon | `GetWeapontypeModel(weaponHash)` |
| Load the model | `RequestModel` / `HasModelLoaded` |
| Create the prop | `CreateObject(model, x, y, z, isNetwork, netMissionEntity, doorFlag)` |
| Find the bone | `GetPedBoneIndex(ped, 24818)` |
| Attach it | `AttachEntityToEntity(...)` |
| Weapon in hand | `GetSelectedPedWeapon(ped)` |

> **Why not CreateWeaponObject?** — `CreateWeaponObject` builds a proper weapon object, but the native reference states that such objects cannot be attached to a ped and points you to `CreateObject` instead. Use `CreateObject` with the model from `GetWeapontypeModel`.

## Choosing which weapons go on the back

Only long guns belong on the back. Pistols and tasers sit in a holster, which is a different job handled by a draw animation (see [the holster guide](https://fam-tools.com/guides/fivem-holster-draw-animation)). Melee weapons are a judgement call: a bat or a katana on the back reads well, a knife does not.

Keep the list in a config array rather than a keyed table. An array keeps its order, and that order becomes your priority when a player carries more long guns than you are willing to render.

*config.lua*

```lua
Config = {}

Config.Max = 2          -- props per player
Config.Range = 60.0     -- draw distance for other players
Config.Bone = 24818     -- SKEL_Spine3

Config.Weapons = {
    { name = 'WEAPON_CARBINERIFLE',   pos = vec3(0.075, -0.15, -0.02), rot = vec3(0.0, 165.0, 0.0) },
    { name = 'WEAPON_ASSAULTRIFLE',   pos = vec3(0.075, -0.15, -0.02), rot = vec3(0.0, 165.0, 0.0) },
    { name = 'WEAPON_SPECIALCARBINE', pos = vec3(0.075, -0.15, -0.02), rot = vec3(0.0, 165.0, 0.0) },
    { name = 'WEAPON_PUMPSHOTGUN',    pos = vec3(0.075, -0.15,  0.10), rot = vec3(0.0, 195.0, 0.0) },
    { name = 'WEAPON_SMG',            pos = vec3(0.075, -0.15,  0.10), rot = vec3(0.0, 195.0, 0.0) },
    { name = 'WEAPON_BAT',            pos = vec3(0.10,  -0.16,  0.00), rot = vec3(0.0, 225.0, 0.0) },
}
```

The numbers are a starting point, not gospel. Every model has its origin in a different place, so a rifle whose pivot sits at the grip needs a different offset from one whose pivot sits at the receiver. Tuning is covered further down.

## Creating the prop from the weapon's model

`GetWeapontypeModel` returns the model hash for any weapon the game knows about, including add-on weapons, because it reads the `Model` field from weapons.meta. That is why this approach works for a custom rifle without extra configuration, as long as the add-on's model is streamed and registered in weaponarchetypes.meta. The vanilla model names are listed in [the weapon model names guide](https://fam-tools.com/guides/gta-5-weapon-model-names).

*client/props.lua*

```lua
local function loadModel(model)
    if model == 0 or not IsModelInCdimage(model) then return false end
    RequestModel(model)
    local deadline = GetGameTimer() + 5000
    while not HasModelLoaded(model) do
        if GetGameTimer() > deadline then return false end
        Wait(0)
    end
    return true
end

function CreateBackProp(ped, entry)
    local model = GetWeapontypeModel(joaat(entry.name))
    if not loadModel(model) then return nil end

    local c = GetEntityCoords(ped)
    local obj = CreateObject(model, c.x, c.y, c.z - 10.0, false, false, false)
    SetModelAsNoLongerNeeded(model)
    SetEntityCollision(obj, false, false)

    AttachEntityToEntity(obj, ped, GetPedBoneIndex(ped, Config.Bone),
        entry.pos.x, entry.pos.y, entry.pos.z,
        entry.rot.x, entry.rot.y, entry.rot.z,
        true, true, false, true, 2, true)

    return obj
end
```

The prop is created below the ped and attached immediately, so nobody sees it pop into existence at the player's feet. Collision is switched off because a rifle with collision catches doorframes and shoves the player sideways in tight corridors.

## AttachEntityToEntity, parameter by parameter

The attach native has fifteen parameters and most copy-pasted scripts get at least one of them wrong. In order:

*AttachEntityToEntity parameters*

| # | Parameter | Value used here | Why |
| --- | --- | --- | --- |
| 1 | entity1 | the prop | The thing being attached |
| 2 | entity2 | the ped | What it is attached to |
| 3 | boneIndex | `GetPedBoneIndex(ped, 24818)` | Bone index, not bone id |
| 4-6 | xPos, yPos, zPos | config offset | Position relative to the bone |
| 7-9 | xRot, yRot, zRot | config rotation | Rotation relative to the bone |
| 10 | p9 | `true` | Commonly passed as true |
| 11 | useSoftPinning | `true` | Lets the attachment detach cleanly under force |
| 12 | collision | `false` | No collision between prop and world |
| 13 | isPed | `true` | The prop is being attached to a ped |
| 14 | rotationOrder | `2` | The order rotations are applied in |
| 15 | syncRot | `true` | Keep the rotation locked to the bone |

The classic mistake is passing `24818` straight in as parameter three. That number is the bone id (`SKEL_Spine3`, `0x60F2`); the native wants the index of that bone inside this ped's skeleton, which is what `GetPedBoneIndex` returns. Pass the raw id and the rifle ends up floating somewhere near the pelvis or the feet, and it will be in a different wrong place on a different ped model.

> **Tune offsets live** — Give yourself a development command that re-attaches the current prop with new numbers, for example `/backoffset 0.07 -0.15 0.0 0 165 0`. Adjusting six floats in-game takes minutes; restarting the resource for each guess takes an evening.

## Knowing what the player actually carries

This is where most back-weapon scripts break on modern servers. `HasPedGotWeapon` asks the ped, and on an inventory server the ped does not hold your whole arsenal.

- **ox_inventory** gives the ped only the weapon that is currently equipped. Everything else is an item in a slot, so `HasPedGotWeapon` returns false for the rifle in your bag. Ask the inventory with the client export `exports.ox_inventory:GetItemCount('WEAPON_CARBINERIFLE')`.
- **qb-inventory** works the same way: weapons are items and the ped receives one when it is used. Read `QBCore.Functions.GetPlayerData().items` on the client and look for weapon items.
- **ESX with the built-in loadout** really does give the ped every weapon, so `HasPedGotWeapon(ped, hash, false)` is correct there.

*client/owned.lua*

```lua
local useOx = GetResourceState('ox_inventory') == 'started'

local function carries(ped, name)
    if useOx then
        return exports.ox_inventory:GetItemCount(name) > 0
    end
    return HasPedGotWeapon(ped, joaat(name), false)
end

function GetBackList(ped)
    local held = GetSelectedPedWeapon(ped)
    local list = {}
    for _, entry in ipairs(Config.Weapons) do
        local hash = joaat(entry.name)
        if hash ~= held and carries(ped, entry.name) then
            list[#list + 1] = entry.name
            if #list >= Config.Max then break end
        end
    end
    return list
end
```

Excluding the weapon in hand is what makes the rifle "move" from the back to the hands when it is drawn. Nothing moves, of course: one prop is deleted and the real weapon appears.

## Making other players see it

There are two ways to make back weapons visible to everyone, and the difference matters more than any offset.

**Networked props.** Each client creates its own props with `isNetwork = true`, so the objects exist on the server and replicate. It works, but every player now owns several networked entities, they are left behind if a client crashes, and with `sv_entityLockdown` set to `strict` the client is not allowed to create them at all.

**State bag plus local props.** Each client publishes the list of weapons it carries on its own player state bag. Every client reads that list for players within range and creates non-networked props locally. Nothing is created on the server, nothing leaks when someone drops, and the whole thing costs one small replicated value per player.

*client/sync.lua*

```lua
local last = ''

CreateThread(function()
    while true do
        local list = GetBackList(PlayerPedId())
        local key = table.concat(list, ',')
        if key ~= last then
            last = key
            LocalPlayer.state:set('backWeapons', key, true)
        end
        Wait(750)
    end
end)
```

*client/render.lua*

```lua
local rendered = {} -- [serverId] = { key, ped, objs }

local function clear(id)
    local r = rendered[id]
    if not r then return end
    for _, obj in ipairs(r.objs) do
        if DoesEntityExist(obj) then DeleteEntity(obj) end
    end
    rendered[id] = nil
end

local function entryFor(name)
    for _, entry in ipairs(Config.Weapons) do
        if entry.name == name then return entry end
    end
end

CreateThread(function()
    while true do
        local myPos = GetEntityCoords(PlayerPedId())
        local seen = {}

        for _, player in ipairs(GetActivePlayers()) do
            local ped = GetPlayerPed(player)
            local id = GetPlayerServerId(player)
            local key = Player(id).state.backWeapons or ''

            if IsPedInAnyVehicle(ped, false) or IsEntityDead(ped)
                or #(GetEntityCoords(ped) - myPos) > Config.Range then
                key = ''
            end

            seen[id] = true
            local r = rendered[id]
            if not r or r.key ~= key or r.ped ~= ped then
                clear(id)
                local objs = {}
                for name in key:gmatch('[^,]+') do
                    local entry = entryFor(name)
                    local obj = entry and CreateBackProp(ped, entry)
                    if obj then objs[#objs + 1] = obj end
                end
                rendered[id] = { key = key, ped = ped, objs = objs }
            end
        end

        for id in pairs(rendered) do
            if not seen[id] then clear(id) end
        end
        Wait(500)
    end
end)

AddEventHandler('onResourceStop', function(res)
    if res ~= GetCurrentResourceName() then return end
    for id in pairs(rendered) do clear(id) end
end)
```

`GetActivePlayers` includes the local player, so the same loop draws your own back weapons. Comparing the stored ped handle catches respawns and model changes, which create a new ped and would otherwise leave the old props attached to nothing.

## Performance and edge cases

- **Cap the count.** Two props per player is plenty. Twenty players with four rifles each is eighty attached objects for no gameplay gain.
- **Hide in vehicles.** Seats clip through rifles on almost every car. The render loop above clears the props whenever the ped is in a vehicle.
- **Bags and vests.** A large backpack (component 5) or a bulky vest (component 9) pushes the model out of alignment. Some servers keep a second offset per weapon for players wearing a bag; check `GetPedDrawableVariation(ped, 5)` and swap offsets.
- **Female peds.** `mp_f_freemode_01` has a slightly different spine. If rifles hover off female characters, add a small per-model correction.
- **Add-on weapons.** A heavy weapon pack means heavy props. Oversized textures on weapons show up here too, because every back weapon streams the full model. [Weapon pack performance](https://fam-tools.com/guides/fivem-weapon-pack-performance) covers budgets.

## Troubleshooting

*Common problems*

| Symptom | Cause | Fix |
| --- | --- | --- |
| Rifle floats at the hips or feet | Raw bone id passed as the index | Wrap it in `GetPedBoneIndex(ped, 24818)` |
| Prop visible only to you | Local prop and no sync | Publish a state bag and render for every player |
| Nothing appears on ox_inventory | `HasPedGotWeapon` used | Use `exports.ox_inventory:GetItemCount` |
| Add-on weapon never shows | Model not streamed or not in archetypes | Check `IsModelInCdimage(model)`; see the streaming guides |
| Rifle stays on the back after drawing | List not refreshed | Exclude `GetSelectedPedWeapon` and poll |
| Props left in the world after a crash | Networked props owned by the client | Switch to the state bag approach |

If an add-on weapon shows in the hand but not on the back, the model hash is probably fine and the offset is the problem: a model whose origin sits far from the grip can end up a metre behind the player. Set the offset to zero and work outwards.

## Questions

### How do I put weapons on a player's back in FiveM?

Create the weapon's world model with `CreateObject(GetWeapontypeModel(hash), ...)` and attach it with `AttachEntityToEntity` to the bone index returned by `GetPedBoneIndex(ped, 24818)`, then delete it whenever that weapon is in the player's hands.

### Why do weapons on back not show with ox_inventory?

ox_inventory only gives the ped the equipped weapon, so `HasPedGotWeapon` is false for everything else. Check the inventory with `exports.ox_inventory:GetItemCount(name)` instead.

### Which bone should a back weapon attach to?

`SKEL_Spine3` (bone id `24818`, `0x60F2`) is the usual choice. Always convert it with `GetPedBoneIndex` before passing it to the attach native.

### Do other players see my back weapons?

Only if you sync them. Publish the carried weapons in a player state bag and let every client create local props for nearby players, or create networked props if your entity lockdown allows it.

### Does this work for add-on weapons?

Yes. `GetWeapontypeModel` reads the model from the add-on's weapons.meta, so any add-on that streams correctly can be shown on the back with its own offset.

## Related

- https://fam-tools.com/guides/fivem-holster-draw-animation
- https://fam-tools.com/guides/gta-5-weapon-model-names
- https://fam-tools.com/guides/ox-inventory-weapons-data
- https://fam-tools.com/guides/fivem-weapon-pack-performance
- https://fam-tools.com/guides/fivem-weapon-flashlight-scope-positions
