# Live Sports Scores API - NBA, NFL, MLB, NHL, NCAAF, EPL, MLS (`neverempty/sports-scores-api`) Actor

Live and historical scores for MLB, NHL, NFL, NBA, NCAAF, Premier League, La Liga and MLS in one identical row shape. Reads official and public league APIs - no HTML scraping, no proxies, and nothing that breaks when a site is redesigned.

- **URL**: https://apify.com/neverempty/sports-scores-api.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Developer tools, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 game row returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Live Sports Scores API - NBA, NFL, MLB, NHL, NCAAF, EPL, MLS

**Eight leagues. One identical row shape. No HTML scraping, no proxies.**

This Actor reads **official and public league APIs** — `statsapi.mlb.com` for MLB, `api-web.nhle.com` for NHL, and ESPN's public scoreboard endpoints for the rest — and normalizes every league into the **same flat columns**, so you can concatenate MLB baseball rows and Premier League football rows without writing a mapping layer.

No HTML parsing. No headless browser. No proxy bill. Nothing that breaks the next time a website is redesigned.

### Leagues covered

| Input value | League | Sport | Source |
|---|---|---|---|
| `mlb` | MLB (Major League Baseball) | Baseball | MLB Stats API (official) |
| `nhl` | NHL (National Hockey League) | Ice hockey | NHL Web API (official) |
| `nfl` | NFL (National Football League) | American football | ESPN public scoreboard |
| `nba` | NBA (National Basketball Association) | Basketball | ESPN public scoreboard |
| `ncaaf` | NCAA Football | College football | ESPN public scoreboard |
| `epl` | Premier League | Soccer / football | ESPN public scoreboard |
| `laliga` | La Liga | Soccer / football | ESPN public scoreboard |
| `mls` | MLS (Major League Soccer) | Soccer / football | ESPN public scoreboard |

### What you get

Scores, schedules, fixtures and results — live, finished and upcoming games — as one row per game:

| Field | Type | Example | Notes |
|---|---|---|---|
| `league` | string | `MLB`, `Premier League` | Which league the row came from |
| `date` | string | `2026-08-23` | Calendar date, `YYYY-MM-DD` |
| `gameId` | string / integer | `824799` | The league's own game identifier |
| `state` | string | `pre` / `in` / `post` | **Normalized across all 8 leagues** |
| `status` | string | `Final`, `Scheduled`, `OFF` | The league's own raw wording |
| `startTimeUtc` | string | `2026-08-23T17:35:00Z` | Kick-off / first pitch, UTC |
| `homeTeam` / `awayTeam` | string | `Baltimore Orioles` / `Tampa Bay Rays` | Team names as the league publishes them |
| `homeScore` / `awayScore` | integer / null | `1` / `3` | **`null` before the game starts** — never a fake `0` |
| `venue` | string | `Oriole Park at Camden Yards` | Stadium / arena |
| `inning` | integer / null | `9` | MLB only |
| `period` | integer / null | `3` | NHL / NFL / NBA / soccer |
| `source` | string | `MLB Stats API (official)` | Which API produced the row |

#### One real row, exactly as the Actor writes it

```json
{
  "league": "MLB",
  "date": "2026-08-23",
  "gameId": 824799,
  "state": "post",
  "status": "Final",
  "startTimeUtc": "2026-08-23T17:35:00Z",
  "homeTeam": "Baltimore Orioles",
  "awayTeam": "Tampa Bay Rays",
  "homeScore": 1,
  "awayScore": 3,
  "venue": "Oriole Park at Camden Yards",
  "inning": 9,
  "source": "MLB Stats API (official)"
}
```

### Two things most sports scrapers get wrong

**1. A game that has not started is not a 0–0 draw.**
ESPN's scoreboard returns `"score": "0"` for fixtures that have not kicked off yet. Copy that straight into a dataset and every upcoming match looks like a goalless draw. This Actor returns `null` for both scores until the game is actually under way, in every league.

**2. Every league words its status differently.**
MLB says `Final`, NHL says `OFF`, ESPN says `Full Time`. You still get each league's raw wording in `status`, but you also get `state`, folded into exactly three values — `pre`, `in`, `post` — so `WHERE state = 'post'` works across all eight leagues without a lookup table.

### Input

Everything is optional. Run it with no input at all and you get the last 7 days across 7 leagues.

```json
{
  "leagues": ["mlb", "nhl", "nfl", "nba", "epl", "laliga", "mls"],
  "daysBack": 7
}
```

Or ask for specific dates:

```json
{
  "leagues": ["epl", "laliga"],
  "dates": ["2026-08-23", "2026-08-22"]
}
```

