# Sports Scores by Date — Fixtures & Tables (`xtracto/espn-scoreboard`) Actor

Scores and fixtures for any date, month or season across NFL, NBA, MLB, NHL, college and world football: per-period scores, team records, venue, TV listings, statistical leaders and league tables. Keyless, HTTP-only.

- **URL**: https://apify.com/xtracto/espn-scoreboard.md
- **Developed by:** [Farhan Febrian Nauval](https://apify.com/xtracto) (community)
- **Categories:** Other, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.25 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## ESPN Scoreboard Scraper

Scores, fixtures and league tables **for any date, month or season** — NFL, NBA, MLB,
NHL, WNBA, college football and basketball, and world football.

HTTP-only. Keyless, no login, no browser.

### Why this exists next to a matches scraper

This repo already has `sports/sofascore-matches`, and its own notes record the gap that
this actor fills: **SofaScore has no date-based fixture endpoint.** Five path shapes
were tried there, all 404. A question as ordinary as *"what was played on 12 September?"*
could not be answered.

ESPN answers it, and carries things SofaScore does not: per-period scores, team win-loss
records, TV broadcast listings, statistical leaders with named players, attendance, and
league tables with qualification zones.

### What you get

| Field | Example |
|---|---|
| `shortName` / `name` | `DET @ BUF` / `Detroit Lions at Buffalo Bills` |
| `startsAt` | `2026-09-18T00:15Z` |
| `statusName` / `statusDetail` / `isCompleted` | `STATUS_FINAL` / `Final` / `true` |
| `homeTeam` / `homeScore` / `homeRecord` | `Buffalo Bills` / `41` / `2-0` |
| `awayTeam` / `awayScore` / `awayRecord` | `Detroit Lions` / `31` / `1-1` |
| `winner` | `home`, `away` or `draw` |
| `venue` / `venueCity` / `attendance` | `Highmark Stadium` / `Orchard Park` / `69214` |
| `broadcasts` | `["Prime Video"]` |
| `week` / `seasonYear` / `seasonType` | `2` / `2026` / `2` |

With **Include per-period scores**: `homeLinescores` / `awayLinescores` —
`[{"period": 1, "value": 14.0}, …]`, whatever periods the sport has.

With **Include statistical leaders**: `leaders` —
`{"category": "passingYards", "athlete": "Jared Goff", "position": "QB", "jersey": "16", "team": "DET", "display": "26/38, 327 YDS, 4 TD"}`.

In **standings** mode: one row per team with `rank`, `orderInGroup`, `stats`,
`statLabels`, `group` and `note` (the qualification zone — `Champions League`,
`Relegation`, a playoff seed).

### The limit will misrepresent a season if you leave it alone

The single most important thing to know about this source. Same league, same query,
three limits:

| Request | Matches | Dates covered |
|---|---|---|
| `dates=2026` | 100 | 2026-01-03 → **2026-09-20** |
| `dates=2026&limit=300` | 300 | 2026-01-03 → **2026-12-20** |
| `dates=2026&limit=1000` | **320** | 2026-01-03 → 2027-01-01 |

The API's default of 100 does not just drop rows off the end — **it changes where the
season appears to finish**. Ask for 2026, get 100 matches ending 20 September, and the
natural conclusion is that the season ended in September. Nothing in the response
contradicts it: there is no total, no next-page marker, no truncation flag.

So this actor always sends an explicit `limit`, and **warns whenever the number of
matches returned equals the limit you asked for**, naming the last date in the data and
pointing out that it is where the data stops rather than where the season does. Raise
`limit` (up to 1000) or ask for one month at a time.

### Dates

- `20260920` — one day
- `202609` — a whole month (48 NFL matches across 13 dates)
- `2026` — a season, subject to the limit above
- `20260901-20260930` — **rejected before the request is made.** The API answers a dash
  range with HTTP 400, and it is the *same* 400 it returns for a league that does not
  exist, so sending it would produce an unhelpful error. Use the month form.

### Every wrong input gets the same error

A bad sport, a bad league, a dash range and `dates=notadate` all return exactly
`{"code":400,"message":"Failed to get events endpoint."}` — 55 bytes, byte identical.
The API will not tell you which mistake you made, and there is no index endpoint to
check against: `/apis/site/v2/sports` returns 404.

So this actor validates leagues, dates and limits locally first, and when a 400 still
comes back its error names both possibilities rather than guessing one.

### `dates` is a US-local day, not a UTC day

`dates=20260920` returned 13 NFL matches dated 20 September and **one dated the 21st**
at `00:20Z` — an evening US kickoff that crosses UTC midnight. NHL did the same;
Premier League, kicking off in the afternoon UK time, did not.

So the parameter picks ESPN's local match day while `startsAt` stays honest UTC. If you
filter downstream on the UTC date, you will drop those late games.

### Two different fields mean "rank"

Soccer standings carry a `rank` stat. **NFL standings do not** — they carry
`playoffSeed`, labelled "Position". `rank` reads whichever exists, so it is filled for
both. `orderInGroup` is kept separately: it is the position in the order the API
returned, which is table order, and it does not always agree with `playoffSeed` (NFL
returned seeds 1, 2, 3, 5, 4, 6 in that order).

### A note on stat names in standings

A soccer table's stats are named `pointsFor` and `pointsAgainst`, with
`displayName: "Goals For"` and `"Goals Against"`. The machine name is identical in every
sport and means something different in each, so `stats` and `statLabels` are both
returned and the label travels with the number.

# Actor input Schema

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

Leagues to read: nfl, nba, mlb, nhl, wnba, college-football, mens-college-basketball, eng.1, esp.1, ita.1, ger.1, fra.1, usa.1, uefa.champions and more. A league not on that list can be given as an explicit 'sport/league' pair such as 'soccer/bra.1' — there is no index endpoint to enumerate them, so the list is curated from leagues verified to answer.

## `mode` (type: `string`):

'scoreboard' returns matches with scores, status, venue, team records and TV listings. 'standings' returns the league table with each team's stats and its qualification note.

## `dates` (type: `string`):

Scoreboard mode only. A single day as YYYYMMDD, a whole month as YYYYMM, or a season as YYYY. Leave empty for the current window the API picks. A dash range is rejected: the API answers one with the same opaque HTTP 400 it uses for a bad league, so it is refused here with a useful message instead.

## `limit` (type: `integer`):

Read this carefully if you ask for a season. The API's own default is 100, and that cap does not just drop rows — it shortens the date range the results appear to cover. 'dates=2026' returned 100 matches ending 20 September; with limit=1000 the same query returned 320 matches ending 1 January. The run warns whenever the count comes back equal to this limit, because that is the only hint the API gives that more exist.

## `season` (type: `string`):

Standings mode only. A four-digit year for a past season's table. Leave empty for the current one.

## `includeLinescores` (type: `boolean`):

Add each team's score by period — quarters, innings, halves or sets, whatever the sport has.

## `includeLeaders` (type: `boolean`):

Add each match's leading players with their position, shirt number, team and stat line (for example 'Jared Goff, QB #16, DET, 26/38, 327 YDS, 4 TD').

## `proxyConfiguration` (type: `object`):

Optional. The API answered every probe from Apify residential without one, but a proxy spreads requests across IPs if you read many leagues.

## Actor input object example

```json
{
  "leagues": [
    "nfl"
  ],
  "mode": "scoreboard",
  "dates": "20260920",
  "limit": 100,
  "season": "2025",
  "includeLinescores": false,
  "includeLeaders": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Dataset items shown in the 'Matches' view.

## `items` (type: `string`):

Every record this run produced, with all fields, as JSON.

# 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 = {
    "leagues": [
        "nfl"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("xtracto/espn-scoreboard").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 = { "leagues": ["nfl"] }

# Run the Actor and wait for it to finish
run = client.actor("xtracto/espn-scoreboard").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 '{
  "leagues": [
    "nfl"
  ]
}' |
apify call xtracto/espn-scoreboard --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,xtracto/espn-scoreboard"
        }
    }
}
```

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/cHK1vVr4KXtZESUB1/builds/bhlqsquUqVNvFqtyd/openapi.json
