Statbotics: The FRC Analytics Engine That Turns Robot Chaos Into Points
How one open-source stack combines Skew-Normal modeling, game-aware heuristics, and a public API to make FIRST Robotics Competition scouting more predictive, readable, and useful.
- Statbotics matters because it translates FRC from an alliance sport into a point-based language scouts can act on.
- EPA is the product, not just the model, because it keeps prediction readable while preserving game-specific nuance.
- The system is game-aware by design, so yearly rule changes and skewed performance distributions change the math instead of breaking it.
- The repo behaves like public infrastructure, with an API, a web app, and a data pipeline that turns match history into usable signals.
Statbotics is not trying to be a prettier leaderboard. It is trying to solve a harder problem: how do you measure a robot team’s real contribution when every match is a 3-vs-3 pileup of strategy, drivetrain quirks, and alliance luck?
My goal with Statbotics is to share FRC data and analysis with a wider audience. Hopefully this page will help you better understand the EPA (Expected Points Added) model, its advantages and disadvantages, and how to best use it.
The Point of Statbotics
FRC scouting has a basic problem. A team’s contribution is hidden inside alliance performance, and the scoreboard does not tell you who caused what. Statbotics answers that by expressing value in Expected Points Added, a metric that speaks the same language as the game itself.
That is the key move. Instead of forcing teams to translate an opaque rating back into reality, Statbotics gives them something directly useful for alliance selection, match prep, and event simulation.
EPA attempts to quantify a team's average point contribution to an FRC match. EPA builds upon concepts from the Elo rating system, but the units are in points and can be interpreted more analogously to a team's OPR.
EPA Is the Real Product
EPA is where Statbotics separates itself from generic rating systems. Elo is useful, but it is abstract. EPA keeps the predictive logic while grounding the output in points, which makes it easier to explain, compare, and split into autonomous, teleop, and endgame contributions.
This is the surprise inside the project. Statbotics is not just ranking teams. It is turning noisy match outcomes into a model that scouts can trust because it behaves like the game they already understand.
Why the Model Is Game-Aware, Not Generic
The code does not pretend every FRC season works the same way. The backend includes year-specific breakdown logic, so the model can account for different scoring systems, asymmetric distributions, and oddball mechanics that make one season nothing like the next.
# Conceptual sketch of the year-aware flow
match_data = fetch_tba_matches(year)
avgs = calc_averages(match_data)
wins = calc_wins(match_data)
epa = calc_epa(match_data, year_specific_rules=True)
write_to_db(epa)
# The key idea: the model changes with the game, not against it.
That matters because a generic algorithm can be elegant and wrong. Statbotics earns credibility by admitting the sport is messy, then encoding that mess into the model instead of smoothing it away.
From Match Data to Updated Ratings
The pipeline is cleanly staged. TBA sync comes first, then averages and wins, then EPA calculation, then database writes. That sounds ordinary until you notice the system treats rating computation as a dependency chain, not a loose batch script.
| Stage | What it does | Why it matters |
|---|---|---|
| TBA sync | Pulls raw match and event data | Keeps the system grounded in the official record |
| Averages and wins | Builds baseline summaries | Creates the inputs the model needs before scoring |
| EPA calculation | Updates point-based ratings | Turns raw results into predictive value |
| DB write | Stores the output for the web app and API | Makes the result queryable and reusable |
The Stack Behind the Signals
The repository is a small monorepo with clear responsibilities: a Python backend for modeling and ingestion, a TypeScript frontend for the site and client surface, and CockroachDB underneath. FastAPI handles the API, Next.js handles the web app, and the Python side does the statistical heavy lifting.
There are also signs of care that matter in production. Profiling middleware suggests the backend is performance-aware, and memory-conscious patterns like `__slots__` show the code is designed to process a lot of match records without getting sloppy.
Why Teams Use This Instead of OPR or Plain Elo
Statbotics lives in a very specific niche. It is more interpretable than Elo, more model-driven than OPR, and more operational than spreadsheet scouting. That is why it has staying power: it gives teams a metric they can act on without translating it three times first.
| System | Output | Early-season stability | Game-aware | Productized |
|---|---|---|---|---|
| Statbotics EPA | Points | High | Yes | Yes |
| Traditional Elo | Rating points | Medium | Usually no | Sometimes |
| OPR | Points | Lower | Limited | Usually no |
| Spreadsheet scouting | Human notes | Depends on the scout | Yes, manually | No |
The real comparison is not between formulas. It is between ways of making decisions under uncertainty. Statbotics wins when a team needs a number that is both predictive and legible.
A Small Team Building Public Infrastructure
This project has the feel of infrastructure, even if the team behind it is small. It offers a public API, a web app, Python tooling, event simulations, and CSV exports. That is a lot of surface area for one codebase, and it explains why the repo reads less like a prototype and more like a maintained service.
That maturity is the point. Statbotics is not just a useful FRC tool. It is a durable layer for a niche community that needs better shared language around performance, and it has turned that need into a working system.





