Access College Football Play by Play Data
Overview
A utility to quickly obtain clean and tidy college football data. Serves as a wrapper around the https://collegefootballdata.com/ API and provides functions to access live play by play and box score data from ESPN https://www.espn.com when available. It provides users the capability to access a plethora of endpoints, and supplement that data with additional information (Expected Points Added/Win Probability added).
New release-dataset loaders (39 functions)
cfbfastR now loads every published CFB dataset on the
release repo, closing the gap with sportsdataverse-py's loader surface. All
loaders return cfbfastR_data-tagged tibbles, accept seasons = TRUE for the
full published range, and support the dbConnection/tablename database
write-through.
load_espn_cfb_*()— 27 loaders for the ESPN-derived family:pbp,schedules,team_box,player_box,drives,game_rosters,linescores,betting,play_participants,power_index,percentiles,passing,rushing,receiving,team_summaries,model_pbp, and the elevenadv_*advanced-stats datasets.
Show all changes in 3.0.0Hide the rest of the changes in 3.0.0
load_cfb_ratings(),load_cfb_ratings_weekly(),load_cfb_fpi_weekly(),load_cfb_team_summaries_weekly(),load_cfb_team_talent(),load_cfb_recruits(),load_cfb_recruiting_proj(),load_cfb_returning_production()— season/weekly ratings, talent, and recruiting datasets.load_cfb_schedule_crosswalk(),load_cfb_teams_crosswalk(),load_cfb_rosters_crosswalk()— CFBD/ESPN id crosswalks.load_ncaa_mfb_*()— 10 loaders for the stats.ncaa.org men's football family (covers FCS and lower divisions):pbp,pbp_cfbfastr(the cfbfastR-schema-shaped variant),drives,linescore,officials,player_stats,rosters,schedule,team_stats,teams.- New internal
parquet_from_url()helper backs the parquet-only datasets (requires the suggestedarrowpackage).
**Which play-by-play loader do I want?** Nothing is deprecated — the classic
functions are unchanged; the new families add sources:
load_cfb_pbp()(unchanged) — the classic cfbfastR EPA/WPA play-by-play, FBS 2014+.load_espn_cfb_pbp()(new) — the ESPN-derived play-by-play (469 columns, EPA/WPA + participant ids), 2004+.load_ncaa_mfb_pbp()(new) — stats.ncaa.org play-by-play incl. FCS and lower divisions, 2013+;load_ncaa_mfb_pbp_cfbfastr()is the same data reshaped onto cfbfastR pbp column conventions for cross-source binds.
This release adds a 65-function ESPN college-football API layer, expanding cfbfastR's ESPN surface from 8 wrappers to 73. The new wrappers expose ESPN's core-v2 endpoints in ESPN's own ID space — complementary to the CollegeFootballData (cfbd_*) wrappers, and the natural join partners for espn_cfb_pbp() / espn_cfb_scoreboard(). Every wrapper was verified live against the 2023, 2024, and 2025 seasons.
**Naming alignment with the sportsdataverse convention (this dev cycle, never on CRAN):** espn_cfb_player_statistics() is renamed to espn_cfb_player_career_stats() (the core-v2 /athletes/{id}/statistics career view, matching hoopR/wehoop/sportsdataverse-py). New espn_cfb_player_stats_v3() wraps the comprehensive web-common-v3 /athletes/{id}/stats payload (all categories, long format) — the _v3 companion to espn_cfb_player_stats() (core-v2 season statistics).
New Fox Sports API wrappers (fox_cfb_*)
A read-only Fox Sports "Bifrost" college-football layer (api.foxsports.com/bifrost/v1/cfb/*), complementary to the espn_cfb_* and cfbd_* families. Eight wrappers flatten Fox's layout-oriented JSON (sections → tables → rows → cells) into tidy cfbfastR-tagged tibbles. Reverse-engineering notes and an OpenAPI 3.1 spec live in the sdv-internal-refs repo. Verified live against the 2025 season.
fox_cfb_pbp()— game play-by-play (quarters → drives → plays), one row per play.fox_cfb_boxscore()— per-team player stat tables, tidy long (one row per player-stat).fox_cfb_odds()— matchup six-pack (spread / to-win / total) per team.fox_cfb_team_roster()— roster by position group, one row per player.fox_cfb_team_stats()— team stat leaders by category.fox_cfb_team_gamelog()— per-game team stats, tidy long (game × category × stat), each game keyed to its Fox event id.fox_cfb_standings()— a team's conference standings table.fox_cfb_league_leaders()— statistical leaderboards by category (stats-con).
New ESPN wrappers — football-specific metrics
espn_cfb_powerindex()— ESPN's College Football Power Index (FPI): every predictive metric and efficiency component, in long format.espn_cfb_qbr()— Total Quarterback Rating (QBR) and the full set of clutch-weighted EPA components, one row per qualified passer.espn_cfb_futures()— the season betting-futures board (national championship, conference, and award markets) with each sportsbook's American odds.espn_cfb_recruits()— ESPN's recruiting board for a class, one row per recruit with grade, position/state/region rank, committed school, and hometown.
New ESPN wrappers — players
espn_cfb_players(),espn_cfb_player(),espn_cfb_player_eventlog(),espn_cfb_player_gamelog(),espn_cfb_player_statistics(),espn_cfb_player_splits(),espn_cfb_player_overview(), andespn_cfb_player_seasons()— player index, biographical detail, per-game logs, season statistics, and split breakdowns. The season-level wrappers resolveathlete_idto human-readable name/position columns via anathlete_detailargument.
New ESPN wrappers — teams
espn_cfb_teams(),espn_cfb_team(),espn_cfb_team_roster(),espn_cfb_team_schedule(),espn_cfb_team_record(), andespn_cfb_team_leaders()— team index, team-in-season detail, roster, schedule, records, and statistical leaders.espn_cfb_team_ats(),espn_cfb_team_powerindex(),espn_cfb_team_events(),espn_cfb_team_ranks(),espn_cfb_team_awards(), andespn_cfb_team_coaches()— team against-the-spread records, single-team power index, season event log, poll-rank history, player awards, and coaching staff.
New ESPN wrappers — game detail
espn_cfb_game_teams(),espn_cfb_game_team_linescores(),espn_cfb_game_team_leaders(),espn_cfb_game_team_roster(),espn_cfb_game_team_statistics(), andespn_cfb_game_team_records()— per-game team breakdowns.espn_cfb_game_odds(),espn_cfb_game_broadcasts(),espn_cfb_game_predictor(),espn_cfb_game_probabilities(),espn_cfb_game_powerindex(), andespn_cfb_game_pbp()— per-game odds, broadcasts, pre-game predictor, live win-probability, matchup power index, and play-by-play.espn_cfb_game_drives(),espn_cfb_game_drive_plays(),espn_cfb_game_play(),espn_cfb_game_leaders(),espn_cfb_game_situation(),espn_cfb_game_status(),espn_cfb_game_player_statistics(), andespn_cfb_game_player_box()— drive log, drive-scoped plays, single-play detail, game statistical leaders, situation, status, and per-player game box lines.- The play-level wrappers (
espn_cfb_game_pbp(),espn_cfb_game_drive_plays(),espn_cfb_game_play()) extract every field ESPN returns for a play and expose its nested child collections through opt-in parameters:participants("none"/"wide"/"long") andparticipants_listsurface per-play athlete involvement (passer, rusher, tackler, …), andteam_participants/team_participants_listsurface the offense/defense team participants —"wide"modes pivot to one row per play, the*_listflags keep the raw detail as a list-column. espn_cfb_game_team_records(detail = TRUE)unpacks each record's full statistic breakdown;espn_cfb_game_odds(line_history = TRUE)returns the open/close/current line-movement history. Roster and player-stats wrappers join ESPN position-catalog detail whenposition_detail = TRUE.espn_cfb_game_drives()gains aplaysargument —"list"nests each drive's plays (full play-by-play schema, with the participant pass-through options) as a list-column,"expand"returns the flat one-row-per-play table withdrive_*context columns. The newespn_cfb_unnest_plays()performs the same drives-to-play-by-play transform on an already-fetched nested frame.- The game wrappers join human-readable team detail when
team_detail = TRUE(default): every team-id column (team_id,home_team_id,start_team_id,leader_team_id, …) gains sibling*_name,*_abbreviation,*_location,*_display_name,*_color,*_logo_href, … columns from the ESPN team catalog.espn_cfb_game_teams(format = "wide")collapses the two competitor rows into a single per-game row withhome_*/away_*columns for direct joining onto one-row-per-game tables. espn_cfb_pbp_v2()— a core-v2-sourced successor toespn_cfb_pbp(): assembles play-by-play in one structured request (vs. the legacy site-v2 summary parse) and, withepa_wpa = TRUE, runs cfbfastR's full EPA/WPA model pipeline — producing EPA/WPA columns identical to the legacy modeled feed.
New ESPN wrappers — catalogs and season metadata
espn_cfb_seasons(),espn_cfb_season_info(),espn_cfb_season_types(),espn_cfb_season_weeks(),espn_cfb_groups(), andespn_cfb_standings()— season structure, conferences, and standings.espn_cfb_coaches(),espn_cfb_coach(),espn_cfb_venues(),espn_cfb_positions(),espn_cfb_awards(),espn_cfb_rankings(), andespn_cfb_week_rankings()— league catalogs and poll rankings.espn_cfb_coach_record(),espn_cfb_franchises(),espn_cfb_franchise(),espn_cfb_venue(),espn_cfb_position(), andespn_cfb_award()— coach season win/loss records, the league franchise catalog, and single-record venue / position / award detail.
New Yahoo Sports wrappers
- Added Yahoo Sports college football wrappers:
yahoo_cfb_player_season_stats(),yahoo_cfb_team_season_stats(),yahoo_cfb_player_season_stats_legacy(),yahoo_cfb_team_season_stats_legacy(),yahoo_cfb_scoreboard(), andyahoo_cfb_boxscore()(scaffold), wrapping Yahoo's shangrila stats graph and editorial feed.
New CollegeFootballData wrappers
cfbd_betting_ats()— season against-the-spread (ATS) summary records by team, wrapping the CollegeFootballData/teams/atsendpoint.cfbd_stats_game_havoc()— per-game havoc statistics (total / front-seven / defensive-back havoc events and rates, offense and defense), wrapping the CollegeFootballData/stats/game/havocendpoint.cfbd_pbp_data_v2()is a new public function: a modular successor tocfbd_pbp_data()that runs the same EPA/WPA pipeline through a single shared engine (.run_epa_wpa()) and a canonical play-type taxonomy (.pbp_play_types()). The legacycfbd_pbp_data()is unchanged.espn_cfb_pbp_v2()now sources play-by-play and meta through the shared engine, requestsparticipants = "wide"andteam_participants = "wide"fromespn_cfb_game_drives(), and adds the meta columnshome_team_name,home_team_color,home_team_alternate_color,home_team_rank(andaway_*) via the new.espn_pbp_game_meta()bridge. Output is a strict superset of legacyespn_cfb_pbp()on the meta columns.
Play-by-play engine — v2 is now the default
- **
cfbd_pbp_data()andespn_cfb_pbp()now run the v2 engine by default.** Both gain penalty enforcement resolution, ESPN-resolved player names, the*_player_idcolumns and theoutputtier selector without a code change. The previous behaviour is one argument away —engine = "legacy"per call, oroptions(cfbfastR.pbp_engine = "legacy")for a session — and a once-per-session message says so.engine = "auto"continues to mean "whatever this release considers current".tests/testthat/test-pbp_equivalence.Rasserts v2 reproduces the legacy frames column-for-column, with an explicit allow-list of intentional deltas. - Play-by-play now overwrites the regex-extracted
*_player_namevalues with ESPN's ownparticipants[]names (2014 onward), so a capture that trailed narration ("Rod Smith 3 Yd"), abbreviated, or carried a team code becomes the real name. Ported fromsportsdataverse'sCFBPlayProcess.__join_participantsand verified against a 60-game offline oracle (5 games from each of 2004, 2006, 2008, 2010, 2013, 2014, 2017, 2019, 2020, 2021, 2023, 2025, including the postseason): 1,236 of 9,545 × 11 name cells change, with zero divergence from the Python. The stage runs **before** id resolution, so the roster matcher gets a clean key rather than narration. espn_cfb_pbp_v2()gainsresolve_names(defaultTRUE). Whenepa_wpa = TRUEit spends one memoised request per game on ESPN's play-by-play sidecar, which supplies (a) full athlete names —"Jalen Mitchell"rather than the core-v2 roster's"J. Mitchell"— and (b) the per-player box score as a second identity source. The box score is the *only* identity source on the large share of games where ESPN 404s the roster resource; adding it cuts*_player_iddivergence from sdv-py from 52/163,656 to 26/166,482 — fewer mismatches over more plays. Setresolve_names = FALSEfor a bulk sweep that would rather have the short names than the requests.- Play-by-play now resolves **which team** each event belongs to, adding 30 columns cfbfastR could not previously produce: the special-teams flip (
kicking_team,return_team,punt_return_team,kick_return_team,fg_team,punt_team), the event-credit columns (sack_team,interception_team,pass_breakup_team,forced_fumble_team,fumble_recovery_team), the fumble/recovery chain (fumble_or_muff,fumbling_team,recovery_team,recovery_team_2), the per-side turnover model (is_turnover,turnover_team,int_turnover,pos_fumble_lost,def_fumble_lost,is_pos_team_turnover,is_def_pos_team_turnover,is_st_turnover,is_blocked_punt_turnover,is_blocked_fg_turnover), penalty attribution (penalized_team,penalty_team_id,penalty_yards_signed) and the id-keyedpos_team_id/def_pos_team_id. Ported fromsportsdataverse'sCFBPlayProcess.__add_attribution_colsand verified against the 60-game offline oracle at zero divergence over 267,260 cells. The turnover flags are framed **per side** because one play can lose the ball twice — the offense fumbles, the defense recovers and fumbles back — and a single boolean cannot say that both teams turned it over. Blocked punts and blocked field goals deliberately stay *out* ofis_turnover: ESPN's official box counts only giveaways, so folding them in would break the reconciliation against it. They get their own flags instead. On the ESPN path, ESPN's own per-play turnover flag is preserved as **espn_is_turnover** rather than being silently overwritten. The two legitimately differ — ESPN's also fires on blocked kicks. - Play-by-play gains
air_yards,air_yardsToEndzoneandyards_after_catch, splitting a completed pass into the yards thrown and the yards run after the catch. ESPN states the catch point as"caught at OU35"; the stated yard line belongs to whichever team owns that side of the field, so the abbreviation is sided against the possessing and defending teams with the same prefix-tolerant matcher the recovery and penalty teams use.yards_after_catchis computed for completions only. Ported fromsportsdataverse'sCFBPlayProcess.__add_air_yards_cols. **One deliberate divergence from the Python:** sdv-py's pattern has no article, so it resolves"caught at OU35"and silently drops"thrown to the ARK30". Both forms occur in ESPN's text — and cfbfastR's core-v2 feed uses the article form almost exclusively, where a verbatim port would have matched nothing at all. This implementation accepts both. The parity test is partitioned accordingly: exact agreement on the 137 oracle rows sdv-py resolves, plus an explicit assertion that the 7 article-form rows it drops are recovered here. - Play-by-play gains
pass_depth,pass_direction,rush_directionandqb_hurry, read from the play text ("short"/"deep","left"/"middle"/"right", and ESPN's"QB hurried by"annotation). Null where ESPN omits the phrase — sacks, screens, and older seasons that never annotated depth or direction. espn_cfb_pbp_v2()now refuses to run the EPA/WPA models on an obviously malformed feed — no plays, or implausibly few or many for a game that has finished — and returns the unmodeled frame with a warning instead. A truncated game models perfectly cleanly and produces EPA, drive results and a box score that all
The NEWS section is longer than shown here.
From NEWS.md in the release
Install
Health
NOTEdependencies in R coder-devel-linux-x86_64-debian-clang, r-devel-linux-x86_64-debian-gcc, r-devel-linux-x86_64-fedora-clang, r-devel-linux-x86_64-fedora-gcc, r-devel-windows-x86_64
r-devel-linux-x86_64-debian-clang, r-devel-linux-x86_64-debian-gcc, r-devel-linux-x86_64-fedora-clang, r-devel-linux-x86_64-fedora-gcc
Base package in Suggests/Enhances imported in NAMESPACE: ‘stats’
r-devel-windows-x86_64
Base package in Suggests/Enhances imported in NAMESPACE: 'stats'
- NOTE8 OK, 5 NOTENow
- NOTE11 OK, 2 NOTE2026-09-12
- OK13 OK2026-08-24
- NOTE12 OK, 1 NOTE2026-08-18
- OK13 OK2026-08-05
- NOTE12 OK, 1 NOTE2026-08-01
Show 7 earlier changesHide 7 earlier changes
- OK13 OK2026-06-27
- NOTE12 OK, 1 NOTE2026-06-20
- OK13 OK2026-06-09
- ERROR12 OK, 1 ERROR2026-06-08
- OK14 OK2026-04-10
- NOTE13 OK, 1 NOTE2026-04-09
- OK14 OK2026-03-10
Documentation
- Help pages
- 244 (5 internal)includes a package overview page
- Examples that run
- 0%213 only when donttest examples are enabled (R CMD check --as-cran)
- Exported functions with examples
- 96%
- Documented parameters
- 100%
- Return-value docs
- 100%
- Help pages citing references
- 0%
Downloads
Repository
- PRs merged (all time)
- 97%
- Median days to close, 50 most recently updated closed issues
- 38
- Median days to close, 50 most recently updated closed PRs
- 0
Stars over time
Forks over time
Releases over time
Issues over time
PRs over time
Commits over time
16 development-tooling and community-health practices detected across 7 families in the upstream repository
Checks run against github.com/sportsdataverse/cfbfastr on 2026-10-18.
The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel
GitHub Pages site last deployed 2026-10-18 · The repository has a site deploy workflow
pkgdown site last built 2026-10-18
Show all practicesHide 3 practices
This repository shows signs of AI coding tools.
- Claude Codefirst seen 2026-06-08Seen in the repository: .claude, CLAUDE.mdNamed in .Rbuildignore: .claude, CLAUDE.mdPull request it wrote: opened by a project member
- GitHub Copilotfirst seen 2026-06-08Seen in the repository: .github/copilot-instructions.md
Dependencies
Installing cfbfastR adds 34 packages (22 with compiled code, 30 MB of source tarballs). Heaviest: stringi 11 MB, data.table 5.7 MB, Rcpp 1.8 MB.
Code & Tests
Datasets
People & History
Show 3 more contributorsHide 3 contributors
Pick two releases to compare their code metrics.
- 3.0.0Latest2026-08-24 · current release · diff ↗ ·
added 148 exports
cfbd_betting_ats, cfbd_coaches_profile, cfbd_coaches_seasons, cfbd_coaches_tenures, cfbd_conference_affiliations, cfbd_conference_changes, cfbd_info_usage, cfbd_pbp_data_v2, cfbd_player_season_overview, cfbd_playoffs_cfp, cfbd_playoffs_cfp_games, cfbd_playoffs_cfp_participants, cfbd_ratings_core, cfbd_ratings_srs_expanded, cfbd_stats_game_havoc, cfbd_stats_player_success, cfbd_stats_player_success_game, cfbd_teams_fbs, clean_play_text, espn_cfb_award, espn_cfb_awards, espn_cfb_clear_cache, espn_cfb_coach, espn_cfb_coach_record, espn_cfb_coaches, espn_cfb_franchise, espn_cfb_franchises, espn_cfb_futures, espn_cfb_game_broadcasts, espn_cfb_game_drive_plays and 118 more - RR 4.6.0 released · 2026-04-24
- unarchivedReturned to CRAN2025-09-09
- 2.0.02025-09-09 · diff ↗ ·
added 10 exports
cfbd_api_key_info, cfbd_live_plays, cfbd_live_scoreboard, cfbd_metrics_fg_ep, cfbd_metrics_wepa_players_kicking, cfbd_metrics_wepa_players_passing, cfbd_metrics_wepa_players_rushing, cfbd_metrics_wepa_team_season, cfbd_ratings_fpi, espn_cfb_player_stats - RR 4.5.0 released · 2025-04-11
- RR 4.4.0 released · 2024-04-24
- archivedRemoved from CRAN2024-04-20issues were not corrected despite reminders
- RR 4.3.0 released · 2023-04-21
- unarchivedReturned to CRAN2022-06-14
- 1.9.02022-06-14 · diff ↗ ·
added 8 exports
cfbd_recruiting_transfer_portal, espn_cfb_calendar, espn_cfb_schedule, espn_cfb_team_stats, espn_ratings_fpi, load_cfb_rosters, load_cfb_schedules, load_cfb_teams - archivedRemoved from CRAN2022-06-11check issues were not corrected in time
- RR 4.2.0 released · 2022-04-22
- 1.6.42021-10-27
- RR 4.1.0 released · 2021-05-18
Package metadata
- First published
- 2021-10-27
- Total releases
- 4 / 5 yrs
- License
- MIT + file LICENSE OSI
- Minimum R
- ≥ 4.1.0
- Bundled data
- 2.2 KB / 3 files
- Download size
- 1.8 MB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("cfbfastR")The package provides a citation file that builds its entry when R runs it. Run citation() to see it.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-20, which the citation names so these numbers can be found later. More on citing and the projects behind them.