The {fantasypl} package is an R package that provides a convenient way to interact with the Fantasy Premier League API endpoints. It leverages the {httr2} package for making HTTP requests and integrates seamlessly with tidyverse packages for data manipulation and analysis.
Installation
You can install the development version of the {fantasypl} package using the {pak} package:
# install.packages("pak")
pak::pak("danieloc1989/fantasypl")
As of this time, there is no intention of releasing the package on CRAN.
Overview
The package offers functions to retrieve various types of information from the Fantasy Premier League API endpoints, such as team data, player statistics, fixtures, and more.
Data Formatting
The data retrieved from the API endpoints are often not in a convenient tabular format. For instance, the ‘bootstrap-static’ endpoint (general information in FPL) returns a list with a mix of dataframes, lists, and other objects:
# API URL
fpl_url <- "https://fantasy.premierleague.com/api"
# Retrieving bootstrap-static endpoint data
general_info <-
httr2::request(fpl_url) |>
httr2::req_url_path_append("bootstrap-static") |>
httr2::req_perform() |>
httr2::resp_body_string() |>
jsonlite::fromJSON()
# First level structure of the bootstrap-static endpoint output
str(general_info, max.level = 1)
#> List of 8
#> $ events :'data.frame': 38 obs. of 23 variables:
#> $ game_settings:List of 28
#> $ phases :'data.frame': 11 obs. of 4 variables:
#> $ teams :'data.frame': 20 obs. of 21 variables:
#> $ total_players: int 9830943
#> $ elements :'data.frame': 714 obs. of 88 variables:
#> $ element_stats:'data.frame': 22 obs. of 2 variables:
#> $ element_types:'data.frame': 4 obs. of 11 variables:
To improve the usability of the data, the {fantasypl} package reformats and organises the data into logical tabular structures.
Example: Team Data
One example is the team data obtained from the ‘teams’ dataframe in the ‘bootstrap-static’ endpoint. By default, the ordering of the columns in the raw data does not make sense:
# Original ordering of columns in teams dataframe
general_info$teams |>
str()
#> 'data.frame': 20 obs. of 21 variables:
#> $ code : int 3 7 91 94 36 90 8 31 11 54 ...
#> $ draw : int 0 0 0 0 0 0 0 0 0 0 ...
#> $ form : logi NA NA NA NA NA NA ...
#> $ id : int 1 2 3 4 5 6 7 8 9 10 ...
#> $ loss : int 0 0 0 0 0 0 0 0 0 0 ...
#> $ name : chr "Arsenal" "Aston Villa" "Bournemouth" "Brentford" ...
#> $ played : int 0 0 0 0 0 0 0 0 0 0 ...
#> $ points : int 0 0 0 0 0 0 0 0 0 0 ...
#> $ position : int 0 0 0 0 0 0 0 0 0 0 ...
#> $ short_name : chr "ARS" "AVL" "BOU" "BRE" ...
#> $ strength : int 4 3 3 3 3 2 3 3 3 3 ...
#> $ team_division : logi NA NA NA NA NA NA ...
#> $ unavailable : logi FALSE FALSE FALSE FALSE FALSE FALSE ...
#> $ win : int 0 0 0 0 0 0 0 0 0 0 ...
#> $ strength_overall_home: int 1230 1115 1060 1125 1165 1060 1115 1100 1075 1095 ...
#> $ strength_overall_away: int 1285 1175 1095 1205 1210 1080 1160 1100 1100 1100 ...
#> $ strength_attack_home : int 1250 1130 1050 1120 1120 1060 1130 1140 1070 1090 ...
#> $ strength_attack_away : int 1250 1190 1100 1220 1200 1080 1210 1170 1120 1090 ...
#> $ strength_defence_home: int 1210 1100 1060 1130 1210 1060 1100 1080 1080 1100 ...
#> $ strength_defence_away: int 1320 1160 1090 1190 1240 1080 1110 1085 1080 1140 ...
#> $ pulse_id : int 1 2 127 130 131 43 4 6 7 34 ...
The {fantasypl} package renames some of the columns and reorganises the data for better readability:
# Improved naming and ordering of columns in teams dataframe
fpl_team_info() |>
str()
#> tibble [20 × 18] (S3: tbl_df/tbl/data.frame)
#> $ team_fpl_code : int [1:20] 3 7 91 94 36 90 8 31 11 54 ...
#> $ team_name : chr [1:20] "Arsenal" "Aston Villa" "Bournemouth" "Brentford" ...
#> $ team_abb : chr [1:20] "ARS" "AVL" "BOU" "BRE" ...
#> $ season_id : int [1:20] 1 2 3 4 5 6 7 8 9 10 ...
#> $ form : logi [1:20] NA NA NA NA NA NA ...
#> $ played : int [1:20] 0 0 0 0 0 0 0 0 0 0 ...
#> $ win : int [1:20] 0 0 0 0 0 0 0 0 0 0 ...
#> $ draw : int [1:20] 0 0 0 0 0 0 0 0 0 0 ...
#> $ loss : int [1:20] 0 0 0 0 0 0 0 0 0 0 ...
#> $ points : int [1:20] 0 0 0 0 0 0 0 0 0 0 ...
#> $ league_position : int [1:20] 0 0 0 0 0 0 0 0 0 0 ...
#> $ strength : int [1:20] 4 3 3 3 3 2 3 3 3 3 ...
#> $ strength_overall_home: int [1:20] 1230 1115 1060 1125 1165 1060 1115 1100 1075 1095 ...
#> $ strength_defence_home: int [1:20] 1210 1100 1060 1130 1210 1060 1100 1080 1080 1100 ...
#> $ strength_attack_home : int [1:20] 1250 1130 1050 1120 1120 1060 1130 1140 1070 1090 ...
#> $ strength_overall_away: int [1:20] 1285 1175 1095 1205 1210 1080 1160 1100 1100 1100 ...
#> $ strength_defence_away: int [1:20] 1320 1160 1090 1190 1240 1080 1110 1085 1080 1140 ...
#> $ strength_attack_away : int [1:20] 1250 1190 1100 1220 1200 1080 1210 1170 1120 1090 ...