Accessing ESPN’s New V3 API for Private Leagues: How We Got Here
This marks post 3 of n of my 2019 ESPN Fantasy Football blog posts. In the last few months, ESPN upgraded their API from V2 to V3, breaking all of our previous work accessing and analysing the data from the API.
In my last two posts, I explored how to access data from ESPN’s V3 API for public leagues. My best efforts to access data for private leagues in R fell short. Using the work from my friend Steve on his blog, I was able to execute Python code inside R chunks with the library reticulate
. I wrote about that process in post 2.
My best efforts to access ESPN’s new API in R fell short, that is, until I asked my friend Nick. Nick crushed this and I’m extremely grateful that he figured it out. I’ll detail below what he did.
A Recap
For public league, you can simply request the data.
We’ll start with our URL. Of course, replace the league ID
with your league ID
. Though I explain the tail
of the URL in detail on my previous post, different derivatives of this will return different data.
base = "http://fantasy.espn.com/apis/v3/games/ffl/seasons/"
year = "2019"
mid = "/segments/0/leagues/"
leagueID = "12345678"
tail = "?view=mDraftDetail&view=mLiveScoring&view=mMatchupScore&view=mPendingTransactions&view=mPositionalRatings&view=mSettings&view=mTeam&view=modular&view=mNav&view=mMatchupScore"
url = paste0(base,year,mid,leagueID,tail)
url
## [1] "http://fantasy.espn.com/apis/v3/games/ffl/seasons/2019/segments/0/leagues/12345678?view=mDraftDetail&view=mLiveScoring&view=mMatchupScore&view=mPendingTransactions&view=mPositionalRatings&view=mSettings&view=mTeam&view=modular&view=mNav&view=mMatchupScore"
Request Private League Data
Unsuccessful Attempts
When requesting the data as the code below shows, we pass the URL to the GET
command.
url = "http://fantasy.espn.com/apis/v3/games/ffl/seasons/2019/segments/0/leagues/89417258?view=mDraftDetail&view=mLiveScoring&view=mMatchupScore&view=mPendingTransactions&view=mPositionalRatings&view=mSettings&view=mTeam&view=modular&view=mNav&view=mMatchupScore&scoringPeriodId=1"
ESPNGet <- httr::GET(url = url)
ESPNGet$status_code
## [1] 200
The status_code
returns 401
. This is good and bad news. Bad news because the API doesn’t return any data. In fact, we are not authorized to view this league
ESPNRaw <- rawToChar(ESPNGet$content)
ESPNFromJSON <- jsonlite::fromJSON(ESPNRaw)
ESPNFromJSON$message
## NULL
But a status_code
of 401
is good news because it means the page exists (IE, we have our URL correct), but that its blocked.
Request Private League Data
Successful Attempts
Exploring the JSON
Now that we have our data, we need to explore the JSON to see what is available. The code below will help you explore what data is available through the API.
listviewer::jsonedit(ESPNFromJSON)
In the meantime, here is an example of the data you can pull from the JSON.
library(tidyverse)
tibble(
AwayID = ESPNFromJSON$schedule$away$teamId,
AwayPoints = ESPNFromJSON$schedule$away$totalPoints,
HomeID =ESPNFromJSON$schedule$home$teamId,
HomePoints = ESPNFromJSON$schedule$home$totalPoints,
Winner =ESPNFromJSON$schedule$winner
) %>%
left_join(
tibble(
id = ESPNFromJSON$teams$id,
AwayTeam = paste(ESPNFromJSON$teams$location,ESPNFromJSON$teams$nickname)
), by = c("AwayID"="id")
) %>%
left_join(
tibble(
id = ESPNFromJSON$teams$id,
HomeTeam = paste(ESPNFromJSON$teams$location,ESPNFromJSON$teams$nickname)
), by = c("HomeID"="id")
)
## # A tibble: 80 x 7
## AwayID AwayPoints HomeID HomePoints Winner AwayTeam HomeTeam
## <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 2 138. 9 97.9 AWAY Philly Chapmania~ Dallas The boys
## 2 3 124. 7 128. HOME The Plainsmen Compute This!
## 3 6 135. 4 108. AWAY Team Ward The OBJective F~
## 4 1 109. 5 120. HOME 'R'm Chair Quart~ Analysis Paraly~
## 5 10 130. 8 156. HOME Palindrome Tikkit The Chief
## 6 6 115. 3 143. HOME Team Ward The Plainsmen
## 7 9 136. 1 100. AWAY Dallas The boys 'R'm Chair Quar~
## 8 2 72.6 10 125. HOME Philly Chapmania~ Palindrome Tikk~
## 9 7 136. 5 120. AWAY Compute This! Analysis Paraly~
## 10 4 145. 8 109. AWAY The OBJective Fu~ The Chief
## # ... with 70 more rows
Future Posts
In future posts, I plan on doing the following:
- Evaluate measures of luck. Which teams win more than they should? Which teams out perform their projections?
- Evaluate ESPN’s projections. How accurate are the projections? Are some positions easier to project than others?
- Evaluate who is the best coach. Which managers are picking their optimal lineup?
Feedback
As always, I do this blog to learn new things, hopefully teach others from my experience, and hopefully receive (respectful and helpful) feedback.
Please leave your thoughts below!!