I've got sync working for Yahoo and ESPN (and Sleeper). What have I learned so far?
First off, I suspect that it's a dumb idea to write this post. I feel like I've figured out something that no one else knows, and I'm not sure it's in my best interests to give that to potential competitors.
For some reason, though, I just want to share it. Maybe it's pride, maybe it's just my generous spirit. Or maybe I'm just no good at keeping secrets.
Anyway, let's talk about how everyone else does sync, and what I think is a better way.
One of the nice things about a Chrome extension is that it's code that is all downloaded and then run on your computer. It's just JavaScript, which means it's not compiled and (usually) easy to read.
So I've looked at how other people do sync.
Some sites...well, Yahoo, at least...has a public API that you can use. It's old, from the days when XML was the data protocol of choice, but it's still here. You don't even need a Chrome extension to access it.
I never dug too deep into this option... What's the point if you've got to use other methods for every other site? I think it could be more useful for in-season: It lets you set your lineups from a third party tool. But I'm not sure if draft data is populated here in real-time.
For non-Yahoo sites, you can try to use their unofficial APIs. In this case, you do need a Chrome extension. In order to authenticate on the site, you need to read a user's cookies, and an extension is the smoothest way to do that.
Once again, this is a better option for in-season tools than in-draft ones. The API is used for league pages, and sometimes those don't get updated in the middle of the draft.
For draft tools that need real-time data, the normal thing to do is to scrape data off of the HTML elements on the draft page using a Chrome extension.
This has some problems. First of all, the data is scattered all over the place. You have to pull the league name from the heading, the team names from somewhere else, and the draft picks from another spot.
And those draft picks are the especially tricky part. Yahoo and ESPN both keep a log of picks on the main page, which is the most tempting spot to scrape. But if the user leaves the draft (intentionally or accidentally) that data is gone forever. You need the user to navigate to the draft board to fill in those lost picks, and then you have to merge new picks from the log into that.
Knowing that limitation from other tools, I wasn't convinced that surface-level scraping was the best way to go. So I kept digging in the Chrome Developer Tools and found something interesting.
Both Yahoo and ESPN use React for their draft room. If you're not familiar with it, React is a framework from Facebook that lets you build a webpage that is easy to update without refreshing the page (like Facebook's timeline feed).
To handle updates, the page needs to keep track of its state. You can see how that makes sense in a draft room: The players section can automatically remove players if it knows who has been drafted. The roster section can put those drafted players into your lineup slots. React keeps track of the state of the draft
For Yahoo and ESPN's React-powered draft rooms, if you dig around in the properties of the DOM elements, you can find ones that contain all of the data you need: the league settings, the scoring categories, the positions, all the team info, all the draft picks, and all the player data.
Then, your Chrome extension isn't just looking at the surface data, it's reading the underlying data all from one place. You don't have to worry about leaving the draft room or having the right items displayed on the screen. You just pull everything every couple of seconds when you sync.
I won't go into the full details here, but here are the basics of how I got it working:
__reactFiber$
property on DOM elements and then look at the props
to get the state. The player info section in the top middle seemed to have everything I needed.props
under a __reactInternalInstance$
property. I think the root element has everything you need.dispatchEvent()
to send data from the "MAIN" world content script to an "ISOLATED" content script. That script uses sendMessage()
to pass it to a background script, which uses sendMessage()
again to pass it to DraftKick.I'm not positive all of that is necessary. I couldn't find much info about this, and it took me a lot of trial and error to get it working.
I've decided that after Yahoo and ESPN, my two syncing targets are Sleeper (for football) and Fantrax (for baseball). I'm pretty content to ignore the rest.
I haven't figured out how to crack either of those open (yet). Fantrax uses Angular instead of React, and I don't know how Angular tracks state. Sleeper has some React, but maybe it's Phoenix Liveview that handles populating data?
Both Sleeper and Fantrax put the draft board front and center in the draft room. If you're scraping the HTML, that makes the picks much easier to deal with than on Yahoo and ESPN. However, I don't see an obvious way to get the scoring categories via scrape.
It looks like Sleeper has a public API that is up-to-date. You can get the draft_id from the URL and plug it in:
const response = await fetch("https://sleeper.com/graphql", {
"headers": {
"accept": "application/json",
"accept-language": "",
"content-type": "application/json"
},
"body": "{\"operationName\":\"get_draft\",\"variables\":{},\"query\":\"query get_draft {\\n get_draft(sport: \\\"nfl\\\",draft_id: \\\"1111111111111111111\\\"){\\n created\\n creators\\n draft_id\\n draft_order\\n last_message_time\\n last_message_id\\n last_picked\\n league_id\\n metadata\\n season\\n season_type\\n settings\\n sport\\n status\\n start_time\\n type\\n }\\n\\n user_drafts_by_draft(draft_id: \\\"1111111111111111111\\\"){\\n user_id\\n user_display_name\\n user_avatar\\n user_is_bot\\n metadata\\n }\\n\\n \\n draft_picks(draft_id: \\\"1111111111111111111\\\") {\\n draft_id\\n pick_no\\n player_id\\n picked_by\\n is_keeper\\n metadata\\n reactions\\n }\\n \\n }\"}",
"method": "POST"
});
const data = await response.json();
If you can fetch data from that endpoint, you don't even need a Chrome extension. So maybe Sleeper will be the easiest nut to crack.
Update: Sleeper is now working in DraftKick using their API.
Tired of clunky spreadsheets or falling behind during the draft? It's time to upgrade to DraftKick, the ultimate fantasy football draft assistant.
Now auto-syncs with Yahoo, ESPN, and Sleeper draft rooms!
DraftKick is packed with features to help you succeed on draft day:
It's completely free to try out!
Hi, I'm Mays.
I've been playing and building fantasy tools for over two decades. I started sharing my insights at Last Player Picked way back in 2009 and have helped countless fantasy players along the way.
With DraftKick, I'm bringing all that experience directly to you. It combines my best-in-class valuation algorithms with a fast and easy-to-use interface that gives you a clear edge.
DraftKick takes the guesswork out of player values, providing the data-driven power you need to dominate your leagues.
You can find me on Twitter at @MaysCopeland or email me at [email protected].