Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.fieldfunded.com/llms.txt

Use this file to discover all available pages before exploring further.

Build a Twitch Esports Overlay with Live Odds

Show real-time esports odds directly on your stream. Viewers see odds updating live as the game progresses.

What You’ll Use

SDK MethodEndpointPurpose
getEvents()GET /v1/eventsFind esports events
getLive()GET /v1/liveGet live esports matches
getEventOdds()GET /v1/events/{id}/oddsReal-time odds
getScores()GET /v1/scoresCurrent map/round scores
getSports()GET /v1/sportsList esports categories

How Twitch Overlays Work

OBS Studio has a “Browser Source” that renders any URL as a transparent overlay on your stream. You build a web page → OBS renders it on top of your game.

Step 1: Find Esports Events

FieldFunded covers esports under specific sport keys. Check available esports:
const sports = await client.getSports();
const esports = sports.sports.filter(s => s.is_esport);
// e.g. 'esports-csgo', 'esports-lol', 'esports-dota2', 'esports-valorant'
Get live esports matches:
const liveEsports = await client.getLive({
  sport: 'esports-csgo', // CS2
});

Step 2: Build the Overlay Page

<!DOCTYPE html>
<html>
<head>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      background: transparent;
      font-family: 'Inter', sans-serif;
      color: #fff;
    }

    .overlay {
      position: fixed;
      bottom: 20px;
      right: 20px;
      background: rgba(10, 10, 30, 0.85);
      border: 1px solid #53FC18;
      border-radius: 12px;
      padding: 16px;
      min-width: 280px;
      backdrop-filter: blur(10px);
    }

    .match-title {
      font-size: 14px;
      font-weight: 600;
      margin-bottom: 8px;
      color: #53FC18;
    }

    .teams {
      display: flex;
      justify-content: space-between;
      margin-bottom: 12px;
    }

    .team {
      text-align: center;
      flex: 1;
    }

    .team-name { font-size: 13px; font-weight: 500; }

    .odds {
      font-size: 18px;
      font-weight: 700;
      padding: 4px 8px;
      background: rgba(83, 252, 24, 0.15);
      border-radius: 6px;
      margin-top: 4px;
      display: inline-block;
    }

    .score {
      text-align: center;
      font-size: 24px;
      font-weight: 700;
      color: #53FC18;
    }

    .map-score { font-size: 11px; color: #aaa; margin-top: 2px; }

    .vs { color: #666; font-size: 12px; }

    @keyframes pulse {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.7; }
    }

    .live-dot {
      width: 8px;
      height: 8px;
      background: #ff4444;
      border-radius: 50%;
      display: inline-block;
      animation: pulse 1.5s infinite;
      margin-right: 6px;
    }
  </style>
</head>
<body>
  <div class="overlay" id="overlay">
    <div class="match-title">
      <span class="live-dot"></span>
      <span id="league">Loading...</span>
    </div>
    <div class="teams">
      <div class="team">
        <div class="team-name" id="team1"></div>
        <div class="odds" id="odds1"></div>
      </div>
      <div class="score">
        <span id="score1">0</span>
        <span class="vs"> - </span>
        <span id="score2">0</span>
        <div class="map-score" id="mapScore"></div>
      </div>
      <div class="team">
        <div class="team-name" id="team2"></div>
        <div class="odds" id="odds2"></div>
      </div>
    </div>
  </div>

  <script>
    const API_KEY = 'YOUR_API_KEY';
    const BASE = 'https://api.fieldfunded.com/v1';
    const SPORT = 'esports-csgo'; // Change for LoL, Dota, Valorant
    const POLL_INTERVAL = 15000; // 15 seconds

    async function api(path) {
      const res = await fetch(`${BASE}${path}`, {
        headers: { 'X-API-Key': API_KEY },
      });
      return res.json();
    }

    async function update() {
      try {
        const live = await api(`/live?sport=${SPORT}`);
        if (!live.events || live.events.length === 0) {
          document.getElementById('league').textContent = 'No live match';
          return;
        }

        const event = live.events[0]; // First live match
        const odds = await api(`/events/${event.id}/odds`);

        document.getElementById('league').textContent = event.league;
        document.getElementById('team1').textContent = event.home_team;
        document.getElementById('team2').textContent = event.away_team;

        // Score
        if (event.scoreboard) {
          document.getElementById('score1').textContent = event.scoreboard.home || '0';
          document.getElementById('score2').textContent = event.scoreboard.away || '0';
        }

        // Main market odds
        if (odds.markets && odds.markets.length > 0) {
          const main = odds.markets[0];
          if (main.selections.length >= 2) {
            document.getElementById('odds1').textContent = main.selections[0].odds;
            document.getElementById('odds2').textContent = main.selections[1].odds;
          }
        }
      } catch (err) {
        console.error('Update failed:', err);
      }
    }

    update();
    setInterval(update, POLL_INTERVAL);
  </script>
</body>
</html>

Step 3: Add to OBS

  1. Open OBS Studio
  2. Sources → Add → Browser Source
  3. Point to http://localhost:3000/overlay.html (or host it online)
  4. Set width/height (300×120 works well)
  5. Check “Shutdown source when not visible”

Rate Limit Math

  • Polling every 15 seconds = 2 requests per poll (live + odds)
  • Per hour: 240 requests
  • 4-hour stream: ~960 requests
  • Free tier (10K/month) supports ~10 full streams per month
  • Starter ($29): ~300 streams/month — more than enough

Live Events Reference

See live endpoint docs →

Get Your Free API Key

Start building in 5 minutes — 10,000 free requests/month