Devices & Reports
On this page8
Three devices, one battery, one paper. Item names and definitions: Items. The voice changer has its own page: Voice & Voice Changer.
Hidden camera
A camera worn on the clothes. While it is on, scans run faster, the memory lasts far longer, and the camera keeps a recording that you can print as a paper report from the F3 menu.
| Key | Default | Allowed | What it does |
|---|---|---|---|
BatterySeconds | 1800 (30 min) | seconds | Recording time per full battery. |
SpeedMultiplier | 2.0 | 1.0–4.0 | Scan speed while the camera is on. |
MinOnShare | 0.5 | 0.0–1.0 | Share of the look the camera must have been on. Below it the result is no camera memory, and the recording cannot be printed ("camera on too short"). |
Photo | true | true / false | Try to add a photo of the person to the report. Needs Config.ScreenshotSystem. |
PhotoWindowSeconds | 5 | seconds | How long to wait for the person to be on screen for the photo. |
PrintReport | true | true / false | Keep a printable recording when a camera look ends. false = finished looks leave no recording (the 30-day camera memory still works). |
ReportPairCooldownMinutes | 30 | minutes | One recording per camera owner and person in this time. A new look at the same person shows "(printed recently)". |
ReportOnWeakScans | false | true / false | Also keep recordings of looks that ended below Config.Scan.MinSavePct. |
SkipEmote | true | true / false | Skip the thinking pose while your own camera is on — camera scans are silent. |
CheckpointPct | 10 | 1–50 | Save the battery level to the database every N % of drain. |
FailedRecognitionMemory | 'none' | 'none' · 'camera' | See below. |
A camera scan also extends the learning range: Config.Scan.CameraDistance (7 m)
instead of the usual 5 m.
Printing camera recordings
No paper drops into your pockets by itself. A camera recording waits in the F3 menu until you print it.
- Switch the hidden camera on (use the item). While it records, the HUD shows
REC with the camera's own % next to it, for example REC 25%. The number
turns green at
Config.Scan.MinSavePct(50 %): from then on the recording can be printed. - Press F3 → Camera recordings. The list shows your recordings of the last 24 hours, newest first, without names — only the scene line, for example "Saw him on camera on Vinewood Blvd in the evening". Looks that are still running are at the top as Recording now · n%.
- Choose one with UP / DOWN and press Enter. A 3-second Printing... bar runs and you get the paper. Each recording prints once.

