Introduction: Fantasy LoL Is Massive
Fantasy esports is one of the fastest-growing segments in gaming. Millions of LoL fans already pick their favorite pros for weekly fantasy matchups, and the demand for better tools keeps growing.
In this guide, you'll learn how to build a fantasy League of Legends platform with:
- Player projections based on historical stats
- Live scoring that updates during matches
- Optimal lineup suggestions
- Salary cap and draft mechanics
Whether you're building a full fantasy platform or adding fantasy features to your Discord server, this guide covers the API integration you need.
The Fantasy LoL Data Model
Every fantasy platform needs these core data points:
Player Fantasy Stats
The stats that generate fantasy points:
- Kills: +3 points
- Deaths: -1 point
- Assists: +2 points
- CS (per 100): +1 point
- Triple kills: +2 bonus
- Quadra kills: +5 bonus
- Penta kills: +10 bonus
- Win: +2 points
What You Need From the API
- Player career stats (for projections)
- Live game stats (for scoring)
- Upcoming schedule (for lineup deadlines)
- Team matchups (for strength-of-schedule)
The Cito API has dedicated fantasy endpoints for exactly this.
Getting Started
mkdir lol-fantasycd lol-fantasynpm init -ynpm install axios dotenv
// api.jsconst axios = require('axios');require('dotenv').config(); const api = axios.create({ baseURL: 'https://api.citoapi.com/api/v1/lol', headers: { 'x-api-key': process.env.CITO_API_KEY },}); module.exports = api;
const api = require('./api'); async function getProjections() { const { data } = await api.get('/fantasy/projections/players'); return data;} async function showTopProjections() { const projections = await getProjections(); console.log('Top Fantasy Projections This Week:\n'); console.log('Player | Team | Proj | Salary'); console.log('----------------|---------|-------|-------'); projections.data .sort((a, b) => b.projectedPoints - a.projectedPoints) .slice(0, 20) .forEach(p => { console.log( `${p.name.padEnd(16)}| ${p.team.padEnd(8)}| ${p.projectedPoints.toFixed(1).padStart(5)} | $${p.salary}` ); });} showTopProjections();
const SCORING = { kills: 3, deaths: -1, assists: 2, cs100: 1, // per 100 CS tripleKill: 2, quadraKill: 5, pentaKill: 10, win: 2,}; function calculatePoints(gameStats) { let points = 0; points += (gameStats.kills || 0) * SCORING.kills; points += (gameStats.deaths || 0) * SCORING.deaths; points += (gameStats.assists || 0) * SCORING.assists; points += Math.floor((gameStats.cs || 0) / 100) * SCORING.cs100; points += (gameStats.tripleKills || 0) * SCORING.tripleKill; points += (gameStats.quadraKills || 0) * SCORING.quadraKill; points += (gameStats.pentaKills || 0) * SCORING.pentaKill; if (gameStats.win) points += SCORING.win; return points;} // Example: Faker's game statsconst fakerGame = { kills: 5, deaths: 1, assists: 8, cs: 312, tripleKills: 1, quadraKills: 0, pentaKills: 0, win: true}; console.log(`Fantasy points: ${calculatePoints(fakerGame)}`);// kills(15) + deaths(-1) + assists(16) + cs(3) + triple(2) + win(2) = 37
async function getLiveFantasyScores(rosterPlayerIds) { const { data } = await api.get('/live'); if (!data.data || data.data.length === 0) { return { live: false, scores: [] }; } const scores = []; for (const match of data.data) { // Get detailed game stats const gameData = await api.get(`/live/${match.gameId}/stats`); for (const player of gameData.data.players) { if (rosterPlayerIds.includes(player.id)) { scores.push({ playerId: player.id, name: player.name, team: player.team, currentPoints: calculatePoints(player.stats), stats: player.stats, gameStatus: match.status, }); } } } return { live: true, scores };} // Check scores for your rosterconst myRoster = ['faker', 'chovy', 'zeus', 'keria', 'peyz'];const scores = await getLiveFantasyScores(myRoster); if (scores.live) { console.log('LIVE Fantasy Scores:\n'); scores.scores.forEach(s => { console.log(`${s.name} (${s.team}): ${s.currentPoints} pts`); console.log(` K/D/A: ${s.stats.kills}/${s.stats.deaths}/${s.stats.assists}\n`); });}
async function getOptimalLineup() { const { data } = await api.get('/fantasy/optimal'); return data;} async function showOptimalLineup() { const optimal = await getOptimalLineup(); console.log('Optimal Fantasy Lineup:\n'); console.log(`Total Projected: ${optimal.data.totalProjected.toFixed(1)} pts`); console.log(`Salary Used: $${optimal.data.salaryUsed} / $${optimal.data.salaryCap}\n`); optimal.data.players.forEach(p => { console.log(`[${p.role}] ${p.name} (${p.team}) - ${p.projected.toFixed(1)} pts - $${p.salary}`); });} showOptimalLineup();
function optimizeLineup(players, salaryCap = 50000) { const roles = ['TOP', 'JNG', 'MID', 'ADC', 'SUP']; const byRole = {}; // Group players by role roles.forEach(role => { byRole[role] = players .filter(p => p.role === role) .sort((a, b) => (b.projectedPoints / b.salary) - (a.projectedPoints / a.salary)); }); // Greedy approach: pick best value per role let lineup = []; let remainingSalary = salaryCap; roles.forEach(role => { const affordable = byRole[role].filter(p => p.salary <= remainingSalary); if (affordable.length > 0) { lineup.push(affordable[0]); remainingSalary -= affordable[0].salary; } }); return { players: lineup, totalProjected: lineup.reduce((sum, p) => sum + p.projectedPoints, 0), salaryUsed: salaryCap - remainingSalary, };}
async function getValueRankings() { const { data } = await api.get('/fantasy/value'); return data;} async function showSleepers() { const value = await getValueRankings(); console.log('Top Fantasy Sleepers (Best Value):\n'); value.data.slice(0, 10).forEach((p, i) => { console.log(`${i + 1}. ${p.name} (${p.team}) - ${p.projectedPoints.toFixed(1)} pts @ $${p.salary}`); console.log(` Value Score: ${p.valueScore.toFixed(2)} | Ownership: ${p.ownership}%\n`); });} showSleepers();
async function analyzeMatchup(playerId) { const [stats, schedule] = await Promise.all([ api.get(`/players/${playerId}/stats`), api.get('/schedule/week'), ]); const player = stats.data.data; // Find this player's upcoming match const nextMatch = schedule.data.data.find(m => m.team1 === player.team || m.team2 === player.team ); if (!nextMatch) return null; const opponent = nextMatch.team1 === player.team ? nextMatch.team2 : nextMatch.team1; // Get opponent's defensive stats const opponentStats = await api.get(`/teams/${opponent}/stats`); return { player: player.name, opponent, playerKDA: player.kda, opponentGamesAllowed: opponentStats.data.data.avgKillsAllowed, projection: player.projectedPoints, matchupBoost: opponentStats.data.data.avgKillsAllowed > 15 ? 'GOOD' : 'TOUGH', };}
class FantasyDashboard { constructor(api) { this.api = api; } async getWeeklyOverview() { const [projections, optimal, value, schedule] = await Promise.all([ this.api.get('/fantasy/projections/players'), this.api.get('/fantasy/optimal'), this.api.get('/fantasy/value'), this.api.get('/schedule/week'), ]); return { topProjections: projections.data.data.slice(0, 20), optimalLineup: optimal.data, sleepers: value.data.data.slice(0, 10), matchesThisWeek: schedule.data.data.length, }; } async getPlayerCard(playerId) { const [stats, fantasy, champions] = await Promise.all([ this.api.get(`/players/${playerId}/stats`), this.api.get(`/fantasy/stats/players/${playerId}`), this.api.get(`/players/${playerId}/champions`), ]); return { stats: stats.data, fantasy: fantasy.data, topChampions: champions.data.data?.slice(0, 5), }; }} // Usageconst dashboard = new FantasyDashboard(api);const overview = await dashboard.getWeeklyOverview();console.log(`${overview.matchesThisWeek} matches this week`);console.log(`Best pick: ${overview.topProjections[0].name}`);
// !fantasy top — Show top projected players// !fantasy lineup — Show optimal lineup// !fantasy sleepers — Show undervalued players// !fantasy player <name> — Show player fantasy card
Check out our Discord bot tutorial for the full bot setup, then add these fantasy commands on top.
Get Started
The Cito API's fantasy endpoints make it straightforward to build a fantasy LoL platform:
Sign up for free — 500 calls/month to prototype
Test the fantasy endpoints in the dashboard sandbox
Build your scoring engine using the code above
Deploy and share with your leagueThe fantasy endpoints are available on all plans, including the free tier.
Get your free API key and start building your fantasy LoL platform today.
---
Related reading: