How to Scrape FanDuel Odds and Lines in 2026

How to Scrape FanDuel Odds and Lines in 2026

FanDuel is one of the hardest sportsbooks to scrape programmatically in 2026. Their odds pages load dynamically via a private REST API, they rotate Cloudflare JS challenges, and their IP detection is aggressive — geo-restricted by state on top of that. But the data is valuable: real-time lines on NFL, NBA, MLB, NHL, PGA, and dozens of other markets, often updating every few seconds during live games. This guide covers what actually works, what will get you blocked fast, and where the engineering tradeoffs land.

How FanDuel’s odds delivery actually works

FanDuel doesn’t serve odds as static HTML. The page shell loads, then the browser fires a series of fetch calls to https://sbapi.fanduel.com/api/.... Most of the useful data comes from two undocumented endpoints:

  • GET /api/event-page?eventId=... returns full market and runner data for a single game
  • GET /api/content-managed-page?page=SPORT_HOME&... returns lobby odds for a sport’s main page

Both return JSON. No API schema is published, but the response shape has been stable since late 2024.

The complication: every request requires a valid X-Auth-Token header. FanDuel generates this client-side via a fingerprinting flow that varies by state. You can’t replicate it with a static string — you either harvest it from a live browser session or reverse the generation logic, which is obfuscated and changes periodically.

Extracting the auth token and session cookies

The most reliable method is headless browser token extraction. Launch Playwright, navigate to the target state URL (e.g., fanduel.com/pennsylvania), wait for network idle, and intercept outgoing XHR calls to capture the token.

from playwright.sync_api import sync_playwright

def get_fanduel_token(state_url: str) -> dict:
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        ctx = browser.new_context(
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        )
        page = ctx.new_page()
        captured = {}

        def handle_request(req):
            if "sbapi.fanduel.com" in req.url:
                token = req.headers.get("x-auth-token")
                if token:
                    captured["token"] = token
                    captured["cookies"] = ctx.cookies()

        page.on("request", handle_request)
        page.goto(state_url, wait_until="networkidle")
        browser.close()
        return captured

Token lifetime is roughly 30 to 60 minutes. Rotate fresh sessions before expiry rather than refreshing mid-scrape — the silent failure mode is a 200 response with empty markets[], not a clean 401.

One thing to watch: FanDuel geo-gates their API by actual IP location, not just the URL slug. Hitting fanduel.com/new-jersey from a California IP gets a 403 or a redirect to a blocked-state page. You need a residential or mobile proxy in the target state. This is the same geo-blocking mechanic that drives up proxy costs in scraping BetMGM lines across states — budget for it before you start.

Parsing the odds response

Once you have a valid token and matching cookies, the API calls are straightforward. The event-page endpoint returns a nested structure: markets[] containing runners[], each with a winRunnerOdds.americanDisplayOdds.americanOdds field (deeply nested, yes).

Key fields per runner:

  • runnerId — stable identifier for a team or player outcome
  • runnerName — human-readable label
  • americanOdds — moneyline or spread price
  • handicap — the spread value (null for moneylines)
  • marketType — e.g., MATCH_ODDS, ASIAN_HANDICAP, TOTAL_SCORE
  • inPlay — boolean, critical if you’re tracking live odds

For spread and totals markets, handicap carries the line number. Cross-check marketType before assuming structure — FanDuel sometimes nests alternate lines inside the same market object, which will corrupt your data if you parse it naively.

If you’re building a cross-book model, you’ll want to pull from sharper books too. The approach in how to scrape Pinnacle sports lines for sharp models is a solid reference: Pinnacle’s API is more permissive and serves as a useful no-vig baseline for line movement analysis.

Anti-bot detection and what actually bypasses it

FanDuel runs Cloudflare with JS challenge mode on most state subdomains. Headless Chromium without stealth patches fails the challenge in roughly 80% of attempts as of early 2026.

Minimum viable bypass stack, in order:

  1. Use playwright-stealth or puppeteer-extra-plugin-stealth to patch navigator properties
  2. Disable WebDriver flags (--disable-blink-features=AutomationControlled)
  3. Run a real Chrome binary rather than bundled Chromium where possible
  4. Route through a residential proxy with a matching state IP
  5. Add realistic mouse movement and short page interaction before the token extraction

FanDuel’s detection is noticeably more aggresive than DraftKings. If you’re already scraping that book, the guide on how to scrape DraftKings odds and lines covers similar stealth patterns — but FanDuel requires stricter fingerprint consistency across the full session (same IP, same user agent, same viewport from page load through API calls).

For scale above 20 to 30 concurrent sessions, you’ll burn through residential proxies fast. Mobile proxies on a rotating pool help with detection rates but cost more. That tradeoff is real and there’s no clean answer.

Bet365’s session architecture has similar complexity. The rotation and geo-routing patterns in how to scrape Bet365 odds around the world apply here too, particularly if you’re running across multiple state jurisdictions simultaneously.

Provider and approach comparison

MethodToken requiredGeo-restrictionScaleRelative cost
Headless browser (Playwright)Auto-capturedYes, state IPLow-mediumMedium
Reverse-engineered direct APIManual extractionYes, state IPHighLow (after setup)
Third-party odds API (OddsAPI, Sportradar)NoNoHighHigh
Managed scraping service (Bright Data, ScrapeHero)NoHandledHighVery high

For one-off research or model inputs, a third-party odds API is worth it. OddsAPI covers FanDuel lines and costs under $100/month at moderate volume. It doesn’t expose market depth or alternate lines, so if you need that granularity you’re back to direct access. Sportradar has full coverage but pricing is enterprise-grade.

For teams building internal tooling that needs raw market data without an intermediary, the headless extraction approach scales reasonably to around 5 to 10 state markets before operational complexity gets painful. Beyond that, the time cost of maintaining session rotation and stealth patches usually justifies a managed service.

If your scraping pipeline spans data categories beyond sports, it’s worth studying how G2 and Capterra scraping pipelines handle rate limiting and token rotation at scale — the underlying queue and retry architecture transfers well to high-frequency odds collection.

Common error codes and what they mean

ErrorLikely causeFix
403 ForbiddenIP geo-mismatch or Cloudflare blockRotate proxy, re-establish session
401 UnauthorizedToken expired or missing headerRe-extract from fresh browser session
429 Too Many RequestsRate limit hit (~20 req/min per IP)Back off 60s, slow cadence
503 Service UnavailableHigh-traffic game event surgeRetry with exponential backoff
200 with empty markets[]Stale session (silent failure)Log market count, alert on zero

The silent 200 with empty markets is the one that burns you in production. Add a check on len(response["markets"]) per response and treat zero as a session-expired signal.

Bottom line

FanDuel is scrappable in 2026 but it takes real infrastructure: headless stealth browsers, state-matched residential proxies, and solid session rotation. If you just need odds for model inputs or comparison tools, OddsAPI covers FanDuel and saves weeks of engineering overhead. If you need raw market depth and alternate lines, the direct approach outlined here is the path. DRT covers the full sportsbook scraping stack — from FanDuel and DraftKings through international books like Bet365 and Pinnacle — so check back as these APIs and detection layers evolve.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top
message me on telegram

Resources

Proxy Signals Podcast
Operator-level insights on mobile proxies and access infrastructure.

Multi-Account Proxies: Setup, Types, Tools & Mistakes (2026)