The capstone
The advanced techniques only pay off if they run reliably at event pace. This lesson lays out the whole pipeline: scouting data goes in, public API data gets joined to it, validated metrics come out, and the whole thing rebuilds with one command between match cycles.
Architecture
Keep the stages decoupled so that any one of them can be debugged or replaced.
- Ingest. Scanned QRScout rows append to a
rawsource, either a Google Sheet or a CSV. Append rows only, and never edit one in place. - Enrich. A script pulls TBA (
event_matches,event_oprs,event_rankings) and Statbotics (get_team_event) for the event, keyed by team number. - Compute. Join the scouting averages with OPR and EPA, then compute your custom metrics (per-level coral rates, endgame reliability, defense rating) along with validation flags.
- Output. A
ranktable and per-match prep sheets, regenerated on demand.
A concrete skeleton
import pandas as pd, tbapy, statbotics
EVENT = '2025cc'
tba = tbapy.TBA('YOUR_TBA_KEY')
sb = statbotics.Statbotics()
# 1. Ingest scouting (exported from your QRScout sheet)
raw = pd.read_csv('scouting_raw.csv')
agg = raw.groupby('teamNumber').mean(numeric_only=True)
# 2/3. Enrich with public analytics
oprs = tba.event_oprs(EVENT)['oprs'] # {'frc254': 78.3, ...}
agg['opr'] = [oprs.get(f'frc{t}') for t in agg.index]
agg['epa'] = [ sb.get_team_event(int(t), EVENT).get('epa', {}).get('unitless')
for t in agg.index ] # EPA at this event
# 4. Validation flags
agg['low_sample'] = raw.groupby('teamNumber').size() < 3
agg['scout_vs_opr_gap'] = (agg['ptsContributed'] - agg['opr']).abs()
agg.sort_values('ptsContributed', ascending=False).to_csv('rank.csv')
Use the Statbotics fields parameter and the TBA simple/keys options to keep responses small and fast. Sending the TBA ETag back as If-None-Match also means a repeated refresh returns a cheap 304 Not Modified.
Make it reliable at event pace
- One command, and idempotent. Running the pipeline twice gives the same result, so you can rebuild anytime without manual cleanup.
- Fail loud on validation. If
low_sampleorscout_vs_opr_gapis high for a top team, surface it so you can send a super-scout, instead of silently ranking on thin data. - Cache API calls. Store the TBA and Statbotics responses locally on each refresh, so a flaky venue connection or a rate limit does not block your rebuild. QR scouting already works offline, so your analysis should degrade gracefully too.
- Keep a manual fallback. If the script breaks mid-event, the
aggspreadsheet alone (from the Worked Examples module) still produces a usable ranking. Never let the fancy pipeline be a single point of failure.
What you have built
Put together with the earlier modules, this is a complete and defensible scouting operation: offline-first collection, measured scout accuracy, validated custom metrics, cross-checks against public analytics, predictive what-ifs, explicit defense evaluation, and a one-command rebuild that feeds picklists and pre-match briefs.
Key takeaways
- Decouple the pipeline into ingest (append-only) -> enrich (TBA + Statbotics) -> compute (custom metrics + validation) -> output (rank + briefs).
- Make rebuilds idempotent and one-command, cache API calls, and fail loud on low-sample or scouting-vs-OPR gaps to trigger super-scouts.
- Always keep a manual spreadsheet fallback so the automated pipeline is never a single point of failure at an event.
You've reached the end of this track
Take the quiz · +10 XP with an accountSources & corrections
This lesson is AI-assisted: drafted from primary sources, then reviewed and edited by hand. Errors still get through. When one is reported we fix it and write down what changed — publicly, in the corrections log.
Sources and further reading
- tbapy - Python wrapper for The Blue Alliancegithub.com
- Statbotics Python API (get_team_event, fields)github.com
- Tech Talk: Efficiently Querying the TBA API (ETag/If-None-Match)blog.thebluealliance.com
Read next
Articles on this, for competition day
The lesson covers how it works. These cover what to do when it breaks.
- 20 min read
Building an FRC Scouting App: Data Model, TBA/Statbotics APIs, and Picklists
Build an FRC scouting app: match and pit scouting, a simple data model, pulling schedules and EPA from the TBA and Statbotics APIs, and building a picklist.
Read - 18 min read
The Blue Alliance (TBA): How to Use FRC's Match & Team Database
The Blue Alliance (TBA) is FRC's free match and team database. Navigate team, event, and match pages, set up myTBA notifications, and use its read API.
Read - 4 min read
FRC Scouting Guide: How to Scout and Build a Picklist
Learn how FRC scouting works, what OPR and EPA actually measure, and how to turn match data into a ranked picklist for alliance selection.
Read
Lesson quiz
RequiredAll 5 right completes the lesson. Miss one and only that question comes back — anything you already answered correctly stays banked.
0 of 5 answered
01.Which sequence describes the decoupled stages of an automated FRC scouting analysis pipeline?
02.How should the ingest stage treat the raw scouting source?
03.When low_sample or a large scout-vs-OPR gap appears for a top team, what should the pipeline do?
04.Why should TBA and Statbotics API responses be cached locally?
05.Why keep a manual spreadsheet fallback for the pipeline?
Answer every question to submit.
All 32 lessons in Scouting & Strategy
- Not started:Project 1: Configure a QRScout Form for REEFSCAPE
- Not started:Project 2: Compute OPR by Hand, Then in a Spreadsheet
- Not started:Project 3: Pull Live Data with the TBA and Statbotics APIs
- Not started:Project 4: Build an EPA-Component Robot Ranking Sheet
- Not started:Project 5: Assemble a One-Page Pre-Match Prep Sheet