cfbfastR now loads every published CFB dataset on the sportsdataverse-data
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 eleven adv_* advanced-stats
datasets.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.parquet_from_url() helper backs the
parquet-only datasets (requires the suggested arrow
package).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).
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).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.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(), and
espn_cfb_player_seasons() — player index, biographical
detail, per-game logs, season statistics, and split breakdowns. The
season-level wrappers resolve athlete_id to human-readable
name/position columns via an athlete_detail argument.espn_cfb_teams(), espn_cfb_team(),
espn_cfb_team_roster(),
espn_cfb_team_schedule(),
espn_cfb_team_record(), and
espn_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(), and
espn_cfb_team_coaches() — team against-the-spread records,
single-team power index, season event log, poll-rank history, player
awards, and coaching staff.espn_cfb_game_teams(),
espn_cfb_game_team_linescores(),
espn_cfb_game_team_leaders(),
espn_cfb_game_team_roster(),
espn_cfb_game_team_statistics(), and
espn_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(), and
espn_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(), and
espn_cfb_game_player_box() — drive log, drive-scoped plays,
single-play detail, game statistical leaders, situation, status, and
per-player game box lines.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") and
participants_list surface per-play athlete involvement
(passer, rusher, tackler, …), and team_participants /
team_participants_list surface the offense/defense team
participants — "wide" modes pivot to one row per play, the
*_list flags 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 when
position_detail = TRUE.espn_cfb_game_drives() gains a plays
argument — "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 with drive_* context columns. The new
espn_cfb_unnest_plays() performs the same
drives-to-play-by-play transform on an already-fetched nested
frame.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 with
home_* / away_* columns for direct joining
onto one-row-per-game tables.espn_cfb_pbp_v2() — a core-v2-sourced successor to
espn_cfb_pbp(): assembles play-by-play in one structured
request (vs. the legacy site-v2 summary parse) and, with
epa_wpa = TRUE, runs cfbfastR’s full EPA/WPA model pipeline
— producing EPA/WPA columns identical to the legacy modeled feed.espn_cfb_seasons(),
espn_cfb_season_info(),
espn_cfb_season_types(),
espn_cfb_season_weeks(), espn_cfb_groups(),
and espn_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(), and
espn_cfb_week_rankings() — league catalogs and poll
rankings.espn_cfb_coach_record(),
espn_cfb_franchises(), espn_cfb_franchise(),
espn_cfb_venue(), espn_cfb_position(), and
espn_cfb_award() — coach season win/loss records, the
league franchise catalog, and single-record venue / position / award
detail.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(), and
yahoo_cfb_boxscore() (scaffold), wrapping Yahoo’s shangrila
stats graph and editorial feed.cfbd_betting_ats() — season against-the-spread (ATS)
summary records by team, wrapping the CollegeFootballData
/teams/ats endpoint.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/havoc endpoint.cfbd_pbp_data_v2() is a new public function: a modular
successor to cfbd_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
legacy cfbd_pbp_data() is unchanged.espn_cfb_pbp_v2() now sources play-by-play and meta
through the shared engine, requests participants = "wide"
and team_participants = "wide" from
espn_cfb_game_drives(), and adds the meta columns
home_team_name, home_team_color,
home_team_alternate_color, home_team_rank (and
away_*) via the new .espn_pbp_game_meta()
bridge. Output is a strict superset of legacy
espn_cfb_pbp() on the meta columns.cfbd_pbp_data() and
espn_cfb_pbp() now run the v2 engine by default.
Both gain penalty enforcement resolution, ESPN-resolved player names,
the *_player_id columns and the output tier
selector without a code change. The previous behaviour is one argument
away — engine = "legacy" per call, or
options(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.R asserts 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_name values with ESPN’s own
participants[] names (2014 onward), so a capture that
trailed narration ("Rod Smith 3 Yd"), abbreviated, or
carried a team code becomes the real name. Ported from
sportsdataverse’s
CFBPlayProcess.__join_participants and 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() gains resolve_names
(default TRUE). When epa_wpa = TRUE it 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_id
divergence from sdv-py from 52/163,656 to 26/166,482 — fewer mismatches
over more plays. Set resolve_names = FALSE for 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-keyed
pos_team_id / def_pos_team_id. Ported from
sportsdataverse’s
CFBPlayProcess.__add_attribution_cols and 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 of is_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_yardsToEndzone and yards_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_catch is computed for completions
only. Ported from sportsdataverse’s
CFBPlayProcess.__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_direction and
qb_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 look reasonable and
are all wrong, and nothing downstream can distinguish that from a real
blowout. The count rules apply only to completed games so a live feed is
never rejected. Ported from
CFBPlayProcess.corrupt_pbp_check.
A pbp-to-boxscore parity gate now guards the
test suite. The per-play parity tests check a play against itself; this
aggregates play-by-play by team and compares it against ESPN’s own team
box, which is the only cheap end-to-end judge of whether parsing put the
right events on the right team. An attribution bug leaves every
per-play assertion green and shows up here immediately. Ported from
sportsdataverse’s
tools/validation/checks/boxscore_parity, adapted from a
per-season harness check to a per-game library gate.
It encodes three conventions proven against the box, two of which are
the opposite of the NFL’s: NCAA charges a sack to
rushing (attempt and yardage both), pass attempts
exclude sacks, and a penalty belongs to the team that
committed it — a positive penalty_yards_signed
means the offence gained, so the defence was flagged. Floors are
measured from the shipped 60-game corpus, never guessed, and are
per-stat because parity is strongly era-dependent (interceptions
reconcile at 97%, 2004-inclusive rushing yardage at 31%).
Audited against the CollegeFootballData OpenAPI spec (5.24.1, 74 endpoints).
15 endpoints that had no wrapper now have one:
cfbd_playoffs_cfp(),
cfbd_playoffs_cfp_games(),
cfbd_playoffs_cfp_participants(),
cfbd_conference_affiliations(),
cfbd_conference_changes(),
cfbd_coaches_profile(),
cfbd_coaches_seasons(),
cfbd_coaches_tenures(), cfbd_ratings_core(),
cfbd_ratings_srs_expanded(), cfbd_teams_fbs(),
cfbd_stats_player_success(),
cfbd_stats_player_success_game(),
cfbd_player_season_overview() and
cfbd_info_usage(). Every one was exercised against the live
API before being committed.
26 parameters added to existing wrappers — most
importantly division on ten more functions, plus
defense / offense_conference /
defense_conference / conference /
division on cfbd_pbp_data(),
competition and round on
cfbd_game_info() (College Football Playoff filtering),
line_provider on cfbd_betting_lines(),
conference on cfbd_play_stats_player() and
recruit_type on cfbd_recruiting_position().
cfbd_conferences() previously took no arguments at
all and now accepts year and
division.
New validate_division() covering
fbs / fcs / ii /
ii/iii / iii. This validates locally because
CFBD ignores an unrecognised filter value rather than rejecting
it — so without it a typo silently returns every division.
Two spec parameters were deliberately not exposed
after testing them: /rankings declares latest
and final as booleans, but the API returns HTTP 400 for
every form of both. poll is validated to
"cfp", the only value it accepts.
espn_cfb_team_coaches() — the year
argument is deprecated. ESPN’s core-v2 coaches endpoint returns the
current coach whatever season is requested, echoing the
requested year back in the response, so historical calls silently
returned today’s coach labelled with the old season (#125).
year now defaults to most_recent_cfb_season();
passing any other season warns and is coerced, rather than returning
misattributed data. Existing calls keep working.
espn_cfb_teams() returned zero
rows, because site.api.espn.com now answers HTTP
403 to a spoofed browser User-Agent. The failure was silent
— the wrapper caught it and returned an empty frame — and every consumer
degraded to NA, which took home,
away, pos_team, def_pos_team,
offense_play, defense_play and every team
abbreviation on the ESPN play-by-play path down with it. Measured
2026-08-19: the endpoint answers 200 with httr2’s default UA, with
curl/8.5.0, or with
Accept/Origin/Referer and no UA
at all, and 403 with the Chrome string. The User-Agent
header is dropped.
Probing every ESPN host the package uses narrowed the blast radius to
exactly two callers — espn_cfb_teams() and
espn_cfb_team_schedule(), the only two that combine
site.api.espn.com with the spoofed header.
espn_cfb_team_schedule() was returning zero rows for the
same reason and now returns data. The other ~65 occurrences of the
header sit on sports.core.api.espn.com and
site.web.api.espn.com, which answer 200 either way, so they
are left alone.
Worth knowing for anyone adding an ESPN call:
cdn.espn.com does something worse than a 403 under the
browser UA — it answers 200 with a zero-byte body, so
nothing raises and the parse silently yields nothing.
tests/testthat/test-espn_http_headers.R is a source-level
guard that fails if the header is re-added to a site.api
caller.
defense_play was a copy-paste duplicate of
offense_play in the ESPN adapter — both
case_when() branches returned the home team — so it named
the team with the ball on every ESPN play.
Play-by-play gains pos_team_id /
def_pos_team_id / offense_play_id /
defense_play_id. pos_team,
def_pos_team, offense_play and
defense_play are team NAMES resolved through the ESPN teams
catalog, and when that catalog is unavailable they all go NA together —
which silently disabled team-aware roster matching, dropping every
player-id lookup to the global-unique fallback. The ids come straight
off the play and are always present. (espn_cfb_teams()
currently returns zero rows, so this is the live condition, not a
hypothetical.)
.espn_cfb_participant_roster() is now memoised
alongside the ESPN catalog helpers. espn_cfb_pbp_v2() needs
one game’s roster twice — once to name participants, once to resolve
player ids — and a season sweep asked for it once per game; both now
cost a single request. The memoised-helper list is a single constant
shared by .onLoad() and
espn_cfb_clear_cache(), which had been a second
hand-maintained copy that could silently drift into caching a helper it
never cleared.
.run_epa_wpa_by_game() had no roster argument, so
cfbd_pbp_data_v2() could never resolve
*_player_id columns however the roster was supplied. It now
threads rosters and participants through,
sliced per game_id.
espn_cfb_pbp() now builds its request URL with the
?event= query separator (previously concatenated as
summaryevent=, which returned HTTP 404 for every game) and
initializes its return frame before the tryCatch so an
upstream failure no longer throws
object 'plays_df' not found.
cfbd_pbp_data_v2() and
espn_cfb_pbp_v2() preserve character id_play
precision through the EPA/WPA pipeline. The legacy shared helper used
unquoted numeric literals in two ifelse calls (a historical
id_play swap for one game), which silently coerced
character id_play to numeric and then lost precision past
2^53 — breaking the play-id join-back in espn_cfb_pbp_v2().
The modular .pbp_clean_pbp_dat() quotes those literals so
id_play stays character; the legacy
clean_pbp_dat() is unchanged.
httr2 package (>= 1.0.0) instead of
the legacy httr. End users running existing wrapper calls
(cfbd_*, espn_cfb_*) should see no behavioural
change – the migration is internal. Custom code that calls
get_req() or check_status() directly must
update from httr::content(res, as = "text") to
httr2::resp_body_string(res) and from
httr::status_code(res) to
httr2::resp_status(res).get_req() now resolves
a proxy in the order: explicit proxy argument ->
getOption("cfbfastR.proxy") -> http_proxy /
https_proxy env vars. The proxy value accepts either a URL
string or a named list with url / port /
username / password / auth for
authenticated proxies.lubridate, progressr, memoise,
cachem, and magrittr have moved out of
Imports (21 -> 16). lubridate is gone
entirely – its two ymd_hm() |> with_tz() calls in
espn_cfb_schedule.R are now base-R
as.POSIXct(format = "%Y-%m-%dT%H:%M", tz = "UTC") +
attr(., "tzone"). progressr,
memoise, and cachem moved to
Suggests and the helpers degrade gracefully when missing:
load_cfb_pbp() / cfbd_pbp_data() /
pbp_epa_wpa_engine() run without a progress bar when
progressr is absent; ESPN catalog wrappers run uncached
when memoise / cachem are absent
(espn_cfb_clear_cache() becomes a no-op). Drops the
Imports count below the >20 R CMD check
NOTE threshold.%>% chains in R/, plus 137 across
vignettes/ and tests/, were converted to the
base-R native pipe |>. magrittr is no
longer an Imports; downstream consumers that load
cfbfastR purely for its functions don’t get
%>% re-exported anymore. User-visible impact is minimal
– the public API is unchanged and dplyr (which is in
Imports) still re-exports %>% for users who
want to keep writing it. Two non-mechanical fixes were needed during the
sweep: three |> [[("url") chains in
cfbd_betting.R and cfbd_coaches.R (rejected as
RHS in R 4.1’s |>) became
|> purrr::pluck("url"); seven
|> tibble::tibble(col = .data$.) constructs were a
magrittr quirk that silently duplicated the LHS into both a
. and the named column – rewritten to
tibble::tibble(col = <lhs>), which drops the
redundant . column.tests/testthat/setup-cfbd-throttle.R adds a 1-second sleep
before every CFBD request made by devtools::test() /
R CMD check. It works by monkey-patching
cfbfastR:::get_req() for the duration of the test session
(restored via withr::defer(., teardown_env())) – the
package code is unchanged, so interactive and production calls pay no
penalty. Tunable via
options(cfbfastR.test_request_delay = N) (default 1; set to
0 for unthrottled local runs). Resolves the cascading
HTTP 429 skip-if-empty results that were turning
otherwise-green test runs into “all green, mostly skipped.”
withr joins Suggests to declare the test-side
dependency cleanly (it was already a transitive dep of
testthat).validate_week() utility function where
some inputs were not being handled correctly (i.e. week 16). Fixes
trickle down to cfbd_pbp_data() and other functions.season_type parameter in
cfbd_game_info() and cfbd_play_stats_player()
function changed from “regular” to “both” to align with other functions
in the package.cfbd_pbp_data() where play-by-play data
for some games were not as expected.add_yardage() where plays with missing yardage
values were not being handled correctly.load_cfb_*() functions now use sportsdataverse-data
releases or the CollegeFootballData.com
API as their underlying data source to remain in compliance with
CFBD API terms and conditions (See Note below).load_cfb_pbp() dataset to include various team-
and game-level ID’s and flags that were not being included, like
home_team_id, away_team_id,
season_type, venue_id, some
drive_* columns, a half-dozen player stat columns, etc.
Essentially, all the leg-work users have undoubtedly had to do while
using these datasets is mostly just included now. The
downside: this means end users need to check their pipelines
which build off these datasets to ensure behavior is as expected and all
your joins are doing what is intended.Special thanks are in order for our newest contributor, Brad Hill (@bradisbrad) for providing most of the v2 upgrade via his first PR to cfbfastR!! 🙌🏽 👑 🥇 Your contributions are most appreciated by the community.
Note: The free-tier API key
for the CFBD v2 API has a strict 1k calls/month limit, so plan your
workflows accordingly! If you receive errors mentioning
r Request failed [429], you have most likely run out of API
calls for the month in your membership tier.
Added all new cfbd_*() functions accommodated by the
new College Football Data API v2. This includes the following
functions:
cfbd_metrics_fg_ep()
function to access the new field goal expected points added metric from
the API.cfbd_metrics_wepa_team_season()
function to access the new opponent adjusted team season predicted
points added metric from the API.cfbd_metrics_wepa_players_passing()
function to access the new opponent adjusted players passing predicted
points added metric from the API.cfbd_metrics_wepa_players_rushing()
function to access the new opponent adjusted players rushing predicted
points added metric from the API.cfbd_metrics_wepa_players_kicking()
function to access the new Points Added Above Replacement (PAAR) ratings
for kickers from the API.cfbd_ratings_fpi()
function to access the new FPI ratings from the API.cfbd_live_scoreboard()
function to access live scoreboard data from the API.cfbd_live_plays()
function to access live play-by-play data from the API.cfbd_api_key_info()
function to get information about your API key, including your Patreon
level and usage limits.Minor changes to the existing cfbd_*() functions
under the hood to accommodate the new API v2 structure. Please see below
for a list of all updated functions:
cfbd_betting_lines()
functioncfbd_coaches()
functioncfbd_conferences()
functioncfbd_drives()
functioncfbd_calendar()
functioncfbd_game_box_advanced()
functioncfbd_game_info()
functioncfbd_game_media()
functioncfbd_game_player_stats()
functioncfbd_game_records()
functioncfbd_game_team_stats()
functioncfbd_metrics_ppa_games()
functioncfbd_metrics_ppa_players_games()
functioncfbd_metrics_ppa_players_season()
functioncfbd_metrics_ppa_predicted()
functioncfbd_metrics_ppa_teams()
functioncfbd_metrics_wp()
functioncfbd_metrics_wp_pregame()
functioncfbd_pbp_data()
functioncfbd_play_stats_player()
functioncfbd_play_stats_types()
functioncfbd_play_types()
functioncfbd_plays()
functioncfbd_player_info()
functioncfbd_player_returning()
functioncfbd_player_usage()
functioncfbd_rankings()
functioncfbd_ratings_sp()
functioncfbd_ratings_sp_conference()
functioncfbd_ratings_srs()
functioncfbd_recruiting_player()
functioncfbd_recruiting_position()
functioncfbd_recruiting_team()
functioncfbd_stats_categories()
functioncfbd_stats_game_advanced()
functioncfbd_stats_season_advanced()
functioncfbd_stats_season_player()
functioncfbd_stats_season_team()
functioncfbd_team_info()
functioncfbd_team_matchup()
functioncfbd_team_matchup_records()
functioncfbd_team_roster()
functioncfbd_team_talent()
functioncfbd_venues()
functionFixed the following functions and/or documentation:
cfbd_team_info()
addressing #97cfbd_stats_game_advanced()
returns an empty data frame when there are no resultscfbd_game_team_stats()
updated to reflect all parameter requirement scenarios.athlete_id parameter cfbd_player_usage()
so that it works as users would expect. There was an API query-parameter
mismatchathlete_id parameter for cfbd_play_stats_player()
function and added more thorough documentation.position to correct value (instead of
NA) from cfbd_stats_season_player()season_type parameter documentation
across many functionscfbd_pbp_data()
to substitute 3 timeouts per half when the data is missing from the
API.stringi v1.8 update in cfbd_play_pbp_data()
EPA and WPA processingespn_cfb_scoreboard()
and espn_cfb_schedule()
functions while adding lubridate dependencyespn_ratings_fpi()
functionespn_cfb_player_stats()
function added.cfbd_game_team_stats() function return data in a long
formatespn_cfb_calendar()espn_cfb_schedule()espn_cfb_pbp()espn_cfb_team_stats()Removes furrr, future dependencies,
adds Rcpp, RcppParallel, and
purrr dependencies
espn_ratings_fpi()
to exports.cfbd_game_team_stats() with _allowed
columns duplicating team stats instead of showing opponent stats.cfbd_game_team_stats().cfbd_pbp_data() to account for
additional timeout cases (namely, kickoffs/extra point attempts).cfbd_betting_lines()espn_ratings_fpi() now requires headers in
httr requestcfbd_ratings_elo()
functionupdate_cfb_db() where the function
failed when trying to load recent games from the data repo. (#35)cfbfastR.dbdirectory that allows to
set the database directory in update_cfb_db()
globally.cfbd_stats_season_team() that were not behaving
correctlyonly_fbs input in
cfbd_team_info() was ignored. It is now possible to get the
team info for all the colleges in the API instead of only FBS
schools.cfbd_metrics_ppa_teams.
cfbd_metrics_ppa_teams and
cfbd_metrics_ppa_players_season now require one of
team or year to be specifiedespn_cfb_scoreboard()espn_cfb_pbp()cfbd_game_weather()cfbd_game_player_stats()cfbd_recruiting_players()cfbd_draft_teams()
- Get list of NFL teamscfbd_draft_positions()
- Get list of NFL positions for mapping to
collegiatecfbd_draft_picks()
- Get list of NFL Draft picksAdded headshot_url to outputs of cfbd_team_roster()
Renamed returns in cfbd_game_box_advanced():
rushing_line_yd_avg to plural
rushing_line_yds_avgrushing_second_lvl_yd_avg to plural
rushing_second_lvl_yds_avgrushing_open_field_yd_avg to plural
rushing_open_field_yds_avgCompleted documentation for all returns except
cfbd_pbp_data()
Continued work on intro vignette
id variable to team_id in espn_ratings_fpi()espn_game_id variable to game_id
in espn_metrics_wp(),
corrected the away_win_percentage calculation and added
tie_percentage to the returns.id variable to athlete_id in cfbd_metrics_ppa_players_season()load_cfb_pbp()
and update_cfb_db()
functions. Pretty much cherry-picking the nflfastR
methodology of loading data from the cfbfastR-data
repository.furrr,
future, and
progressr
dependencies to the package to allow for parallel processing of the
play-by-play data with progress updates if desired.All functions sourced from the College Football Data API will
start with cfbd_ as opposed to cfb_ (as in
cfbscrapR). One additional cfbd_ function has been added
that corresponds to the result when cfbd_pbp_data()
has the parameter epa_wpa=FALSE. It has now been separated
into its own function for clarity cfbd_plays().
The parameter and functionality still exists in cfbd_pbp_data()
but we expect this function will still exist but made obsolete in favor
of a function more closely matching nflfastR’s naming
conventions.
Similarly, data and metrics sourced from ESPN will begin with
espn_ as opposed to cfb_. In particular, the
two functions are now espn_ratings_fpi()
and espn_metrics_wp()
Data generated from any of the cfbfastR methods will
use cfb_
The CollegeFootballData API now requires an API key, here’s a quick run-down:
To get an API key, follow the directions here: College Football Data Key Registration.
Using the key: You can save the key for consistent usage by
adding CFBD_API_KEY=XXXX-YOUR-API-KEY-HERE-XXXXX to your
.Renviron file (easily accessed via usethis::edit_r_environ()).
Run usethis::edit_r_environ(),
a new script will pop open named .Renviron,
THEN paste the following in the new script that pops up
(without quotations)
CFBD_API_KEY = XXXX-YOUR-API-KEY-HERE-XXXXXSave the script and restart your RStudio session, by clicking
Session (in between Plots and
Build) and click Restart R (n.b. there also
exists the shortcut Ctrl + Shift + F10 to restart your
session). If set correctly, from then on you should be able to use any
of the cfbd_ functions without any other changes.
CFBD_API_KEY (with quotations) using a command like the
following.{r} Sys.setenv(CFBD_API_KEY = "XXXX-YOUR-API-KEY-HERE-XXXXX")