How to Build a Football Stats Dashboard with React and AI
Build a football stats dashboard with React, TheStatsAPI, and any AI coding tool. Use llms.txt, natural-language prompts, fixtures, player stats, standings, and odds.
You do not need to hand-code a football dashboard from a blank React project anymore. The fastest workflow is to give your AI coding tool the right football API context, describe the product you want in plain English, and let it scaffold the boring parts: routes, components, data fetching, loading states, tables, cards, and API adapters.
TheStatsAPI is built for that workflow. You can use our Build with AI tool to generate a prompt for Claude Code, Cursor, Lovable, Bolt, Replit, Windsurf, or any agentic coding assistant. You can also point your AI tool directly at our site llms.txt and the full API llms.txt, so it uses real endpoints instead of inventing fields.
This guide shows the React dashboard you can build, the AI prompts to use, and the few technical guardrails that matter.
The Fast Path
If you want the shortest route to a working app, do this:
- Open Build with AI.
- Describe your product: "Build me a React football stats dashboard with fixtures, live scores, player search, standings, and odds."
- Copy the generated prompt into your AI coding tool.
- Tell the tool to read
https://api.thestatsapi.com/llms.txtbefore writing code. - Add your TheStatsAPI key on the server side.
- Run the app and iterate feature-by-feature.
That is the workflow this page is designed around. The code examples below are here so you can inspect what the AI should produce, not because you need to type every line by hand.
What You Can Ask AI to Build
A good first version of a React football dashboard usually has five screens or panels:
| Feature | What the user sees | TheStatsAPI endpoint |
|---|---|---|
| Fixtures | Upcoming and recent matches for a league | GET /football/matches |
| Live scores | Currently live matches with polling | GET /football/matches?status=live |
| Player search | Search players and open profile cards | GET /football/players?search={name} |
| League table | Team positions, points, form, goal difference | GET /football/teams + GET /football/teams/{team_id}/stats?season_id={season_id} |
| Odds panel | Bet365, Pinnacle, Betfair Exchange, Kambi prices | GET /football/matches/{match_id}/odds |
The AI should also build the unglamorous production pieces: loading states, empty states, error handling, caching, environment variables, and a server-side API proxy so your key is never exposed in the browser.
Runnable Next.js Starter
If you want real React code before using the AI prompt, start with this small Next.js shape. It keeps your API key server-side, fetches matches through a proxy route, and renders a compact dashboard panel.
Create app/api/thestatsapi/route.ts:
import { NextRequest, NextResponse } from "next/server";
const API_BASE_URL = "https://api.thestatsapi.com/api";
export async function GET(request: NextRequest) {
const upstreamPath = request.nextUrl.searchParams.get("path");
if (!upstreamPath?.startsWith("/football/")) {
return NextResponse.json(
{ error: "Unsupported TheStatsAPI path" },
{ status: 400 }
);
}
const response = await fetch(`${API_BASE_URL}${upstreamPath}`, {
headers: {
Authorization: `Bearer ${process.env.THESTATSAPI_KEY}`,
Accept: "application/json",
},
next: { revalidate: 60 },
});
const body = await response.json();
return NextResponse.json(body, { status: response.status });
}
Create a tiny fetch helper:
export async function fetchFootball<T>(path: string): Promise<T> {
if (!path.startsWith("/football/")) {
throw new Error("TheStatsAPI path must start with /football/");
}
const response = await fetch(
`/api/thestatsapi?path=${encodeURIComponent(path)}`
);
if (!response.ok) {
throw new Error(`TheStatsAPI request failed: ${response.status}`);
}
return response.json();
}
Then render fixtures from a client component:
"use client";
import { useEffect, useState } from "react";
import { fetchFootball } from "./fetchFootball";
type Match = {
id: string;
utc_date: string;
status: string;
home_team: { name: string };
away_team: { name: string };
score?: { home: number | null; away: number | null };
xg_available?: boolean;
live_odds_available?: boolean;
};
type MatchResponse = {
data: Match[];
};
export function FootballDashboard() {
const [matches, setMatches] = useState<Match[]>([]);
const [status, setStatus] = useState<"loading" | "ready" | "error">("loading");
useEffect(() => {
fetchFootball<MatchResponse>("/football/matches?per_page=10")
.then((result) => {
setMatches(result.data);
setStatus("ready");
})
.catch(() => setStatus("error"));
}, []);
if (status === "loading") return <p>Loading fixtures...</p>;
if (status === "error") return <p>Could not load fixtures.</p>;
if (matches.length === 0) return <p>No fixtures found.</p>;
return (
<section>
<h2>Fixtures</h2>
<div>
{matches.map((match) => (
<article key={match.id}>
<time>{new Date(match.utc_date).toLocaleString()}</time>
<strong>
{match.home_team.name} {match.score?.home ?? "-"} -{" "}
{match.score?.away ?? "-"} {match.away_team.name}
</strong>
<small>
{match.status}
{match.xg_available ? " · xG available" : ""}
{match.live_odds_available ? " · live odds available" : ""}
</small>
</article>
))}
</div>
</section>
);
}
Put THESTATSAPI_KEY in .env.local, restart your dev server, and build outward from this first working data path: competition selector, season picker, player search, odds panel, and match details.
Prompt: Build the First Version
Paste this into your coding agent. It works best after you add your app framework preference, styling preference, and whether you want Vite, Next.js, or an existing repo.
Read this API reference before coding: https://api.thestatsapi.com/llms.txt
Build a React football stats dashboard using TheStatsAPI.
Requirements:
- Keep the API key server-side. Do not expose it in browser code.
- Create a backend proxy route under /api/thestatsapi that accepts a validated upstream path and adds the Bearer token.
- Build a dashboard with these panels:
- Fixtures for a selected competition
- Live scores with 30-second polling
- Player search with debounced input
- League table built from team season stats
- Optional odds panel for a selected match
- Use real endpoint paths and response fields from llms.txt only.
- Include loading, empty, and error states.
- Add a small config file for competition_id and season_id.
- Keep the UI clean, dense, and useful for a sports data product.
Use these endpoints:
- GET /football/competitions
- GET /football/competitions/{competition_id}/seasons
- GET /football/matches
- GET /football/players
- GET /football/teams
- GET /football/teams/{team_id}/stats
- GET /football/matches/{match_id}/odds
After implementing, explain where to put THESTATSAPI_KEY and how to run the app.
This prompt is intentionally specific. It tells the agent what to build, where the API truth lives, and what not to do.
Why llms.txt Matters
AI tools are good at React, but they often guess API shapes. That is where sports-data projects go wrong: one invented field name can break an entire dashboard.
TheStatsAPI publishes machine-readable docs for AI tools:
- Site llms.txt explains the product, core URLs, and important pages.
- API llms.txt lists the actual API endpoints, parameters, response fields, and data models.
When your coding agent reads the API llms file first, it can build against real paths like:
GET /football/matches
GET /football/players
GET /football/competitions/{competition_id}/seasons
GET /football/teams/{team_id}/stats
GET /football/matches/{match_id}/odds
GET /football/matches/{match_id}/odds/live
That is much safer than asking it to "use a football API" and hoping it guesses correctly.
Agentic Workflow: From Idea to Product
Here is a practical agent workflow that works well with Claude Code, Cursor agents, or similar tools.
Step 1: Product brief
Start with the user outcome, not the code:
I want a soccer/football dashboard for MLS and Premier League fans.
Users should pick a league, see upcoming fixtures, check live scores,
search players, and inspect match odds. The app should feel like a
developer tool, not a marketing landing page.
Step 2: Data plan
Ask the agent to map features to endpoints before it codes:
Before writing code, read https://api.thestatsapi.com/llms.txt and make a data plan.
For each dashboard feature, list the endpoint, required query params,
fields used, cache strategy, and empty-state behavior.
Do not implement until the data plan is complete.
Step 3: Scaffold
Let it create the app structure:
Implement the dashboard using React components:
- FootballApiClient
- FixturesPanel
- LiveScoresPanel
- PlayerSearch
- LeagueTable
- MatchOddsPanel
- ErrorMessage
- EmptyState
Use a server-side proxy for TheStatsAPI requests.
Step 4: Iterate
Once the first version runs, use smaller prompts:
Improve the fixtures panel so finished matches, live matches, and scheduled matches
are visually distinct. Keep the layout compact and scannable.
Add a match detail drawer. When a user clicks a fixture, fetch match stats and odds
if available. Show xG, shots, possession, corners, and 1X2 odds.
Add defensive error handling for unavailable data. If xG or odds are missing,
show a neutral empty state instead of throwing.
This is where agentic coding is strongest: the first prompt gets you a working base, then each follow-up improves one visible workflow.
Backend Proxy Pattern
For a React app, the most important rule is simple: keep the API key out of the browser.
Your frontend should call your own backend. A simple pattern is to pass the upstream TheStatsAPI path as a query parameter and validate it server-side:
export async function fetchFootball<T>(path: string): Promise<T> {
if (!path.startsWith("/football/")) {
throw new Error("TheStatsAPI path must start with /football/");
}
const response = await fetch(
`/api/thestatsapi?path=${encodeURIComponent(path)}`
);
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
return response.json();
}
Your backend route then validates that path and calls TheStatsAPI:
const API_BASE_URL = "https://api.thestatsapi.com/api";
export async function proxyFootballRequest(path: string) {
if (!path.startsWith("/football/")) {
throw new Error("Unsupported TheStatsAPI path");
}
const response = await fetch(`${API_BASE_URL}${path}`, {
headers: {
Authorization: `Bearer ${process.env.THESTATSAPI_KEY}`,
Accept: "application/json",
},
});
if (!response.ok) {
throw new Error(`TheStatsAPI error: ${response.status}`);
}
return response.json();
}
If you are using Next.js, put this in a route handler. If you are using Vite React, use a small Express, Fastify, Hono, or serverless backend.
Feature Prompts
Use these as follow-up prompts after the first dashboard exists.
Fixtures
Add a fixtures panel using GET /football/matches.
Support competition_id, season_id, status, date_from, and date_to filters.
Show home team, away team, score, status, UTC date, and xg_available.
Add loading, empty, and error states.
Seasons
Add a season picker using GET /football/competitions/{competition_id}/seasons.
Default to the season where is_current is true. Store season_id in dashboard config
and use it when fetching team stats or season-specific matches.
Live Scores
Add a live scores panel using GET /football/matches?status=live.
Poll every 30 seconds, stop polling when the component unmounts,
and show a quiet empty state when no matches are live.
Player Search
Add player search using GET /football/players?search={query}.
Debounce input by 300ms. Show player name, position, nationality,
current team, and a link to fetch season stats later.
League Table
Build a league table by first fetching teams with GET /football/teams,
then fetching each team's stats with GET /football/teams/{team_id}/stats.
Use competition_id and season_id when fetching teams, and pass season_id to
the team stats endpoint. Sort by position. Show played, wins, draws, losses,
goal difference, points, and form.
Odds
Add a match odds panel using GET /football/matches/{match_id}/odds.
Show bookmaker, 1X2 prices, BTTS, total goals, corners, and Asian handicap
when fields are present. If odds are unavailable, show a neutral empty state.
Minimal Component Shape
The AI should produce components roughly like this:
type Match = {
id: string;
utc_date: string;
status: string;
home_team: { id: string; name: string };
away_team: { id: string; name: string };
score?: { home: number | null; away: number | null };
xg_available?: boolean;
live_odds_available?: boolean;
};
function MatchCard({ match }: { match: Match }) {
return (
<article>
<time>{new Date(match.utc_date).toLocaleString()}</time>
<div>
{match.home_team.name} {match.score?.home ?? "-"} -{" "}
{match.score?.away ?? "-"} {match.away_team.name}
</div>
<small>{match.status}</small>
</article>
);
}
Keep the UI straightforward at first. Once the data flow works, ask the agent to improve the layout, filters, and match detail view.
Better Than Starting from Scratch
The old way to build this page was:
- Read API docs.
- Copy endpoint examples.
- Create types.
- Build fetch helpers.
- Add components.
- Debug wrong fields.
- Add states and caching.
The better way:
- Use Build with AI to generate the prompt.
- Tell your agent to read API llms.txt.
- Let it scaffold the app.
- Iterate in natural language.
- Test the flows that matter to your users.
That is faster, and it produces a cleaner first version because the AI has the actual API contract in context.
Production Checklist
- Keep
THESTATSAPI_KEYserver-side. - Cache fixtures, teams, and player searches.
- Poll only live matches, not every dashboard panel.
- Treat odds, xG, and live data as availability-dependent.
- Add empty states for unsupported competitions or missing match data.
- Log endpoint, params, and status code for failed proxy requests.
- Use API llms.txt whenever adding a new endpoint.
FAQ
Can I build a React football dashboard with AI?
Yes. Use Build with AI to generate a prompt, then give your coding agent the full API llms.txt so it builds against real endpoint paths and fields.
Can I call TheStatsAPI directly from React?
Do not do that in production. Browser code exposes secrets. Use a backend proxy, serverless function, or a framework with server-side data fetching.
What should I ask my AI tool first?
Ask it to read https://api.thestatsapi.com/llms.txt, create a data plan, and map each product feature to exact endpoints before writing code.
Can I use this with Cursor, Claude Code, Lovable, Bolt, or Replit?
Yes. The workflow is tool-agnostic. Any coding assistant that can read URLs or accept pasted docs can use the llms.txt context and the prompts above.
Can I build this with Next.js instead?
Yes. Next.js is often the best production path because route handlers and server components make it easy to keep your API key server-side. See the Next.js football dashboard tutorial.
Ready to Power Your Sports App?
Start your 7-day free trial. All endpoints included on every plan.