Project 3: Pull Live Data with the TBA and Statbotics APIs
Write real Python that fetches an event's matches and OPRs from The Blue Alliance and EPA ratings from Statbotics, the foundation of any automated analysis.
Sign in to track progress, earn XP, and save lessons.
Goal
A short Python script that, given an event key, pulls (a) the qualification schedule and results from The Blue Alliance (TBA) and (b) Statbotics EPA ratings, so your analysis sheet can refresh itself instead of being retyped.
Get a TBA Read API key
Go to your TBA account dashboard and generate a key under Read API Keys. Every direct request to the base URL https://www.thebluealliance.com/api/v3 must include the header X-TBA-Auth-Key. Event keys look like 2025cc (the 2025 Chezy Champs off-season event; the event code is the part after the year in the event URL, e.g. thebluealliance.com/event/2025cc).
TBA with the tbapy wrapper
pip3 install tbapy
import tbapy
tba = tbapy.TBA('YOUR_TBA_KEY')
event = '2025cc'
# Every match at the event (objects with alliances + score_breakdown)
matches = tba.event_matches(event)
# OPR / DPR / CCWM that TBA already computed
oprs = tba.event_oprs(event) # dict with 'oprs', 'dprs', 'ccwms'
rankings = tba.event_rankings(event) # qualification ranking + RP
for m in matches:
if m['comp_level'] != 'qm':
continue
red = m['alliances']['red']['team_keys'] # e.g. ['frc254','frc1678','frc2713']
red_score = m['alliances']['red']['score']
print(m['key'], red, red_score)
The score_breakdown on each match is gold: for REEFSCAPE it splits out auto vs teleop coral counts by level, algae, and barge points, which you can feed straight into component OPR (Project 2).
Statbotics for EPA
EPA (Expected Points Added) is Statbotics' rating; it was built to replace OPR/Elo and is designed to be predictive, expressed in point units, and split into auto/teleop/endgame component EPAs.
pip install statbotics==3.0.0
import statbotics
sb = statbotics.Statbotics()
print(sb.get_team(254)) # team profile incl. EPA summary
print(sb.get_team_year(254, 2025)) # one team's 2025 EPA
ty = sb.get_team_event(254, '2025cc') # EPA at a specific event
ms = sb.get_matches(team=254, year=2025) # match-level EPA records
Use the fields parameter (e.g. sb.get_team(254, fields=['team','norm_epa'])) to request only what you need so responses stay small.
Putting it together
A practical pattern: pull TBA event_rankings for ranking-point standings, TBA event_oprs for a no-scouting power baseline, and Statbotics get_team_event for predictive EPA, then join all three on team number in a DataFrame. When TBA OPR and Statbotics EPA agree with your own scouting averages, you have high confidence; when they disagree, that team is worth a super-scout's eyes. Cache responses (TBA returns an ETag; send it back as If-None-Match to get a cheap 304 Not Modified) so you are polite to the API and fast on refresh.
Key takeaways
- TBA requires the X-TBA-Auth-Key header; tbapy wraps event_matches, event_oprs, and event_rankings into one-line calls.
- TBA score_breakdown gives per-phase REEFSCAPE counts (auto vs teleop coral by level) you can feed into component OPR.
- Statbotics v3 (pip install statbotics==3.0.0) exposes get_team, get_team_year, get_team_event, and get_matches for predictive EPA with auto/teleop/endgame components.
Go deeper
Lesson quiz
RequiredAnswer all 3 questions correctly to complete this lesson.
1.How do you authenticate a request to The Blue Alliance Read API v3?
2.Which correctly describes the TBA API v3 base URL and request style?
3.Compared with TBA, what is distinctive about pulling team data from the Statbotics Python API?
Answer every question to submit.