Real-time web dashboard for Forza Motorsport. Receives UDP telemetry from the game and displays it in a browser: tachometer, G-force, tire temps, driver inputs, and lap timing.
docker build -t forza-telemetry .
docker run -p 3000:3000 -p 41234:41234/udp forza-telemetryOpen http://localhost:3000.
Requires Go and Node.js.
make runThis builds the frontend, embeds it into the Go binary, and starts the server.
- In-game, open Settings → HUD and Gameplay (FM8) or Settings → Gameplay & HUD (FH5)
- Scroll to the Data Out section and enable it
- Set Data Out IP Address to your machine's local IP
- Windows: run
ipconfigand look for your IPv4 address - Linux/macOS: run
ip aorifconfig
- Windows: run
- Set Data Out Port to
41234 - Set Data Out Packet Format to
Car Dash - Apply and start a session. The dashboard will show CONNECTED once packets arrive
When running via Docker, Forza must target the host machine's IP address, not
localhost.
| Variable | Default | Description |
|---|---|---|
API_PORT |
3000 |
HTTP and WebSocket port |
TELEMETRY_PORT |
41234 |
UDP port for incoming Forza data |
API_PORT=8080 TELEMETRY_PORT=41234 ./server- Lap times reset when you pause, rewind, or hit a loading screen. Forza zeroes out the timing fields during these, so whatever you had is gone.
The web/ and static/ directories are a bit unconventional. web/ is the Vue frontend, static/ is a Go package that just embeds the built output so the server can serve it as a single binary. It's not the cleanest setup but I wanted to keep everything in one repo without a separate deployment step, and this was the best approach I could come up with. Open to better ideas.
Run the Go server and Vite dev server separately for hot reload:
# terminal 1 - Go server (WebSocket + UDP)
go run ./cmd/server/
# terminal 2 - Vite dev server (http://localhost:5173)
cd web && npm run devVite proxies /ws to the Go server automatically.
