Bodycam & Dashcam
A bodycam and dashcam script for FiveM, providing immersive video and recording features for law enforcement roleplay.
Installation
Download the Script
Download Bodycam & Dashcam (sx_bodycamdashcam) using the Cfx Portal.
Download the Dependencies
Download the latest ox_lib GitHub.
Server.cfg Configuration
Add the following lines to your server.cfg to ensure the required resources are loaded:
ensure ox_lib
ensure sx_bodycamdashcamMake sure ox_lib is started before sx_bodycamdashcam.
If you are using R2 for recording storage, also add:
set R2_BUCKET ""
set R2_ACCOUNT_ID ""
set R2_ACCESS_KEY_ID ""
set R2_SECRET_ACCESS_KEY ""Configuration
Ace Permission Setup
Available Ace Permissions
| Permission | Description |
|---|---|
DashcamSetup | Allows user to set up dashcam positions using the in-game setup command (/dashcamsetup). |
BodycamDashcam | (Standalone only) Allows user to use bodycam & dashcam features when framework is set to standalone. |
Example Usage
add_ace group.admin "DashcamSetup" allow
add_ace group.police "BodycamDashcam" allow # Only needed for standalone modeInventory Integration
ox_inventory
If you are using the ox_inventory inventory, you must include the export table within the item data for the bodycam item.
Example:
['bodycam'] = {
label = 'Bodycam',
weight = 0.1,
consume = 0,
server = {
export = 'sx_bodycamdashcam.bodycam'
}
},
-- Optional and only required if you're using the battery feature
['bodycam_battery'] = {
label = 'Bodycam Battery',
weight = 0.1,
consume = 0,
server = {
export = 'sx_bodycamdashcam.battery'
}
},This is required for the item(s) to function properly with ox_inventory.
Bodycam Configuration
The bodycam script is highly configurable via the ClientConfig.Bodycam section. Below are the key options and their explanations:
Prop
Type
Recording Storage
Bodycam recordings support:
Discord webhooks are not supported for bodycam video uploads as it is very limited in terms of the max file size.
Fivemanage Setup
To use Fivemanage for recording storage, you need to generate an API key from your Fivemanage dashboard.
Retrieve API Key from Fivemanage
- Go to the Fivemanage Dashboard.
- In the navigation menu, select API Keys.
- Click Create Token.
- Enter any name for your token (e.g., "Bodycam Videos").
- Set the Token Type to Videos Only.
- Click Create and copy your new API token.
Add Fivemanage API Key and Configuration to config_server.lua
Add the Fivemanage API Key to your config_server.lua:
Fivemanage = {
ApiUrl = 'https://api.fivemanage.com/api',
ApiKey = 'replace_with_your_api_key', -- HERE
OnlyShowDepartmentRecordings = true,
DepartmentFolderPaths = {
['police'] = '/police',
},
}Set Provider to Fivemanage in config_server.lua
In config_server.lua, set the storage provider to fivemanage:
Storage = {
Provider = "fivemanage"
}Restart the Resource
Restart the script to apply the changes.
Cloudflare R2 Setup
To use Cloudflare R2, configure both your Cloudflare credentials and storage provider.
Create or Select an R2 Bucket
Open the Cloudflare Dashboard and go to Storage & databases > R2 Object Storage. Create or use an existing bucket for bodycam recordings.
Generate API Credentials
Generate credentials and copy an Access Key ID + Secret Access Key.
- Go to the Cloudflare Dashboard.
- Select Storage & databases > R2 Object Storage > Overview.
- Select Manage next to API Tokens.
- Select Create Account API token or Create User API token.
- Choose Object Read & Write permission.
- Set Apply to specific buckets only and select your bucket.
- Select Create API Token.
- Copy the Access Key ID and Secret Access Key.
Add R2 Credentials to server.cfg
set R2_BUCKET "your_bucket_name"
set R2_ACCOUNT_ID "your_account_id"
set R2_ACCESS_KEY_ID "your_access_key_id"
set R2_SECRET_ACCESS_KEY "your_secret_access_key"Set Provider to R2 in config_server.lua
In config_server.lua, set the storage provider to r2:
Storage = {
Provider = "r2"
}Restart the Resource
Restart your server or restart the script to apply the changes.
If you decide to only restart the script, make sure to paste the four R2_* convars into the server console otherwise they will not be set.
Recording Time Limit: The maximum recording duration can be configured in Recording.RecordingLimit (default: 300 seconds).
Permissions Configuration
If you are using a framework (not standalone), you must configure the Permissions table to control access to bodycam and dashcam features:
Permissions = {
BodycamDashcam = {
Ace = 'BodycamDashcam',
Jobs = {
['police'] = 1
}
},
ViewCameras = {
Ace = 'BodycamDashcam',
Jobs = {
['police'] = 2
}
},
DeleteRecordings = {
Ace = 'BodycamDashcam',
Jobs = {
['police'] = 3
}
}
},BodycamDashcam: Allows the specified jobs to use bodycam & dashcam features.ViewCameras: Allows the specified jobs to view camera recordings.DeleteRecordings: Allows the specified jobs to delete recordings.
If you set ClientConfig.Framework to standalone, the script will ignore the Jobs table and instead require the Ace permission.
Storage Options
OnlyShowDepartmentRecordings: Ensures that players with a job can only see recordings from their own folder path set inDepartmentFolderPaths. For example, a player with thepolicejob will only be able to see recordings in the/policefolder.DepartmentFolderPaths: Specifies the folder where recordings for each job are saved. For example,['police'] = '/police'saves police recordings in the/policefolder. Leaving this table empty will save all recordings in the root directory.
Dashcam Configuration
The dashcam script is configurable via the ClientConfig.Dashcam section. Below are the key options and their explanations:
Prop
Type
Usage
Bodycam
- Toggle the bodycam overlay using the
/bodycamcommand. - Start recording by pressing the X or using the
/recordbodycamcommand. - The bodycam must be equipped and allowed for your job.
- If
ClientConfig.Bodycam.Battery.Enabledis true, battery drains based onDrainIntervalandDrainPercentageand the remaining percentage is shown in the Bodycam UI. - Recording uploads footage to your configured provider (
fivemanageorr2).
Dashcam
Use the /dashcamsetup command in-game to set up dashcam positions for vehicles. This command requires the DashcamSetup ace permission.
Viewing Dashcam
Drivers and passengers can press C to switch to their vehicle's dashcam view, if the vehicle is registered with a dashcam. See the next step for instructions on registering a dashcam.
Registering a Vehicle Dashcam
To integrate a dashcam into a vehicle, use the following export in your script:
exports['sx_bodycamdashcam']:registerVehicleDashcam(netId, {
jobName = player.PlayerData.job
})Make sure to replace player.PlayerData.job with your framework's player job name.
Prop
Type
Developers
Exports
Client exports
openCamerasTablet
Opens the Cameras tablet UI.
Returns true if the tablet was opened, false if the player is missing permissions.
local opened = exports.sx_bodycamdashcam:openCamerasTablet()
if not opened then
-- player does not have ViewCameras permission
endviewBodycamFeed
Starts viewing a specific bodycam feed.
Parameters
| Name | Type | Description |
|---|---|---|
bodycamId | number | The id field from getActiveBodycams(). |
local result = exports.sx_bodycamdashcam:viewBodycamFeed(1)
if not result then
-- e.g. show an error notification
endReturns false on failure (permission denied, bodycam not found, target ped not reachable) or a table on success.
| Name | Type | Description |
|---|---|---|
targetServerId | number | The server ID of the target player. |
targetPedCoords | vec3 | The coordinates of the target player. |
isRecording | boolean | Whether the target player is currently recording. |
{
targetServerId = 12,
targetPedCoords = vec3(0, 0, 0),
isRecording = false
}viewDashcamFeed
Starts viewing a vehicle's dashcam feed.
Parameters
| Name | Type | Description |
|---|---|---|
vehicleNetId | number | The network ID of the vehicle. |
local vehicleNetId = NetworkGetNetworkIdFromEntity(vehicleEntity)
local result = exports.sx_bodycamdashcam:viewDashcamFeed(vehicleNetId)
if not result then
-- e.g. show an error notification
endReturns false on failure (no dashcam on vehicle, permission denied, vehicle not found) or a table on success.
| Name | Type | Description |
|---|---|---|
dashcamId | number | Unique dashcam ID for this session. |
vehicleNetId | boolean | The network ID of the vehicle. |
vehicleCoords | vec3 | The coordinates of the target vehicle. |
{
dashcamId = 1,
vehicleNetId = 123,
vehicleCoords = vec3(0, 0, 0)
}Server exports
getActiveBodycams
Returns a list of currently active bodycams.
Returns table[].
| Field | Type | Description |
|---|---|---|
id | number | Unique bodycam ID for this session. |
targetServerId | number | The server ID of the player wearing the bodycam. |
officerName | string | The player's in-game name. |
coords | vector3 | Last known coordinates of the officer. |
status | string | "live" or "recording". |
jobName | string | The job or department name of the officer. |
sessionStartedAt | number | Unix timestamp when the bodycam was activated. |
location | string | Last known area or zone name. |
street | string | Last known street name. |
local bodycams = exports.sx_bodycamdashcam:getActiveBodycams()
for _, cam in ipairs(bodycams) do
print(cam.officerName, cam.status, cam.coords)
endisBodycamActive
Returns whether a specific player currently has an active bodycam.
Parameters
| Name | Type | Description |
|---|---|---|
source | number | The server ID of the player. |
Returns boolean
local isActive = exports.sx_bodycamdashcam:isBodycamActive(source)isPlayerRecording
Returns whether a specific player is currently recording their bodycam.
Parameters
| Name | Type | Description |
|---|---|---|
source | number | The server ID of the player. |
Returns boolean
local isRecording = exports.sx_bodycamdashcam:isPlayerRecording(source)
if isRecording then
-- player is actively recording right now
endgetActiveDashcams
Returns a list of currently registered dashcams.
Returns table[].
| Field | Type | Description |
|---|---|---|
id | number | Unique dashcam ID for this session. |
vehicleNetId | number | Network ID of the vehicle. |
jobName | string | The job or department that owns this dashcam. |
local dashcams = exports.sx_bodycamdashcam:getActiveDashcams()
for _, cam in ipairs(dashcams) do
print(cam.vehicleNetId, cam.jobName)
endgetRecordings
Fetches a paginated list of recordings from the configured storage backend (fivemanage or r2).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number. |
limit | number | 20 | Max results per page. |
path | string|nil | nil | Optional folder path filter (for example, "police/"). |
local recordings = exports.sx_bodycamdashcam:getRecordings(1, 20, 'police/')
if not recordings then
return
end
for _, rec in ipairs(recordings.data) do
print(rec.name, rec.url)
endReturns table[] or nil on error.
| Field | Type | Description |
|---|---|---|
id | number | Unique recording ID . |
url | string | The recording URL. |
size | number | The recording size. |
metadata | table | Meta data of the recording. |
createdAt | string | Unix timestamp when the recording has been uploaded. |
Guides
Troubleshooting
- Ensure ox_lib is installed and started before sx_bodycamdashcam. Click here
- Make sure you have the correct ace permissions for the Bodycam & Dashcam. Click here
Theming
Add colors. Make it yours.
Five Emergency
Five Emergency is an advanced online police simulation for FiveM that offers a fully immersive law enforcement experience. Players take on the role of police officers and interact with a wide range of in-game systems designed to simulate real-life police duties.