You do not have to stop the look or walk away: a look that is still running can be printed as soon as the camera has seen 50 %. The look keeps running after the print, and its end does not make a second paper.
Gray rows in the list (the list refreshes by itself every few seconds):
| Row | Means |
|---|---|
| Recording now · 25% (needs 50%) | The camera has not seen enough yet. Keep the person in view. |
| (camera on too short) | The camera was off for too much of this look (MinOnShare). |
| (printed recently) | You already have a recording of this person from the last ReportPairCooldownMinutes. |
What players can see:
| Message | When |
|---|---|
| Camera recording saved. Print it from the Recognition menu (Camera recordings). | A camera look ended with a recording. |
| The camera saw only 25% - not enough for a recording (needs 50%). | A camera look ended below 50 %. |
| You need your hidden camera with you to print. | The hidden camera is not in the inventory. |
| No room for the report. You will get it when you have space. | The inventory is full; the paper waits (Config.Report.PendingMax). |
F3 → Stop looking ends every scan and quiet look at once, the camera look included. What the camera saw up to then is kept as usual.
Player view of the whole flow: Hidden Camera & Reports.
FailedRecognitionMemory
A recognise scan that stayed below the act line — the person is in a look you already know, and you still did not place them:
| Value | Behaviour |
|---|---|
'none' (default) | Your memory stays as it is. |
'camera' | Also write or refresh a 30-day camera memory of the look recorded now. |
A disguised person is no longer this case: that scan is a stranger scan and lands on the disguise memory it matches best, or starts a new one. See Memory & Familiarity.
Magnetic scanner
A hand wand that beeps near hidden electronics on people around you.
| Key | Default | Allowed | What it does |
|---|---|---|---|
Radius | 2.0 | metres | Area searched around the user. |
SweepSeconds | 4 | seconds | Length of one sweep. |
DetectCarriedOff | true | true / false | A camera that is carried but switched off gives a weak signal. |
DetectVoiceChanger | 'off' | 'off' · 'on' · 'carried' | Whether voice changers are detected at all. on = only while active. carried = active or not. |
SampleMs | 500 | ms | Time between samples during a sweep. |
CooldownSeconds | 10 | seconds | Before the same player can sweep again. |
MaxMoveMeters | 1.5 | metres | How far the user may move during a sweep before it stops. |
Beeps use GTA frontend sounds:
Sounds = {
weak = { name = 'Beep_Red', set = 'DLC_HEIST_HACKING_SNAKE_SOUNDS', count = 1 },
strong = { name = 'Beep_Red', set = 'DLC_HEIST_HACKING_SNAKE_SOUNDS', count = 3 },
}Device housekeeping
| Key | Default | Allowed | What it does |
|---|---|---|---|
Config.Devices.PresenceCheckSeconds | 5 | seconds | How often an active device is re-checked as still being in the player's inventory. |
Config.Devices.TurnOffOnDown | false | true / false | Switch devices off when the wearer goes down. |
Police jobs
Who counts as police decides who gets a memory from a camera report, who can be sent statements, and who sees the "possible match" hint line.
| Key | Default | Allowed | What it does |
|---|---|---|---|
Config.Jobs.Police | { 'police' } | your job names | Jobs that count as police (add your sheriff or FIB jobs here). |
Config.Jobs.RequireDuty | true | true / false | Must be on duty to count as police. |
Config.Jobs.HintJobs | { 'police' } | your job names, or {} | The only jobs that see the "possible match" hint after a scan. {} turns the hint off for everyone. |
Config.Jobs.HintRequireDuty | false | true / false | The hint job must be on duty as well. |
Config.Jobs.AcceptTypes | { 'leo' } | list of type names, or {} | A job whose framework type is in this list satisfies Police and HintJobs too. qb and qbx report a type. |
Both lists ship with 'police' only, because that is the one police job stock QBCore,
Qbox and ESX all have. config.lua keeps a commented example line under each list.
Remove the -- to use it, or type your own departments:
Police = { 'police' },
-- Police = { 'police', 'sheriff', 'fib' }, -- example: add your other departmentsrecognition:selftest checks both lists against your framework's jobs:
| Result | When |
|---|---|
PASS jobs.police | Every listed job exists. |
WARN jobs.police | A job in Police or HintJobs does not exist on your server. The line names it. An unknown job never matches anyone, so it breaks nothing. Remove it or create the job. Also a WARN when none of the Police jobs exists but jobs of a type in AcceptTypes do (for example lspd and bcso with type leo): those jobs are police, and the line names them. |
FAIL jobs.police | Config.Jobs.Police is empty, or not one of its jobs exists and no job gets in through AcceptTypes either (the list is empty, or no job on your server has one of its types). Police features cannot work then. |
SKIP jobs.police | Your framework (ox_core, standalone or custom) cannot say whether a job exists, so the names were not checked. On standalone and custom, who is police comes from Hooks.GetCustomJob in bridge/hooks.lua. |
Names are compared the way the police check compares them: upper and lower case do
not matter, so 'Police' is the police job. When a row is a WARN and nothing
failed, the last line reads self-test: no check failed (1 warning(s), see above).
Camera reports
| Key | Default | Allowed | What it does |
|---|---|---|---|
Config.Report.PoliceCap | 60 | 1–100 | Police who read a camera report get a memory of that person capped at this %. |
Config.Report.PoliceSeconds | 604800 (7 days) | seconds | How long that police memory lasts. |
Config.Report.KeepDays | 60 | days | How long a report stays readable. After that the paper turns blank. |
Config.Report.PushToMDT | true | true / false | Also send camera reports to the MDT where one is supported. |
Config.Report.MDTOnlyForPolice | true | true / false | Only camera owners with a police job push to the MDT. |
Config.Report.ShowPhoto | true | true / false | Show the photo on the paper when one exists. |
Config.Report.PendingMax | 5 | count | Papers held back per character when the inventory is full. |
Config.Report.GiveDistance | 2.5 | metres | Range of "hand over paper" on inventories without item metadata. |
MDT options
Used only by the MDT selected in Config.MDTSystem. Names are case-sensitive.
Config.MDT = {
['lb-tablet'] = { Mdt = 'Police', TabId = 'reports', TextFieldId = 'description' },
['tk_mdt'] = { Page = 'police' },
['redutzu-mdt'] = {},
['drx_mdt'] = {},
['origen_police'] = { Job = 'police' },
['wasabi_mdt'] = {},
}| MDT | Option | Must match |
|---|---|---|
lb-tablet | Mdt, TabId, TextFieldId | lb-tablet/config/mdts.json and your report tab's text field id. |
tk_mdt | Page | Its page name. |
origen_police | Job | Its job name. |
Per-MDT behaviour and what each one supports: Police, MDT & Evidence.
Inventory fallbacks
Not every inventory can store item metadata. Where one cannot, the script keeps the device identity in its own table and the item is just a token:
| Situation | What happens |
|---|---|
| Inventory with metadata (ox, qs, qb v2, jaksam, tgiann, ak47, origen, codem, core) | Serial, battery and report id ride on the item. Hand it over normally. |
| ESX default inventory, or any inventory without metadata | Device identity lives in recognition_devices, paper identity in recognition_reports. Use /recognition:handover <item> to give one to the person in front of you (within Config.Report.GiveDistance). |
| Standalone, no inventory at all | The script keeps the items. /recognition:items, /recognition:use <item>, /recognition:handover <item>. |
Introduce, describe, statements, mirror
These are not devices, but they share the paper item.
Introduce
| Key | Default | Allowed | What it does |
|---|---|---|---|
Config.Introduce.Enabled | true | true / false | Turn it on or off. |
.Distance | 3.0 | metres | Face to face. |
.MinLength / .MaxLength | 2 / 32 | characters | Name length. |
.PendingHours | 2 | hours | A name that could not be attached yet waits this long for the next scan. |
.SameEncounterOnly | true | true / false | A waiting name is dropped when the two part before a scan. |
.Mode | 'one' | 'one' · 'nearby' | Who hears it: the person you face, or everyone close who faces you. |
.NotifyListener | true | true / false | The listener gets a short line. |
.PairCooldownSeconds | 60 | seconds | Before the same person can introduce again to the same listener. |
.MaxPending | 32 | 1–256 | Most waiting names one listener can hold. Over the cap, their oldest is dropped. |
The picker
The small list of remembered people (labels only — no percentages, no timers) used by Describe and Statement.
| Key | Default | Allowed | What it does |
|---|---|---|---|
Config.Picker.TokenSeconds | 120 | seconds | How long the list stays valid. |
Config.Picker.MaxItems | 20 | count | The 20 most recently seen people, shown A–Z. |
Describe
Tell a friend what someone looked like. They get a weak memory — never enough to act.
| Key | Default | Allowed | What it does |
|---|---|---|---|
Config.Describe.Enabled | true | true / false | |
.Cap | 50 | 1–100 | Maximum % for the friend. Keep it below Config.Scoring.ActThreshold. |
.Seconds | 86400 (24 h) | seconds | How long it lasts. |
.Distance | 3.0 | metres | |
.AllowedSources | { 'memory', 'camera' } | 'memory' · 'camera' | Which of your memories can be passed on. Second-hand memories never can. |
.TalkSeconds | 8 | seconds | Talking before the description is given. |
.CooldownSeconds | 60 | seconds | Between two descriptions, counted from opening the list. |
.Hint | true | true / false | After any scan, show "Looks like someone you were told about" when a report or description fits. |
.HintMinPct | 25 | 1–100 | The hint shows from this %. It can never reach the act line. |
.HintPoliceOnly | true | true / false | The hint line only goes to Config.Jobs.HintJobs. false = everyone holding a report or a description sees it. |
Witness statements
| Key | Default | Allowed | What it does |
|---|---|---|---|
Config.Statement.Enabled | true | true / false | |
.AllowedSources | { 'memory', 'camera' } | as above | |
.Delivery | 'both' | 'paper' · 'mdt' · 'both' · 'choice' | Where the statement goes. choice = the player picks. |
.AllowAnonymous | true | true / false | The writer may stay anonymous, where the MDT can hide the author. |
.MaxNotes | 500 | characters | Free-text notes. |
.WriteSeconds | 10 | seconds | Writing time. |
.CooldownSeconds | 60 | seconds | Between two statements, from opening the list. |
.DetailPct | 60 | 1–100 | Cue % from which the paper gives full detail — colours, pattern codes. |
.MinCuePct | 25 | 1–100 | Below this %, a cue is written as "did not see clearly". |
.MDTZones | {} | { { coords = vector3(x,y,z), radius = 10.0 }, … } | Places from which the MDT copy can be sent. Empty = anywhere. |
.MdtPerDay | 5 | count | Most MDT copies per author per day. |
.MdtMaxAgeHours | 48 | hours | Only memories seen in the last 48 h can be sent to the MDT. |
Mirror check
| Key | Default | Allowed | What it does |
|---|---|---|---|
Config.Mirror.Enabled | true | true / false | |
.UseEmote | true | true / false | Play the mirror emote. Skipped in a vehicle. |
.LiveRefresh | true | true / false | Update the card while it is open when your look changes. |