TUTORIAL

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.

5 min read

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_available and live_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.

Start building today

Ready to Power Your Sports App?

Start your 7-day free trial. All endpoints included on every plan.

Cancel anytime
7-day free trial
Setup in 5 minutes