| Field | Default | Meaning |
|---|---|---|
| `leagues` | 7 leagues (all but `ncaaf`) | Which leagues to pull |
| `dates` | empty | Specific `YYYY-MM-DD` dates. Overrides `daysBack` |
| `daysBack` | `7` | How many days back from today, when no dates are given |
| `maxRetries` | `3` | Retries per league/day if an API returns an error or something that is not JSON |

The wide default is deliberate. The eight leagues have different seasons, so a narrow default would return an empty dataset in the middle of the year. Seven leagues across seven days always has games in it.

### Pricing

### A league with no games still gets a row

Most scoreboard Actors return nothing for a league that is out of season. You get a table, you count the leagues in it, one is missing — and you cannot tell whether the league is in its offseason or whether the Actor quietly failed for it.

This one always answers. Every league × date you ask for produces at least one row, and `rowType` says which kind:

| `rowType` | `ok` | What it means | Charged? |
|---|---|---|---|
| `game` | `true` | A real fixture. All the score columns are filled | **Yes** |
| `no-games` | `true` | The official API answered normally and had nothing scheduled. Baseball in January | **No** |
| `unavailable` | `false` | We could not reach the source after every retry. `reason` carries the error | **No** |

The score columns on a `no-games` or `unavailable` row are `null`, never `0`. A `0-0` would be indistinguishable from a real goalless draw.

Verified on 2026-08-27: asking for MLB, NHL and the Premier League on `2026-01-15` returns 12 rows — 10 NHL fixtures, plus one `no-games` row each for MLB and the Premier League, both of which are out of season on that date.

**You are charged per game actually returned** — not per run, not per hour, not per request. A day with no games in it costs nothing.

### How to use it

1. Click **Try for free** and hit **Start** — the defaults already produce a full dataset.
2. Narrow it down: pick your leagues, or pass exact dates.
3. Export the dataset as JSON, CSV, Excel, or pull it from the Apify API.
4. To keep it fresh, schedule it — daily, hourly, or every few minutes during a game.

Works from the Apify API, the JavaScript and Python clients, MCP, and any HTTP client.

### Typical uses

- A scoreboard or live-score widget on a site or app
- Loading historical results into a database for analysis or modelling
- Fantasy-league and betting-model inputs
- Alerts and bots that fire when a game ends
- Any pipeline that needs baseball, hockey, football, basketball and soccer results in one schema

### FAQ

**Does this need a proxy?**
No. It reads public APIs directly. No proxy configuration, no proxy cost.

**Will it break when a sports website changes its design?**
Site redesigns do not touch these endpoints, because nothing here parses HTML.

**What happens out of season?**
You get zero rows for that league and a clean run — not an error. That is why the default spans several leagues at once.

**Can I get one league only?**
Yes — pass a single value, e.g. `{"leagues": ["nhl"]}`.

**Is live, in-progress data included?**
Yes. Games under way come back with `state: "in"` and the current score, plus `inning` (MLB) or `period`.

**How far back can I go?**
Pass any past date in `dates`. The leagues' own archives go back years.

### Other tools by NeverEmpty

Every NeverEmpty Actor follows the same rule: it never returns an empty result to mean two different things, and it only charges for rows that actually carry an answer.

- **[us-weather-forecast-api](https://apify.com/neverempty/us-weather-forecast-api)** - US forecasts from the official National Weather Service API
- **[earthquakes-usgs](https://apify.com/neverempty/earthquakes-usgs)** - earthquakes from the official USGS feed

### Support

Found a wrong row, a missing league, or a field you need? Open an issue on the Actor's **Issues** tab. Reports about incorrect data are fixed first.

# Actor input Schema

## `leagues` (type: `array`):

Which leagues to pull. MLB and NHL come from the leagues own official APIs; the rest from ESPN public scoreboards. All of them return the same columns.

## `dates` (type: `array`):

Leave empty to use 'Days back' instead.

## `daysBack` (type: `integer`):

Used only when no specific dates are given. The default of 7 days across all leagues is deliberate: it guarantees a non-empty result at any time of year, since the leagues have different seasons.

## `maxRetries` (type: `integer`):

How many times to retry a league/day if the official API returns an error or an unexpected response.

## Actor input object example

```json
{
  "leagues": [
    "mlb",
    "nhl",
    "nfl",
    "nba",
    "epl",
    "laliga",
    "mls"
  ],
  "dates": [],
  "daysBack": 7,
  "maxRetries": 3
}
```

# Actor output Schema

## `results` (type: `string`):

All rows produced by this run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/sports-scores-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/sports-scores-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call neverempty/sports-scores-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/sports-scores-api"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6tXP1K67g8PnH5NIf/builds/suYjenbnpzQ4iqasc/openapi.json
