GuidesSPORTS APIS
Free football API for JavaScript
For a JavaScript project, 5 free football APIs work straight from fetch() with no private key: OpenLigaDB, the openfootball JSON files, TheSportsDB with its public key 123, Sportscore and ESPN's soccer scoreboard. Of 9 football APIs we tested on 28 October 2026, football-data.org answers its X-Auth-Token preflight with Access-Control-Allow-Origin: http://localhost, so the browser blocks the token on every other origin, and the Fantasy Premier League API sends no CORS header at all. The free cors.dev proxy (no signup, GET and HEAD only, about 600 requests a minute per IP) fixes FPL and football-data.org's token-free lists; the token itself needs cors.dev Pro, $5 a month for 500,000 requests with a 7-day trial of 1,000 requests and no card.
Which free football API to use
Pick OpenLigaDB for current tables, openfootball for fixtures and past seasons, and football-data.org or API-Football for deeper data when a server can hold the key. Each endpoint was called on 28 October 2026 with a browser Origin header and again through https://proxy.cors.dev/.
| API | Free tier | Key | CORS from the browser | Through cors.dev |
|---|---|---|---|---|
| OpenLigaDB | Free community API, Bundesliga and more | None | Yes, any origin | Works, not needed |
| openfootball | Public domain JSON, 8 leagues for 2026-27 | None | Yes, any origin | Works, not needed |
| TheSportsDB | 30 requests per minute, trimmed results | Public key 123 in the path | Yes, any origin | 429, call it directly |
| Sportscore | About 10,000 requests per day per IP | None, attribution link | Yes, any origin | Works, not needed |
| ESPN scoreboard | Unofficial, no published limit | None | Yes, any origin | 403, call it directly |
| Fantasy Premier League | Unofficial, Premier League only | None | No CORS headers | Free tier works |
| football-data.org | 12 competitions, 10 calls per minute | X-Auth-Token header | No, preflight allows http://localhost only | Lists free, token needs cors.dev Pro |
| API-Football | 100 requests per day, 10 per minute | x-apisports-key header | Yes, when the key is sent | Not needed, free tier refuses the key |
| Sportmonks | 2 leagues, 3,000 calls per entity per hour | api_token or Authorization | No CORS headers | Works with api_token in the URL |
Football data with no key and no proxy
OpenLigaDB (api.openligadb.de) is a free community project: reading needs no key or account, and it sends Access-Control-Allow-Origin: *. /getbltable/bl1/2026 returned the 18-team Bundesliga 2026/27 table (4,382 bytes), and /getavailableleagues lists all 840 leagues with shortcuts such as bl1, bl2, la1 and pl.
// OpenLigaDB sends Access-Control-Allow-Origin: *, so call it directly with no key
const league = 'bl1'; // bl2, bl3 and other shortcuts come from /getavailableleagues
const season = 2026; // the year the season starts
const response = await fetch(`https://api.openligadb.de/getbltable/${league}/${season}`);
if (!response.ok) throw new Error(`OpenLigaDB answered ${response.status}`);
const table = await response.json();
table.forEach((team, index) => {
console.log(`${index + 1}. ${team.teamName} ${team.points} pts (${team.goals}:${team.opponentGoals})`);
});Community leagues are only as current as their editors: on 28 October 2026 LaLiga (la1) had results to 25 October, the Premier League (pl) only to 12 October.
openfootball publishes public domain (CC0) JSON on GitHub. The 2026-27 folder holds 8 leagues (en.1, en.2, de.1, es.1, it.1, fr.1, nl.1, pt.1), served with Access-Control-Allow-Origin: * from both raw.githubusercontent.com and cdn.jsdelivr.net. en.1.json lists all 380 Premier League fixtures in 55,359 bytes, but only 45 had a full-time score, the latest from 20 September 2026.
Three more need no private key and send Access-Control-Allow-Origin: *; call each one directly:
- TheSportsDB: the public key
123goes in the path, as in/api/v1/json/123/searchteams.php?t=Arsenal, and free results stop at 1 team per search, 5 table rows and 1 next match. Through cors.dev it answered a Cloudflare429. - Sportscore:
sportscore.com/api/widget/matches/?sport=football&limit=10returned 10 matches with no key. Pages that use the data must show a visible dofollow "Powered by SportScore" link. - ESPN: the unofficial scoreboard at
site.api.espn.com/apis/site/v2/sports/soccer/eng.1/scoreboardreturned 102,731 bytes; call it directly, since ESPN answers403through cors.dev. The ESPN API guide covers its other endpoints.
football-data.org and its localhost-only preflight
football-data.org's free plan covers 12 competitions (PL, ELC, BL1, SA, PD, FL1, DED, PPL, BSA, CL, EC, WC) with fixtures, tables and delayed scores at 10 calls per minute, using a free token in the X-Auth-Token header. Without a token you get 100 requests per 24 hours for the area and competition lists only; /v4/competitions/PL/standings returned 403 "The resource you are looking for is restricted".
The token header triggers a preflight, which football-data.org answered with Access-Control-Allow-Origin: http://localhost for every origin we sent, including http://localhost:5173. Only a page on exactly http://localhost, port 80, matches, so dev servers on other ports and every deployed site get a CORS error with a valid token. The token-free /v4/competitions (190 competitions, 73,822 bytes) has no CORS header either, but returns 200 with one through the free cors.dev proxy.
The token cannot ride on the free tier: a request carrying X-Auth-Token answered 400 with X-Cors-Error: header_not_allowed. cors.dev Pro forwards it for $5 a month and 500,000 requests, with a 7-day trial of 1,000 requests and no card:
- Sign up
Create an account at cors.dev/signup with Google.
- Create a Connection
Add your exact page origin and the target host
api.football-data.org. - Send both headers
Put the Connection's publishable key in
X-Cors-Keyand your token inX-Auth-Token.
const PROXY = 'https://proxy.cors.dev/';
const target = 'https://api.football-data.org/v4/competitions/PL/standings';
const response = await fetch(PROXY + target, {
headers: {
'X-Cors-Key': 'YOUR_CONNECTION_KEY', // publishable, works only from your registered origins
'X-Auth-Token': 'YOUR_FOOTBALL_DATA_TOKEN', // visible in DevTools: internal tools and prototypes only
},
});
const proxyError = response.headers.get('X-Cors-Error');
if (proxyError) throw new Error(`cors.dev: ${proxyError}`);
if (!response.ok) throw new Error(`football-data.org answered ${response.status}`);
const { standings } = await response.json();
const total = standings.find((standing) => standing.type === 'TOTAL');
for (const row of total.table) {
console.log(`${row.position}. ${row.team.shortName} ${row.points} pts, ${row.playedGames} played`);
}The token stays visible in DevTools, and football-data.org's 10 calls per minute still apply. cors.dev Pro fits internal tools, prototypes and apps where each user pastes their own token; a public site running on your token should call football-data.org from a backend.
API-Football keys in the browser
API-Football (v3.football.api-sports.io) takes the key in the x-apisports-key header and works from fetch() directly, no proxy needed. Its preflight answered 204 with Access-Control-Allow-Origin: * and allowed x-apisports-key, x-rapidapi-key and authorization, and a GET with a key header came back with the same wildcard.
Without any key, /status returned 403 with no CORS header, so a missing key shows up as a CORS error; an invalid key returns 200 with an errors.token message. Any visitor can copy the key from DevTools and spend your 100 daily requests, so keep a production key behind a server route. The free cors.dev proxy refuses x-apisports-key with 400 header_not_allowed.
Sportmonks and the Fantasy Premier League API
Sportmonks' free plan covers the Danish Superliga and the Scottish Premiership with 3,000 API calls per entity per hour, no card and no expiry. It sent no CORS headers on its 401 response or on preflight, so fetch() fails, and its FAQ says to keep the token on your server.
The token goes in the api_token query parameter or the Authorization header. The free cors.dev tier refuses Authorization but forwards query strings as-is: a test api_token got Sportmonks' own 401 Invalid token provided back, with CORS headers added. A token in a URL is readable in DevTools, so keep this to prototypes.
The Fantasy Premier League API needs no key but sends no Access-Control-Allow-Origin header. Through the free proxy, fantasy.premierleague.com/api/bootstrap-static/ returned 200 with 1,788,526 bytes, inside the 6 MiB free response limit.
Free limits to plan for
- football-data.org: 10 calls per minute; "Free w/ Livescores" is EUR 12 a month for live scores and 20 calls per minute.
- API-Football: 100 requests per day, 10 per minute and limited seasons. API-Football's Pro plan is $19 a month for 7,500 per day, prepaid with no auto-renewal.
- Sportmonks: 3,000 calls per entity per hour on 2 leagues; Starter is EUR 29 a month for 5 leagues, with a 14-day trial.
- cors.dev: free needs no signup and allows GET and HEAD at about 600 requests a minute per IP, with 6 MiB responses. cors.dev Pro is $5 a month for 500,000 requests at 3,000 requests a minute per account and 100 in flight, and forwards custom headers such as
X-Auth-Token.
Good questions.
Is there a free football API that needs no API key?
Yes. OpenLigaDB, the openfootball JSON files, Sportscore and ESPN's unofficial soccer scoreboard need no key, and TheSportsDB works with its public key 123. All five send Access-Control-Allow-Origin: *, so fetch() works from the browser with no proxy.
Why does football-data.org give a CORS error on localhost?
Its preflight for X-Auth-Token answers Access-Control-Allow-Origin: http://localhost, with no port, whatever origin you send. A dev server on http://localhost:5173 or http://localhost:3000 does not match, so the browser blocks the request even with a valid token. Call it from a server, or through cors.dev Pro, which forwards X-Auth-Token.
Is API-Football free?
Yes: 100 requests per day and 10 per minute, with limited seasons; API-Football's Pro plan costs $19 a month for 7,500 per day. It sends Access-Control-Allow-Origin: * when the x-apisports-key header is present, so it works from the browser, but every visitor can see the key.
Why did the free cors.dev proxy answer 400 header_not_allowed?
The free tier forwards only Accept, Accept-Language, If-None-Match, If-Modified-Since and Range, and answers 400 header_not_allowed to credential headers such as X-Auth-Token, x-apisports-key, X-API-Key and Authorization. A cors.dev Pro Connection key in X-Cors-Key lets them through.
Does cors.dev hide my football API key?
No. A key in browser code, in a header like X-Auth-Token or a URL parameter like api_token, is visible in the DevTools network tab. cors.dev Pro suits internal tools, prototypes and apps where each user brings their own token; a public site running on your key needs a backend.