FiveM Docs
Addons

esx_barbershop

Install and configure esx_barbershop for ESX Legacy. Hair, beard and makeup changes via esx_skin, all config keys, the pay callback, refund logic and common fixes.

esx_barbershop places barber shops on the map where players pay to change their hairstyle, beard, eyebrows, makeup, lipstick and ear accessories. It reuses the esx_skin menu in restricted mode and saves the result server-side, with an automatic refund if saving fails.

Overview

Resourceesx_barbershop
SideClient + server
Dependenciesesx_lib, es_extended, esx_skin
DatabaseNone (uses the skin column via esx_skin)
PaymentCash (xPlayer.removeMoney)

In-game flow:

  1. The player walks into one of the 7 default shop markers and presses E.
  2. The esx_skin menu opens, limited to the fields listed below.
  3. After confirming with "Yes", the server checks distance and money, charges Config.Price and saves the skin.
  4. "No", leaving the marker or a failed payment reloads the previous look.

Editable fields: hair_1, hair_2, hair_color_1, hair_color_2, beard_1 to beard_4, eyebrows_1 to eyebrows_4, makeup_1 to makeup_4, lipstick_1 to lipstick_4, ears_1, ears_2.

Installation

There is no SQL file. Make sure esx_skin (which exports SaveSkin) starts first:

server.cfg
ensure es_extended
ensure esx_lib
ensure skinchanger
ensure esx_skin
ensure esx_barbershop

Configuration

All keys live in config.lua.

KeyDefaultDescription
Config.Price100Cash price per visit.
Config.ShopDistance3.0Server-side maximum distance (meters) between the player and a shop for paying.
Config.DrawDistance10.0Distance at which markers are drawn.
Config.MarkerSizevector3(1.5, 1.5, 1.0)Marker size. The interaction radius is fixed to 1.5 in the client.
Config.MarkerColor{r = 102, g = 102, b = 204}Marker color (alpha fixed to 100).
Config.MarkerType1Marker type.
Config.LocaleGetConvar('esx:locale', 'en')Locale for help text and notifications.
Config.Shops7 vector3 positionsShop locations. Each gets a marker and a blip (sprite 71, color 51).

Default shop positions:

config.lua
Config.Shops = {
	vector3(-814.3, -183.8, 36.6),
	vector3(136.8, -1708.4, 28.3),
	vector3(-1282.6, -1116.8, 6.0),
	vector3(1931.5, 3729.7, 31.8),
	vector3(1212.8, -472.9, 65.2),
	vector3(-32.9, -152.3, 56.1),
	vector3(-278.1, 6228.5, 30.7)
}

Callbacks

Both callbacks are registered with xLib.callback.registerCompat, so they work with xLib.callback and ESX.TriggerServerCallback.

esx_barbershop:pay

xLib.callback('esx_barbershop:pay', false, function(paid, reason) end, skin)
NameTypeDescription
skintableFull skin table from skinchanger:getSkin.

Returns paid (boolean) and, on failure, a reason string. Reasons set by this resource: player_unavailable, rate_limited, not_near_shop, invalid_appearance:payload:expected_table, payment_pending, insufficient_funds, payment_failed, appearance_save_failed, appearance_save_error, appearance_save_rejected, resource_stopped. esx_skin can pass its own reasons through as well (for example appearance_scope_mismatch:sex).

The server:

  • rate limits each player (2 requests, refilled 1 per 2 seconds),
  • requires the player within Config.ShopDistance of a shop,
  • locks the account with xPlayer.beginAccountOperation() and allows only one pending payment per identifier,
  • calls exports.esx_skin:SaveSkin(source, skin, finish, 'barber') and refunds the price with reason Haircut Refund if the save does not succeed.

esx_barbershop:checkMoney

xLib.callback('esx_barbershop:checkMoney', false, function(canPay) end)

Returns true when the player is near a shop and has at least Config.Price cash.

Server events

esx_barbershop:pay

TriggerServerEvent('esx_barbershop:pay', skin)

Legacy net event that runs the same logic as the callback without returning a result. The bundled client uses the callback.

Client-triggerable

Any client can send this event with an arbitrary skin table. The server still enforces the distance check, rate limit and full price, and esx_skin's SaveSkin with scope 'barber' only copies the fields listed in its Config.SkinEditFields.barber onto the stored skin and rejects a changed sex. A cheater cannot get a free haircut or swap clothes this way, as long as esx_skin is current.

Client events

Local events fired by the marker zones:

EventArgumentFired when
esx_barbershop:hasEnteredMarkerzone (shop index)Player enters a shop marker. Shows the help text with ESX.TextUI.
esx_barbershop:hasExitedMarkerzonePlayer leaves. Closes the menu and restores the old skin if nothing was paid.

Common issues

  • Purchase failed notification, money returned. esx_skin rejected the save. Check the server console for [esx_barbershop] Appearance save failed and the reason; usually esx_skin is outdated and has no SaveSkin export.
  • "Not enough money" although the bank is full. Only cash (money account) is used.
  • Look resets after relog. The save failed or another skin script overwrote the skin. Make sure only one appearance resource writes to users.skin.

Frequently asked questions

Independent documentation

esx-fivem.com is a community project and is not affiliated with the ESX Framework team. Facts on this page were checked against the upstream source. Official resources: docs.esx-framework.org and github.com/esx-framework.
Edit on GitHub

Last updated on

On this page