How Xon Sight fits together
Xon Sight is four pieces working together: a bodycam app that captures and uploads footage in-game, this website that stores and reviews it, and two ways to reach the website without leaving the game - an in-hand tablet prop and an LB Phone app. This page covers what each one does and how they talk to each other. For the webhook wire format, see the API reference instead.
Overview
Nothing here gives a website a live video feed - Xon Sight (the in-game resource) has no documented way to stream actual camera frames out of the game. What moves between the pieces below is: finished clips (uploaded after the fact), a schematic position feed ("who's recording and roughly where"), and the portal's own pages, which the tablet and phone app simply display in a window rather than rebuilding.
Architecture
The portal is the only piece holding data - the tablet and phone app are just windows onto it, so there's nothing to keep in sync between them. Xon Sight doesn't require OPS Phone specifically - its webhook is generic, so the LB Phone app above can submit evidence straight from LB Phone's own camera too, alongside (or instead of) a dedicated bodycam resource.
Multiple servers, one portal
One Xon Sight deployment can host more than one FiveM server, each in its own dedicated MySQL database - nobody's evidence, live roster, or alerts end up in anyone else's. Each of these communities gets its own API token; point your bodycam script at that token instead of the shared webhook key and everything it sends lands in that community's own database from then on.
Get started
to sign up yourself - name your community and you're the first admin - or ask an existing
deployment's operator to create one for you from Admin → Communities. Either way,
Xon Sight provisions a fresh MySQL database and user for it on the spot and shows its API token
once (it's only ever masked after that).
xonsight-lbphone / xonsight-livesync: config.lua →
Config.CommunityToken. opslabs-bodycam: config_server.lua
→ ServerConfig.XonSight.Token (support for sending it as
X-XonSight-Token is still on opslabs-bodycam's side to ship - use the shared webhook
key there for now). Set it instead of (not alongside) the existing shared key field - whichever
resources that server runs will send X-XonSight-Token from then on, and the portal
routes every evidence upload, live-roster sync, and alert from that token into the matching
community's database automatically.
A self-signed-up community's admin lands on /integration after creating it - the
token, setup steps, and a regenerate button all live there, reachable again any time from the
account menu.
Scope today: only Dashboard/Evidence/Live are tenant-aware. Cases, the Assistant, the public
Community tip line, Analytics, and Admin itself still run against this portal's own original
database regardless of which community you're on - a deliberate, incremental rollout rather than a
half-migrated everything-at-once. A self-signed-up community's admin sees their own tenant data as
soon as they're logged in, on this same primary URL - dedicated subdomains
(<slug>.opslabsystems.cloud) work too once the operator points a wildcard DNS
record here, but aren't required to get started.
Components
OPS Phone · a bodycam
Xon Sight's webhook contract is generic - it doesn't require OPS Phone or any other specific resource, it just needs something to POST evidence to it. OPS Phone is the reference bodycam implementation this portal was built against: a bodycam app on an officer's in-game phone. When they stop recording, the finished clip uploads to wherever LB Phone's camera upload is configured to put it (Fivemanage, S3, etc. - this site never touches the raw video), and a webhook tells the portal the clip exists, who submitted it, and a caption. The LB Phone App below can submit evidence the same way, straight from LB Phone's own camera, if you'd rather not run a separate bodycam resource at all.
- Sends the device serial automatically, so the Evidence viewer's Metadata tab fills itself in
- Fires an alert (shots fired, weapon drawn) the instant it happens - raises the banner on the Live page
-
Pushes the live roster on start/stop, not just on a timer - a new recorder shows up on
/livewithin ~1s - Optional chest-mounted camera mode for a true body-worn-camera angle instead of free-look
The Portal · this website
Everything OPS Phone sends lands here. It's the one place all of it gets reviewed, organized, and searched - the tablet and phone app don't have their own separate view of this data, they just open these same pages. Everything below needs a staff login except the public tip line.
/dashboard
Recent submissions and a quick count of what's active, at a glance.
/evidence
Every clip, with a frame-stepping player, markers, clips-within-clips, and a transcript tab.
/live
Who's recording right now and their last known position on a schematic map.
/cases
Group evidence under a status (open / under review / closed) with an audit trail.
/community
The public tip line and per-case request links - no account needed on their end.
/assistant
AI-drafted report narratives, footage summaries, and BOLOs.
/analytics
Submission volume, alert types, case status, top submitting officers.
/admin/*
Users, communities, Discord notifications, and the audit log.
In-game Tablet · held prop
A stock in-game prop an officer holds and reads from without tabbing out of GTA. It's the real portal in a window, not a reimplementation of it.
-
Stock GTA prop (
prop_cs_tablet) - no custom model to source or stream in -
Opens on a configurable key (
F6by default); closes with the same key, the on-screen ×, or Esc - Logs in once and stays logged in between uses, same as a normal browser tab
LB Phone App · installable app, viewer + capture
Installed as a proper app icon on an officer's LB Phone - open it from the home screen like any other app. It's the only piece that's two things at once: a viewer onto the portal, and - with a tap of its "Record evidence" button - an independent way to submit evidence too, using LB Phone's own camera. Third-party phone frameworks work with Xon Sight through this same path: nothing about the webhook cares what recorded the footage.
- Records video with LB Phone's camera and posts it straight to the evidence webhook - no bodycam resource required
-
The webhook key stays server-side (
server.lua) - never exposed to the NUI/browser layer -
Capture can be turned off (
Config.AllowCapture = false) to ship this as a viewer-only app instead -
Registers itself via lb-phone's own
AddCustomAppexport - nothing to edit in lb-phone's config - Free, paid, or installed on every phone automatically - your choice per server
- Same persistent login as the tablet, inside the phone's own NUI browser
Requirements
Xon Sight can host the portal for you - there's nothing to deploy, patch, or keep online yourself. With a hosted portal, the only real requirement is the FiveM side: a server to add resources to, and something sending it evidence over its webhook - OPS Phone is the reference implementation, but it's not mandatory; the LB Phone app can submit evidence directly from LB Phone's own camera instead. Self-hosting the portal instead is supported too, if you'd rather run your own.
- A FiveM server you can add resources to
-
One evidence source speaking Xon Sight's webhook contract - OPS Phone /
opslabs-bodycamis the reference one, but not mandatory -
...or just
xonsight-lbphonewithConfig.AllowCaptureon - it can be that evidence source by itself, via LB Phone's own camera -
lb-phonealready installed and running - only if you wantxonsight-lbphone -
xonsight-tabletandxonsight-livesyncneed nothing extra - stock GTA assets only, no other resource dependency - Every piece just needs the portal's URL and (for the webhook-speaking ones) its key - nothing else to provision
- Nothing to install - you get a portal URL and a webhook key, ready to point OPS Phone at
- Uptime, backups, and updates are handled for you
-
Python 3.10+ and the packages in
requirements.txt(Flask, SQLAlchemy, Flask-Login, Flask-Limiter, Flask-WTF, PyMySQL, gunicorn) -
A database - SQLite works with zero setup (default if
DATABASE_URLis blank); MySQL only for multi-tenancy -
A reverse proxy (nginx or similar) with TLS - session cookies are hardcoded
Secure, so logins silently won't work over plain HTTP -
SECRET_KEYandXONSIGHT_WEBHOOK_KEYset in.envat minimum - see.env.examplefor the full list -
Optional:
ANTHROPIC_API_KEY(Assistant), hCaptcha keys (Community form), a Discord webhook URL (notifications)
Self-hosting behind multiple gunicorn workers? Point RATELIMIT_STORAGE_URI at a shared
backend (e.g. redis://...) - the default in-memory limiter counts per worker, not per
actual visitor, once you're past a single process.
Setting it up
Each in-game piece is an independent FiveM resource - install whichever ones your server actually uses.
OPS Phone / opslabs-bodycam is the reference bodycam, but the only real requirement is something posting to the webhook - xonsight-lbphone with capture enabled can be that on its own, no separate bodycam resource needed.
xonsight-livesync · optionalPushes the active-recorder roster so the Live page shows more than "no active recorders." Only meaningful alongside a bodycam resource that exposes a roster, like OPS Phone.
xonsight-tablet and/or xonsight-lbphone · optionalEither or both, depending on whether officers should reach the portal via a held prop, an LB Phone app, or neither - the website works fine on its own in a browser tab.
Each resource ships with its own README.md and config.lua covering exactly
what to edit (mainly the portal's URL, and either the shared webhook key or a
per-community token if this portal
hosts more than one server). See the
API reference for the
wire format if you're writing your own bridge instead of using the ones above.