Play custom sounds in FiveM: NUI audio, volume by distance, formats

Play custom sounds on FiveM with NUI audio (SendNUIMessage and an HTML audio element), distance-based volume, OGG files, xsound and native audio banks.

You have a sound file, such as a doorbell, a siren or a notification, and you want to play it from a script. FiveM has no simple native for custom audio files, so the usual answer is NUI: a hidden web page in your resource that plays the file when a client script asks it to. This is how resources in the style of interact-sound work. Below you find the code, the distance volume, the formats and the other options.

How it works

  1. The resource has an HTML page (ui_page) with a small script.
  2. The client script sends a message to the page with SendNUIMessage.
  3. The page creates an Audio object with the file and plays it.

The page can stay invisible, and it needs no mouse focus.

The resource

text
resources/[mic]/my_sounds/
  fxmanifest.lua
  client.lua
  html/
    index.html
    sounds/
      doorbell.ogg
      alarm.ogg
lua
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

ui_page 'html/index.html'

files {
    'html/index.html',
    'html/sounds/*.ogg',
}

client_script 'client.lua'

The sound files must be in files, or the page cannot load them.

The HTML page

html
<!DOCTYPE html>
<html>
<body>
<script>
  window.addEventListener('message', (event) => {
    const data = event.data
    if (data.action !== 'play') return

    const audio = new Audio('./sounds/' + data.file + '.ogg')
    audio.volume = Math.min(Math.max(data.volume ?? 1.0, 0), 1)
    audio.play().catch((err) => console.log('sound error', err))
  })
</script>
</body>
</html>

audio.volume goes from 0.0 to 1.0. Values outside that range cause an error, so the code clamps it.

The client script

lua
local function playSound(file, volume)
    SendNUIMessage({
        action = 'play',
        file = file,
        volume = volume or 1.0,
    })
end

RegisterNetEvent('my_sounds:play', function(file, volume)
    playSound(file, volume)
end)

exports('PlaySound', playSound)

Now another client script can call exports.my_sounds:PlaySound('doorbell', 0.6), and the server can send TriggerClientEvent('my_sounds:play', source, 'doorbell', 0.6) to one player, or -1 for all of them.

Tip: for a sound a player should hear all the time (a notification, a phone ringtone), this is all you need. For a sound that belongs to a place, use the distance version below.

Distance-based volume

For a sound at a point, such as an alarm on a building, the server sends the coordinates, and each client decides how loud it is:

lua
-- client.lua
RegisterNetEvent('my_sounds:playAt', function(file, coords, maxDistance, baseVolume)
    local pos = GetEntityCoords(PlayerPedId())
    local dist = #(pos - vec3(coords.x, coords.y, coords.z))

    if dist >= maxDistance then return end

    local volume = (1.0 - dist / maxDistance) * (baseVolume or 1.0)
    playSound(file, volume)
end)
lua
-- server.lua: everyone gets it, only players in range hear it
TriggerClientEvent('my_sounds:playAt', -1, 'alarm', vec3(120.0, -1300.0, 29.0), 40.0, 1.0)

This checks the distance once, when the sound starts. For a long sound where the player moves, send the position again at intervals, or keep the audio object in the page and update its volume as the client sends new values. A sound that must follow a moving vehicle is where a ready made library helps, as in the next section.

Keep the server in control of who triggers what. If you let clients send a play for everyone event, any cheater can spam sounds to the whole server. See server events and security.

File formats and size

  • OGG: the best default, small and good quality.
  • MP3: also fine, and easy to find.
  • WAV: works, but it is large. Use it only for very short effects.

Every file in files is downloaded by every player, so keep it short, mono for effects, and compressed. Trim silence at the start of the file: a delay that you hear in game often comes from that. If the total is big, the same warning applies as for other assets: see oversized assets.

xsound and other libraries

Instead of writing the page yourself, you can use a sound library such as xsound. It plays audio from a file or an URL at a position or on an entity, and can change the volume and the position later, which suits music in a bar or a boombox that follows a player. Read its README for its exact exports, since they differ between versions. The idea is the same: a hidden NUI page plays the audio, and a client script controls it.

Native sounds and audio banks

The game's own sounds are another option. They are played with natives such as PlaySoundFrontend or PlaySoundFromCoord, with the sound's name and set, and need no files from you. Adding your own sounds to the game's audio system is also possible, with audio bank files and data_file lines for audio, but it is a specialist job with its own tools and it is easy to break. For most servers, NUI audio is simpler and enough.

Common problems

  • No sound at all. Check the file name and that the file is in files. Open the NUI in the game's developer tools if you have them, and read the console for a 404.
  • Sound plays only once. Create a new Audio object each time, as in the code above, or reset currentTime on a kept one.
  • Too loud or too quiet. Keep volume from 0.0 to 1.0, and set it low by default.
  • The sound is cut when the resource restarts. The page is reloaded with the resource. That is expected.
  • A script that uses interact-sound fails. Resources that expect that name need a resource with the same name and exports. Check what the script wants before you rename yours.

Checklist

Symptom Fix
Nothing plays Put the files in files and check the ui_page line
Wrong path Use ./sounds/<name>.ogg relative to the HTML page
Too loud Clamp audio.volume between 0 and 1, and lower the default
Sound should fade with distance Send coordinates and compute the volume on the client
Download is slow Use short OGG files and compress them
Moving source (vehicle) Use a library such as xsound, or update the volume as the player moves

Quick answers

What audio format should I use?

OGG is a good default: small files and well supported by the game's browser. MP3 also works. Avoid WAV for anything long, since the files are large and every player downloads them.

Do I need SetNuiFocus to play a sound?

No. Playing audio from NUI needs no focus and no visible interface, only a page loaded with ui_page that contains the audio code.

How do I make a sound quieter when the player is far away?

Send the coordinates of the sound to the client, measure the distance to the player and set the audio volume from it, for example linearly from 1 close to 0 at the maximum distance.

Scripts that skip this problem

Arcade MachinesSeven playable arcade games in real cabinets, with leaderboards and bets.View script →Mic PhoneA foldable phone that unfolds into a tablet and carries onto a player's real phone.View script →Crypto MiningBuy a warehouse, build rigs part by part and mine coins on a market that moves.View script →

Keep reading