How to Get Football Data with JavaScript (Node.js) - API Tutorial
Step-by-step JavaScript and Node.js tutorial for fetching football fixtures, match stats and odds via API. Working fetch code examples you can copy.
JavaScript is everywhere - Node.js backends, serverless functions, scripts, and Discord or Telegram bots. TheStatsAPI is a REST JSON API, so the built-in fetch (available in Node.js 18+ and every modern browser) is all you need.
This tutorial shows how to fetch football data with JavaScript: competitions, fixtures, pagination, match stats, and odds. Every example reuses one small get() helper.
Building a frontend instead? See the React and Next.js tutorials. On the client, never expose your API key - proxy requests through your own backend.
Prerequisites
You need:
- Node.js 18+ (for built-in
fetch) - A TheStatsAPI API key
Set your API key as an environment variable:
export THESTATSAPI_KEY="your_api_key"
If you do not have a key yet, sign up at thestatsapi.com for a 7-day free trial.
Create a Small API Client
Create footballApi.js. This uses ES modules, so set "type": "module" in your package.json (or use a .mjs extension).
const API_KEY = process.env.THESTATSAPI_KEY;
const BASE_URL = "https://api.thestatsapi.com/api";
export async function get(endpoint, params = {}) {
const url = new URL(`${BASE_URL}${endpoint}`);
Object.entries(params).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
const res = await fetch(url, {
headers: {
Authorization: `Bearer ${API_KEY}`,
Accept: "application/json",
},
});
if (!res.ok) {
throw new Error(`API request failed: ${res.status} ${res.statusText}`);
}
return res.json();
}
URL and searchParams handle URL-encoding for you. Every example below reuses get().
Fetch Competitions
import { get } from "./footballApi.js";
const result = await get("/football/competitions", { search: "Premier League" });
for (const competition of result.data) {
console.log(competition.id, competition.name, competition.country);
}
Typical output:
comp_3039 Premier League England
Save the competition ID for match and season queries.
Get Fixtures for a League
import { get } from "./footballApi.js";
const result = await get("/football/matches", {
competition_id: "comp_3039",
per_page: 10,
});
for (const match of result.data) {
const { home_team, away_team, status, utc_date } = match;
console.log(`${utc_date} - ${home_team.name} vs ${away_team.name} (${status})`);
}
Add date_from, date_to, season_id, team_id, and status to filter. See the fixtures API for all parameters.
Handle Pagination
List endpoints return a meta block with total_pages.
import { get } from "./footballApi.js";
export async function getAll(endpoint, params = {}) {
let page = 1;
const rows = [];
while (true) {
const result = await get(endpoint, { ...params, page });
rows.push(...result.data);
const totalPages = result.meta?.total_pages ?? 1;
if (page >= totalPages) break;
page += 1;
}
return rows;
}
const matches = await getAll("/football/matches", { competition_id: "comp_3039" });
console.log(`Fetched ${matches.length} matches`);
For data-sync jobs, run this on a schedule and cache results in your database.
Get Match Stats
import { get } from "./footballApi.js";
const { data } = await get("/football/matches/mt_010249745/stats");
const overview = data.overview;
const shots = overview.total_shots.all;
const possession = overview.ball_possession.all;
const xg = overview.expected_goals.all;
console.log(`Shots: ${shots.home} - ${shots.away}`);
console.log(`Possession: ${possession.home} - ${possession.away}`);
console.log(`xG: ${xg.home} - ${xg.away}`);
This powers match centres and form models. See the match stats API and xG API.
Get Pre-Match Odds
import { get } from "./footballApi.js";
const { data } = await get("/football/matches/mt_010249745/odds");
for (const book of data.bookmakers ?? []) {
const matchOdds = book.markets?.match_odds;
if (!matchOdds) continue;
console.log(book.bookmaker, matchOdds);
}
Use /football/matches/{match_id}/odds/live for in-play odds. See the Football Odds API for markets and bookmakers.
CommonJS Version
If your project uses CommonJS (require), the only change is the export and import:
// footballApi.cjs
const API_KEY = process.env.THESTATSAPI_KEY;
const BASE_URL = "https://api.thestatsapi.com/api";
async function get(endpoint, params = {}) {
const url = new URL(`${BASE_URL}${endpoint}`);
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
const res = await fetch(url, {
headers: { Authorization: `Bearer ${API_KEY}`, Accept: "application/json" },
});
if (!res.ok) throw new Error(`API request failed: ${res.status}`);
return res.json();
}
module.exports = { get };
On Node.js 16 or older, install node-fetch and import it, or upgrade to Node 18+ to use native fetch.
Production Tips
- Store the API key in environment variables; never ship it to the browser.
- For frontend apps, proxy API calls through your own server or a serverless function.
- Cache responses (in-memory, Redis, or your database) to respect plan limits.
- Use pagination for backfills and run them outside request handlers.
- Check availability flags such as
xg_availableandlive_odds_available.
FAQ
Can I use JavaScript with TheStatsAPI?
Yes. TheStatsAPI is a REST JSON API, so the built-in fetch in Node.js 18+ and modern browsers works directly. The examples above use fetch with no extra dependencies.
Do I need an SDK or node-fetch?
No SDK is needed. On Node.js 18+ fetch is built in. On older Node versions, install node-fetch or upgrade.
How do I fetch football odds in JavaScript?
Use /football/matches/{match_id}/odds for pre-match odds and /football/matches/{match_id}/odds/live for live odds where available.
Is it safe to call the API from the browser?
Do not put your API key in client-side code. Proxy requests through your own backend or serverless function so the key stays on the server.
Ready to Power Your Sports App?
Start your 7-day free trial. All endpoints included on every plan.