Skip to main content

ESPN Fantasy

ESPN Fantasy is the system of record for your league and the target of every write. This page summarizes how the system uses it. The worker's reverse-engineering notes hold the protocol detail.

Unofficial endpoints and ESPN's terms

ESPN publishes no fantasy API. The project uses endpoints seen in ESPN's own web app plus browser automation, so ESPN can change or block them at any time. Automating lineup changes, waivers, trades and drafts may conflict with ESPN's terms of use. You're responsible for compliance and use the project at your own risk. See the disclaimer.

The public-release audit decides the final wording of this notice.

Core never writes to ESPN. It validates a request, then publishes a message that a worker bot turns into the ESPN call.

What does it read?​

ReaderMethodDataWhere
Core ingestionespn-api library, mSettings, mRoster, mTeamLeague settings, teams, rosterssync_league
Core ingestionkona_player_infoKicker and D/ST projections, ESPN player IDssync_kicker_dst, sync_skill_position_crosswalk
Core APISame library, cached in RedisCurrent week, standings, box scoresLeague dashboard and matchup services
Worker botsDirect REST view= callsRosters, pending trades, league chat, draft stateespn_api.js
Worker draft botsWebSocketLive picks, turn notices, draft completeDraft sync and clicker

Each view= and its fields are listed in Read views. Cached reads in core expire after 60 to 300 seconds, and a verified write invalidates the league's cache.

What does it write?​

Every write except draft picks is one POST to ESPN's transactions/ endpoint. Dry run, approval and read-back rules are in the Safety model.

ActionMechanismVerification statusWorker page
Lineup and IR movesREST transactionConfirmed against a real saveLineup
Waiver and free-agent claimsREST transactionItem shape partly unverified. FAAB bids aren't implemented.Waiver sniper
Trade proposalsBrowser clicks, with a REST body used to cross-checkSubmit request captured. See Trades.Trade builder
Draft picksSELECT frame on the draft-room socketConfirmed. A DOM click fallback is unverified.Draft clicker
note

Core marks an action accepted when it queues the message. It marks it verified only after a fresh ESPN read shows the change.

How does authentication work?​

ESPN identifies you by two cookies, espn_s2 and SWID. They're your own session credentials, copied from a logged-in browser.

SurfaceNeedsUsed by
REST reads and writes, draft WebSocketThe two cookiesMost bots, core ingestion
Rendered pagesA full interactive login saved as browser session stateTrade builder, draft-room DOM fallback
  • No scripted login. ESPN's login page is protected against automation. A person logs in, and the credentials are stored in OpenBao.
  • Manual renewal. Cookies expire without warning. Renewing them is a manual step, described in Session and auth.
  • Early warning. The espn-session-healthcheck CronJob runs Mondays at 06:00 UTC and fails when the roster page stops rendering.

What can go wrong?​

FailureBehavior
Expired cookiesThe message returns to the queue after 30 seconds and succeeds once you refresh credentials.
League or room not foundTreated as permanent and dropped, so it can't loop.
Rate limitingThere's no ESPN-specific limiter. Volume stays low because one league's actions are infrequent and the queue handles one message per worker at a time.
Locked lineupThe lineup bot refuses to submit.
Unclear outcome after a trade clickThe bot reads pending trades. If that can't settle it, the bot stops for a person.
ESPN changes a request or selectorThe bot fails closed. Update the worker, then retry.

ESPN's rejection codes are decoded in Error codes.

Where is the code?​

AreaRepo and path
League and projection ingestionfantasy-core-pipeline, src/ingestion/
Read cache, dashboardsfantasy-core-pipeline, src/services/
ESPN REST client, auth, botsfantasy-browser-worker, src/bots/
Credentials in the clusterfantasy-infra, overlays/production/