A local-first desktop companion app for Rocket League. Capture live match data, build your personal match history, and analyze your performance — no cloud, no accounts, no tracking.
After Psyonix disabled BakkesMod for online play with the EAC update, players lost their primary stats tracking tool. The new official Rocket League Stats API streams live match data locally — but there's no official app to consume it.
RL Stats fills that gap. It reads the local TCP stream from your game, parses every event, and gives you:
- Live Dashboard — Real-time player stats, scores, boost levels, and event feed during matches
- Match History — Every match you play, saved locally with full detail: goals, assists, saves, demos, ball hits
- Performance Analytics — Win rates, averages, trends, and streaks over days, weeks, months, and play sessions
- OBS Overlay Streaming — Built-in HTTP/WebSocket server for OBS Studio browser sources with live scoreboards, player stats, and event feeds
- Session Detection — Automatic grouping of consecutive matches into play sessions based on configurable time gaps
- Privacy First — All data stays on your PC. No accounts, no cloud, no telemetry.
| Layer | Technology |
|---|---|
| Desktop Shell | Tauri 2 (Rust) |
| Backend | Rust (tokio, rusqlite, serde, thiserror) |
| Frontend | React 19, TypeScript (strict), Vite |
| State | Zustand (global), TanStack Query (async) |
| Database | SQLite (WAL mode, r2d2 connection pooling) |
| Styling | Tailwind CSS v4, shadcn/ui primitives |
| Charts | Recharts |
| Icons | Lucide React |
| Testing | Vitest, React Testing Library, Playwright (E2E) |
| CI/CD | GitHub Actions (build, test, lint, release) |
The app includes a built-in HTTP/WebSocket server for streaming live match data to OBS Studio as browser source overlays.
| Overlay | URL | Description |
|---|---|---|
| Scoreboard | http://127.0.0.1:9528/overlays/scoreboard |
Live score, arena, timer, OT badge |
| Player Stats | http://127.0.0.1:9528/overlays/player-stats |
Blue/orange team panels with stats |
| Event Feed | http://127.0.0.1:9528/overlays/event-feed |
Goals, saves, demos in a live feed |
| All-in-One | http://127.0.0.1:9528/overlays/all-in-one |
Combined scoreboard + stats + events |
- Go to Settings > Streaming OBS and click Iniciar streaming
- Open OBS Studio and add a new Browser source
- Copy and paste one of the overlay URLs into the URL field
- Adjust width/height to match the overlay design
- Start Rocket League and play — the overlays update in real time
The server runs locally on 127.0.0.1. The default port is 9528 (configurable in settings). Make sure your local firewall allows connections to this port.
Developers can create custom OBS overlays using the included RL Overlay SDK:
<script src="http://127.0.0.1:9528/sdk/rl-overlay.js"></script>
<script>
const overlay = RLOverlay.connect({ port: 9528 });
overlay.on("state", (data) => {
console.log("Blue:", data.scoreBlue, "Orange:", data.scoreOrange);
});
</script>The SDK auto-detects the port from the page URL when loaded from the overlay server.
The app automatically groups consecutive matches into play sessions. A session is a sequence of matches where the gap between matches does not exceed a configurable threshold.
- Matches are ordered by start time and grouped when consecutive matches are played within the session gap (default: 30 minutes)
- If more than 30 minutes pass between matches, a new session starts
- The session gap can be configured in Settings > General
- Sessions are used in the Analytics page under the "Sesion" tab for per-session performance stats
- Windows 10 or 11 (the app is Windows-only for now)
- Rocket League installed on the same machine
- Rust toolchain (stable)
- Node.js 20+ with pnpm (recommended)
Prebuilt Windows installers are published on every tagged GitHub release.
- Go to GitHub Releases:
https://github.com/LucasSabena/rl-stats/releases - Download one of the Windows x64 artifacts:
*.msi- Recommended standard Windows installer*-setup.exe- NSIS installer*.zip- Portable bundle when available
Each release is expected to ship these assets:
RL Stats_<version>_x64_en-US.msiRL Stats_<version>_x64-setup.exelatest.jsonfor the Tauri updaterchecksums.txtwith SHA256 hashes
The project is open source, so source code, release notes, issues, and binary downloads all live in the same GitHub repository.
# Clone the repository
git clone https://github.com/LucasSabena/rl-stats.git
cd rl-stats
# Install dependencies
pnpm install
# Run in development mode (Vite dev server + Tauri)
pnpm tauri devpnpm tauri buildThe output will be in src-tauri/target/release/bundle/:
RL Stats_x.x.x_x64-setup.exe— NSIS installerRL Stats_x.x.x_x64_en-US.msi— MSI installer
The Rocket League Stats API must be enabled before the app can capture data. The API streams events locally on 127.0.0.1:49123.
- Go to your Rocket League config directory:
%USERPROFILE%\Documents\My Games\Rocket League\TAGame\Config\ - Open or create
TASystemSettings.ini - Add these lines under
[SystemSettings]:[SystemSettings] AllowPerFrameYield=False AllowPerFrameSleep=False bEnableReplayStatsAPI=True
- Save the file and restart Rocket League
The app will show a connection status indicator on the Live Dashboard page. If the API isn't enabled or the game isn't running, you will see a "Waiting for match..." state.
api-rocketleague/
├── src/ # React frontend (Vite + TypeScript)
│ ├── components/ # Reusable UI components
│ │ ├── live/ # Live match dashboard components
│ │ ├── history/ # Match history components
│ │ ├── analytics/ # Performance analytics components
│ │ ├── settings/ # Settings panel components
│ │ └── ui/ # Base UI primitives (shadcn)
│ ├── pages/ # Route-level pages
│ ├── hooks/ # Custom React hooks
│ ├── stores/ # Zustand state stores
│ ├── lib/ # Utilities, types, constants
│ └── styles/ # Tailwind + global styles
├── src-tauri/ # Rust backend (Tauri)
│ └── src/
│ ├── main.rs # Entry point
│ ├── core/ # Domain logic
│ │ ├── ingestor/ # TCP connection manager
│ │ ├── parser/ # Event parsing and validation
│ │ ├── models/ # Domain types and DTOs
│ │ ├── storage/ # SQLite persistence layer
│ │ ├── metrics/ # Derived metrics engine
│ │ ├── session/ # Match lifecycle & session grouping
│ │ ├── overlay/ # OBS overlay HTTP/WebSocket server
│ │ ├── settings/ # Configuration & RL INI helper
│ │ ├── tracker_api/ # Tracker Network API client
│ │ └── process_watcher/ # RL process detection
│ ├── commands/ # Tauri IPC command handlers
│ └── updater/ # Auto-update orchestration
├── src-tauri/overlays/ # Embedded overlay HTML/CSS/JS for OBS
├── docs/ # Project documentation
├── scripts/ # Build and release utilities
├── tests/ # End-to-end tests (Playwright)
└── .github/workflows/ # CI/CD pipeline definitions
The app follows a layered architecture with clear separation of concerns:
Rocket League ──TCP──► Ingestor ──► Parser ──► SessionManager ──► Storage (SQLite)
│ │
▼ ▼
Tauri Events OverlayServer
│ (OBS via HTTP/WS)
▼
Frontend (React/TS)
- Ingestor manages the TCP connection to
127.0.0.1:49123with reconnection and exponential backoff - Parser validates JSON and maps raw events to strongly-typed Rust structs
- SessionManager tracks match lifecycle (Waiting -> Active -> Finished) and drives both the frontend and overlay server
- OverlayServer broadcasts live state to OBS browser sources via WebSocket and REST endpoints
- Storage uses SQLite in WAL mode with connection pooling for concurrent reads
- Frontend communicates with the backend through type-safe Tauri commands
For a detailed breakdown of modules, database schema, and API surface, see the Architecture Document.
pnpm install # Install frontend dependencies
pnpm tauri dev # Start development server
pnpm tauri build # Production build
pnpm test # Run frontend unit tests (Vitest)
pnpm lint # Run ESLint
cd src-tauri && cargo test # Run Rust tests
cd src-tauri && cargo clippy # Run Rust linterContributions are welcome! Before submitting a PR, please:
- Read the Agent Guide for coding conventions and project rules
- Read the Design Document for the design system and component patterns
- Ensure all tests pass (
pnpm testandcargo test) - Run linting (
pnpm lintandcargo clippy) - Follow the commit conventions used in the project
See the Release Process for information about publishing new versions.
This repository is the canonical home for:
- source code
- issue tracking
- documentation
- release notes
- downloadable Windows installers
For end users, GitHub Releases is the main download page. If you publish a new version, make sure the MSI, NSIS installer, updater manifest, and checksums are attached.
| Document | Description |
|---|---|
| Product Requirements | User stories, features by version, success metrics |
| Architecture | System design, data flow, database schema, module breakdown |
| Design System | Color palette, typography, components, animations, accessibility |
| Security & Privacy | Threat model, privacy policy, operational security rules |
| Release Process | Version bumping, changelog, CI/CD, updater testing |
| Agent Guide | Coding conventions, project rules, key decisions |
The Rocket League Stats API does not provide:
- MMR / Rank / Division — The API streams in-match data only, not competitive rankings
- Historical match data — No access to Psyonix servers; the app only captures matches played while it's running
- Reliable playlist/mode detection — The API does not reliably report whether a match is Ranked, Casual, or an Extra Mode
- Distance traveled or total boost used — These are estimated as derived metrics (not directly provided by the API)
- Cross-platform support — Windows only in V1; macOS/Linux may be explored in the future
MIT © Lucas Sabena
See LICENSE for full text.
- Rocket League and Psyonix for the official Stats API
- rlstatsapi — Rust library reference for event parsing
- RocketLeagueStatsAPI — Python library reference for event schema
- Tauri — The framework that makes this app possible