Skip to main content

When APIs Don't Exist, We Make Our Own: A Fantasy Football Data Integration Story

Toby Comer

How reverse engineering ESPN's fantasy football API taught me that determination beats documentation every time

The Problem: Custom League, Custom Problems

It's August, which means one thing in my household: fantasy football draft preparation is in full swing. But here's the thing about our keeper league – it's beautifully complex and frustratingly unique. We use custom scoring rules (6-point passing TDs, no PPR), we can keep players from previous seasons, and ESPN's native app doesn't let us designate keepers properly.

Standard fantasy rankings? Useless. Third-party sites? They don't account for our scoring quirks. ESPN's export features? Non-existent for what we need.

As someone who works at Semaphore Partners implementing ServiceNow solutions, I've learned that when you can't find the integration you need, you build it yourself. Even if that means getting creative with undocumented APIs.

The Solution: When There's No API, Become the API Whisperer

Step 1: Network Tab Detective Work

My first move was opening Chrome's Developer Tools and watching what happened when I loaded ESPN's fantasy rankings. After some digging through the Network tab, I discovered the goldmine:

GET: https://lm-api-reads.fantasy.espn.com/apis/v3/games/ffl/seasons/2025/segments/0/leagues/${LEAGUE_ID}

The magic was in the headers – specifically this beautifully complex filter:

X-Fantasy-Filter: {
  "players": {
    "filterStatus": {"value": ["FREEAGENT","WAIVERS"]},
    "filterSlotIds": {"value": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,23,24]},
    "filterRanksForScoringPeriodIds": {"value": [1]},
    "sortPercOwned": {"sortPriority": 2, "sortAsc": false},
    "sortDraftRanks": {"sortPriority": 100, "sortAsc": true, "value": "STANDARD"},
    "limit": 300
  }
}

You'll also need to copy a cookie from your browser as well, for authentication.

This gives me exactly what I need: all available players with their rankings, ownership percentages, and projected points – all adjusted for our league's specific scoring system.

Step 2: API Testing with RapidAPI

Rather than building a full application, I use RapidAPI (or Paw) to make these calls manually. It's perfect for one-off data pulls and lets me experiment with different filter parameters without writing code.

The response comes back as rich JSON data with everything I need:

{
  "players": [
    {
    "fullName": "Ja'Marr Chase",
    "defaultPositionId": 3,
    "proTeamId": 4,
    "draftRanksByRankType": {
      "STANDARD": {
        "rank": 1,
        "auctionValue": 57
      }
    },
    "ownership": {
      "averageDraftPosition": 1.56,
      "percentOwned": 99.92
    }
  }
  ...

Step 3: Browser Console Magic

Here's where it gets fun. Rather than writing a separate script, I use the browser console to transform the JSON into tab-delimited data which can easily be pasted into Google Sheets:

copy(
  o.players.map(function(x) {
    return [
      x.player.fullName,
      x.player.defaultPositionId,
      x.player.proTeamId,
      x.player.draftRanksByRankType.STANDARD.rank,
      "",
      x.player.ownership.averageDraftPosition,
      x.player.ownership.averageDraftPositionPercentChange,
      x.player.stats[x.player.stats.length-1].appliedTotal
    ].join("\t")
  }).join("\n")
)

This one-liner extracts player name, position, team, rank, ADP, and projected points – perfectly formatted for pasting directly into Google Sheets.

Step 4: Google Sheets as the Ultimate Dashboard

The final piece is my Google Sheets setup. I paste the data and use conditional formatting to:

  • Color-code different positions (WRs in blue, RBs in green, etc.)
  • Highlight players who are already kept (so I know they're off-limits)
  • Create separate columns for each position
    • ex: =QUERY('2025 Raw Data'!A2:J301,"SELECT D, A, J, H, F WHERE I='RB'", -1)

The result? A custom fantasy football dashboard that accounts for our unique league settings and keeper situation.

The Bigger Picture: Integration Philosophy

This little project perfectly illustrates something we live by at Semaphore Partners: there's always a way to integrate, even when there isn't supposed to be one.

Whether it's:

  • Legacy systems without modern APIs
  • SaaS platforms that don't officially support your use case
  • Third-party services with limited export capabilities

The key is being stubborn, determined, and skilled enough to find the data pathways that exist – even if they're not documented or officially supported.

The Technical Lessons

  1. Network inspection is your friend – Most modern web apps are API-driven, even if those APIs aren't public
  2. Browser dev tools are incredibly powerful – You can do sophisticated data transformation without leaving the browser
  3. Don't over-engineer – Sometimes a manual process with the right tools beats a complex automated solution
  4. Google Sheets is more powerful than people think – It's often the perfect middle layer between raw data and actionable insights

The Fantasy Football Confession

Has this elaborate data pipeline helped me win my fantasy league?

Absolutely not. In fact, I have finished dead last more often that I would like to admit. In 2015, I even had to take the SATs (as a 25 year old) as punishment.

But this is my year. I can feel it.

And if it's not, well, at least I'll have the most beautifully formatted last-place roster in fantasy football history.