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 × 11
#> player_id player_name position tournament_id tournament_name round hole par
#> <chr> <chr> <int> <chr> <chr> <int> <int> <int>
#> 1 3470 Rory McIlr… 1 401703504 Masters Tourna… 1 1 4
#> 2 3470 Rory McIlr… 1 401703504 Masters Tourna… 1 2 5
#> 3 3470 Rory McIlr… 1 401703504 Masters Tourna… 1 3 4
#> 4 3470 Rory McIlr… 1 401703504 Masters Tourna… 1 4 3
#> 5 3470 Rory McIlr… 1 401703504 Masters Tourna… 1 5 4
#> 6 3470 Rory McIlr… 1 401703504 Masters Tourna… 1 6 3
#> # ℹ 3 more variables: score <int>, score_type <chr>, year <int>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()
Strokes gained
Per-round strokes gained averages for the current season ship with the package:
load_strokes_gained("Scheffler")
#> # A tibble: 7 × 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.053 0.115 0.398 0.618 1.13 1.08
#> 2 46046 Scottie Scheff… USA 0.023 0.249 0.145 0.515 0.909 0.932
#> 3 46046 Scottie Scheff… USA 0.202 0.3 0.819 0.356 1.48 1.68
#> 4 46046 Scottie Scheff… USA -0.301 0.399 1.19 1.02 2.62 2.31
#> 5 46046 Scottie Scheff… USA 0.095 0.316 1.27 0.816 2.40 2.50
#> 6 46046 Scottie Scheff… USA 0.382 0.322 1.29 0.748 2.36 2.74
#> 7 46046 Scottie Scheff… USA 0.512 0.471 0.601 0.665 1.74 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().
