golfastr provides tidy professional golf data in R: tournament schedules, leaderboards, hole-by-hole scoring, and strokes gained. Completed PGA Tour seasons are served from pre-built files hosted on GitHub releases (updated daily), so loading a full season takes seconds. Everything else falls back to the live ESPN API.
The season schedule
sched <- load_schedule(2025)
head(sched)
#> # A tibble: 6 × 4
#> event_id tournament_name start_date end_date
#> <chr> <chr> <date> <date>
#> 1 401703489 The Sentry 2025-01-02 2025-01-05
#> 2 401703490 Sony Open in Hawaii 2025-01-09 2025-01-12
#> 3 401703491 The American Express 2025-01-16 2025-01-19
#> 4 401703492 Farmers Insurance Open 2025-01-22 2025-01-25
#> 5 401703493 AT&T Pebble Beach Pro-Am 2025-01-30 2025-02-02
#> 6 401703494 WM Phoenix Open 2025-02-06 2025-02-09Leaderboards
load_leaderboard() takes a year and an optional
tournament, matched by event ID or partial name:
masters <- load_leaderboard(2025, "Masters")
head(masters)
#> # A tibble: 6 × 8
#> position player_id player_name total_score score_to_par tournament_id
#> <int> <chr> <chr> <int> <chr> <chr>
#> 1 1 3470 Rory McIlroy 277 -11 401703504
#> 2 2 569 Justin Rose 277 -11 401703504
#> 3 3 5579 Patrick Reed 279 -9 401703504
#> 4 4 9478 Scottie Scheffler 280 -8 401703504
#> 5 5 11382 Sungjae Im 281 -7 401703504
#> 6 6 10046 Bryson DeChambeau 281 -7 401703504
#> # ℹ 2 more variables: tournament_name <chr>, year <int>Leave the tournament out to get every completed event in the season in one tibble:
season <- load_leaderboard(2025)
nrow(season)
#> [1] 5832Hole-by-hole scoring
Hosted seasons include full-field scorecards, one row per player per hole:
holes <- load_holes(2025, "Masters")
head(holes)
#> # A tibble: 6 × 20
#> player_id player_name position tournament_id tournament_name round hole par
#> <chr> <chr> <int> <chr> <chr> <int> <int> <int>
#> 1 10046 Bryson DeC… 6 401703504 Masters Tourna… 1 1 4
#> 2 10046 Bryson DeC… 6 401703504 Masters Tourna… 1 2 5
#> 3 10046 Bryson DeC… 6 401703504 Masters Tourna… 1 3 4
#> 4 10046 Bryson DeC… 6 401703504 Masters Tourna… 1 4 3
#> 5 10046 Bryson DeC… 6 401703504 Masters Tourna… 1 5 4
#> 6 10046 Bryson DeC… 6 401703504 Masters Tourna… 1 6 3
#> # ℹ 12 more variables: score <int>, score_type <chr>, year <int>,
#> # field_avg <dbl>, to_par <int>, vs_field <dbl>, cume_to_par <int>,
#> # win_prob <dbl>, win_prob_before <dbl>, wpa <dbl>, skill_rating <dbl>,
#> # hole_order_source <chr>That granularity is enough to rebuild the tournament story. For example, the cumulative score to par of the top five finishers:
library(ggplot2)
top5 <- masters |>
slice_head(n = 5) |>
pull(player_id)
race <- holes |>
filter(player_id %in% top5) |>
arrange(player_id, round, hole) |>
group_by(player_id, player_name) |>
mutate(
hole_index = row_number(),
to_par = cumsum(score - par)
) |>
ungroup()
ggplot(race, aes(hole_index, to_par, color = player_name)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "grey60") +
geom_step(linewidth = 0.8) +
scale_y_reverse() +
labs(
title = "2025 Masters, top five finishers",
x = "Holes played", y = "Score to par", color = NULL
) +
theme_minimal()
Analysis
load_leaderboard() returns a tibble you can pass
straight into the summary helpers:
player_summary("Scheffler", data = season)
#> # A tibble: 1 × 9
#> player tournaments wins top_5 top_10 top_25 avg_finish best_finish
#> <chr> <int> <int> <int> <int> <int> <dbl> <int>
#> 1 Scottie Scheffler 21 6 12 18 19 7 1
#> # ℹ 1 more variable: worst_finish <int>
win_leaders(data = season, top_n = 5)
#> # A tibble: 5 × 2
#> player wins
#> <chr> <int>
#> 1 Scottie Scheffler 6
#> 2 Rory McIlroy 3
#> 3 Ben Griffin 2
#> 4 Brian Campbell 2
#> 5 Hideki Matsuyama 2Strokes gained
Per-round strokes gained averages ship with the package. Filter by
player and season. "E" in score_to_par means
even par.
load_strokes_gained("Scheffler", use_bundled = TRUE, year = 2026)
#> # A tibble: 1 × 11
#> player_id player_name country sg_putt sg_arg sg_app sg_ott sg_t2g sg_total
#> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 46046 Scottie Scheff… USA 0.574 0.392 0.673 0.61 1.67 2.25
#> # ℹ 2 more variables: rounds <int>, season <int>Live data and other tours
Hosted data covers completed PGA Tour events. For tournaments in
progress, pass live = TRUE to query ESPN directly:
load_leaderboard(2026, "Travelers", live = TRUE)LIV Golf, the LPGA, the DP World Tour, and the Champions Tour are
available through the same functions via the tour
argument:
load_schedule(2026, tour = "lpga")
load_leaderboard(2026, "Adelaide", tour = "liv")Field-level documentation for every column lives in the Field
descriptions article and in
pga_field_descriptions().
