# MLB Scraper (`mlg14/mlb-scraper`) Actor

Collect public baseball teams, rosters, scores, standings, player statistics, game totals, and leaders as flat records.

- **URL**: https://apify.com/mlg14/mlb-scraper.md
- **Developed by:** [MLG Data](https://apify.com/mlg14) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.20 / 1,000 results

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?

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

## MLB Scraper

Scrape MLB teams, rosters, schedules, scores, standings, statistics, game totals, and leaders from public data. Export MLB data as flat JSON, CSV, or spreadsheet rows for research, reporting, and applications that need an MLB data API alternative without maintaining seven separate collectors.

### What data can you extract from MLB?

| Mode | One row represents | Useful fields |
| --- | --- | --- |
| `teams` | One club in one season | Team ID, name, abbreviation, league, division, venue, first year of play |
| `players` | One player on a club roster | Player ID, jersey, position, roster status, birth details, height, weight, batting and throwing side, debut date |
| `schedule` | One game | Start time, official date, status, clubs, scores, winner, venue, series and doubleheader details |
| `standings` | One club's season record | Wins, losses, winning percentage, ranks, games back, runs scored and allowed, streak, clinch details |
| `playerStats` | One player season statistic split | Player and team IDs, season, group, games played, hitting, pitching, or fielding measures |
| `gameDetails` | One club in one game | Batting totals, pitching totals, fielding totals, opponent and game identifiers |
| `leaders` | One ranked player in one category | Statistic category, rank, value, player, club, league |

#### Output field reference

The table covers every field that may be emitted. Fields appear only in relevant modes. Season stat columns are taken from the selected group, so a hitting row and a pitching row have different measures. A missing field means that the source did not provide that measure for the row; a `null` value means the field belongs to the row but is unavailable at that point, such as a score before first pitch.

| Field | Description | Example |
| --- | --- | --- |
| `abbreviation` | Abbreviation | — |
| `active` | Active | — |
| `age` | Age | — |
| `airOuts` | Air outs | — |
| `assists` | Assists | — |
| `atBats` | At bats | — |
| `atBatsPerHomeRun` | At bats per home run | — |
| `avg` | Avg | — |
| `awayLosses` | Away losses | — |
| `awayScore` | Away score | 4 |
| `awayTeam` | Away team | Chicago Cubs |
| `awayTeamId` | Away team id | — |
| `awayWins` | Away wins | — |
| `babip` | Babip | — |
| `balks` | Balks | — |
| `baseOnBalls` | Base on balls | — |
| `bats` | Batting side code | — |
| `battersFaced` | Batters faced | — |
| `birthCity` | Birth city | — |
| `birthCountry` | Birth country | — |
| `birthDate` | Birth date | — |
| `birthStateProvince` | Birth state province | — |
| `blownSaves` | Blown saves | — |
| `catcherERA` | Earned run average while catching | — |
| `catchersInterference` | Catchers interference | — |
| `category` | Leaderboard statistic category | homeRuns |
| `caughtStealing` | Caught stealing | — |
| `caughtStealingPercentage` | Caught stealing percentage | — |
| `chances` | Chances | — |
| `clinched` | Clinched | — |
| `completeGames` | Complete games | — |
| `dayNight` | Day night | — |
| `division` | Division | — |
| `divisionId` | Division id | — |
| `divisionRank` | Division rank | — |
| `doubleHeader` | Doubleheader code | — |
| `doublePlays` | Double plays | — |
| `doubles` | Doubles | — |
| `earnedRuns` | Earned runs | — |
| `eliminationNumber` | Elimination number as displayed | — |
| `era` | Era | — |
| `errors` | Errors | — |
| `fielding` | Fielding | — |
| `firstYearOfPlay` | First year of play | — |
| `gameDate` | Scheduled game start in UTC | — |
| `gameNumber` | Game number | — |
| `gamePk` | Official game identifier | 776318 |
| `gameType` | Game type | — |
| `games` | Games | — |
| `gamesBack` | Games behind leader as displayed | — |
| `gamesFinished` | Games finished | — |
| `gamesPitched` | Games pitched | — |
| `gamesPlayed` | Games played | — |
| `gamesStarted` | Games started | — |
| `groundIntoDoublePlay` | Ground into double play | — |
| `groundOuts` | Ground outs | — |
| `groundOutsToAirouts` | Ground outs to airouts | — |
| `height` | Height | — |
| `hitBatsmen` | Hit batsmen | — |
| `hitByPitch` | Hit by pitch | — |
| `hits` | Hits | — |
| `hitsPer9Inn` | Hits per9inn | — |
| `holds` | Holds | — |
| `homeLosses` | Home losses | — |
| `homeRuns` | Home runs | 55 |
| `homeRunsPer9` | Home runs per9 | — |
| `homeScore` | Home score | 0 |
| `homeTeam` | Home team | Pittsburgh Pirates |
| `homeTeamId` | Home team id | — |
| `homeWins` | Home wins | — |
| `inheritedRunners` | Inherited runners | — |
| `inheritedRunnersScored` | Inherited runners scored | — |
| `innings` | Innings | — |
| `inningsPitched` | Innings pitched | — |
| `intentionalWalks` | Intentional walks | — |
| `jerseyNumber` | Jersey number | — |
| `league` | League | — |
| `leagueId` | League id | — |
| `leagueRank` | League rank | — |
| `leftOnBase` | Left on base | — |
| `locationName` | Location name | — |
| `losses` | Losses | 68 |
| `magicNumber` | Division clinch magic number as displayed | — |
| `mlbDebutDate` | First major league game date | — |
| `numberOfPitches` | Number of pitches | — |
| `obp` | Obp | — |
| `officialDate` | Local official game date | 2025-09-15 |
| `opponent` | Opponent | — |
| `opponentId` | Opponent id | — |
| `ops` | Ops | — |
| `outs` | Outs | — |
| `passedBall` | Passed balls | — |
| `pickoffs` | Pickoffs | — |
| `pitchesPerInning` | Pitches per inning | — |
| `pitchingBaseOnBalls` | Pitching base on balls | — |
| `pitchingHits` | Pitching hits | — |
| `pitchingInnings` | Innings pitched by the club in this game | — |
| `pitchingRuns` | Pitching runs | — |
| `pitchingStrikeOuts` | Pitching strike outs | — |
| `plateAppearances` | Plate appearances | — |
| `player` | Player full name | — |
| `playerId` | Player id | 660271 |
| `position` | Position | — |
| `positionAbbreviation` | Position abbreviation | — |
| `putOuts` | Put outs | — |
| `rangeFactorPer9Inn` | Range factor per9inn | — |
| `rangeFactorPerGame` | Range factor per game | — |
| `rank` | Rank including ties | 1 |
| `rbi` | Rbi | — |
| `recordType` | Type of output record | game |
| `rosterStatus` | Roster status | — |
| `runDifferential` | Run differential | — |
| `runs` | Runs | — |
| `runsAllowed` | Runs allowed | — |
| `runsScored` | Runs scored | — |
| `runsScoredPer9` | Runs scored per9 | — |
| `sacBunts` | Sac bunts | — |
| `sacFlies` | Sac flies | — |
| `saveOpportunities` | Save opportunities | — |
| `saves` | Saves | — |
| `season` | Season year | 2025 |
| `seriesDescription` | Series description | — |
| `seriesGameNumber` | Series game number | — |
| `shutouts` | Shutouts | — |
| `slg` | Slg | — |
| `statGroup` | Hitting, pitching, or fielding group | hitting |
| `status` | Status | Final |
| `stolenBasePercentage` | Stolen base percentage | — |
| `stolenBases` | Stolen bases | — |
| `streak` | Streak | — |
| `strikeOuts` | Strike outs | — |
| `strikePercentage` | Strike percentage | — |
| `strikeoutWalkRatio` | Strikeout walk ratio | — |
| `strikeoutsPer9Inn` | Strikeouts per9inn | — |
| `strikes` | Strikes | — |
| `team` | Club name | — |
| `teamId` | Team id | 112 |
| `teamName` | Team name | — |
| `teamSide` | Home or away side | — |
| `throwingErrors` | Throwing errors | — |
| `throws` | Throwing hand code | — |
| `totalBases` | Total bases | — |
| `triplePlays` | Triple plays | — |
| `triples` | Triples | — |
| `url` | Public site page for this record | — |
| `value` | Leaderboard value as displayed by the source | 60 |
| `venueId` | Venue id | — |
| `venueName` | Venue name | — |
| `walksPer9Inn` | Walks per9inn | — |
| `weight` | Weight | — |
| `whip` | Whip | — |
| `wildCardGamesBack` | Wild card games back | — |
| `wildPitches` | Wild pitches | — |
| `winPercentage` | Win percentage | — |
| `winningPercentage` | Season win percentage as displayed | — |
| `winningTeam` | Winner once final | — |
| `wins` | Wins | 94 |

### How to scrape MLB

1. Choose a dataset with `mode`. Start with `teams` if you need club IDs, `players` if you need player IDs, or `schedule` if you need game IDs.
2. Select one or more seasons. For schedules and game details, optionally add a date, start date, end date, game type, or selected game IDs. A date range is the clearest way to keep a large schedule run focused.
3. Add filters only when needed. Club IDs narrow clubs, rosters, games, standings, and leaders. Player IDs restrict player stats. A leaderboard category names the statistic to rank.
4. Set `maxItems` to the largest number of rows you want returned. Run the scraper and export the dataset as JSON, CSV, or a spreadsheet file.

### Input

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `teams` | Selects one of the seven datasets. |
| `seasons` | string array | current year | One or more season years; rows keep their season label. |
| `season` | integer | unset | Single season shortcut, merged with `seasons`. |
| `teamIds` | string array | all clubs | Restricts clubs or matching games to these official IDs. |
| `teamId` | integer | unset | Single club ID shortcut, merged with `teamIds`. |
| `playerIds` | string array | roster players | In player stats mode, fetches these people directly. |
| `playerId` | integer | unset | Single player ID shortcut, merged with `playerIds`. |
| `gamePks` | string array | games from schedule | In game details mode, fetches these games directly. |
| `gamePk` | integer | unset | Single game ID shortcut, merged with `gamePks`. |
| `date` | string | unset | One local official date for schedule or game details. |
| `fromDate` | string | unset | Beginning of a schedule or game-details date range. |
| `toDate` | string | unset | End of a schedule or game-details date range. |
| `leagueId` | string | `both` | Standings for both leagues, AL, or NL. |
| `statGroup` | string | `hitting` | Hitting, pitching, or fielding in player stats and leaders. |
| `gameType` | string | `R` | Regular season or another supported game classification. |
| `leaderCategories` | string array | `homeRuns` | Categories to rank in leaders mode. |
| `maxItems` | integer | `1000` | Hard cap on emitted dataset rows. |

A date overrides a date range. When a date, date range, or explicit game ID is supplied in a game mode, the request is evaluated once rather than repeated for every season in `seasons`. All dates use `YYYY-MM-DD`. The `gameDate` value is an ISO timestamp in UTC, while `officialDate` is the date assigned to the game by the league; those can differ across time zones.

This example collects final scores and game details for a small, reproducible window:

```json
{
  "mode": "schedule",
  "seasons": ["2025"],
  "fromDate": "2025-09-15",
  "toDate": "2025-09-17",
  "gameType": "R",
  "maxItems": 50
}
```

### Output example

This is a real game row from the 2025-09-15 to 2025-09-17 validation run, which returned 40 rows:

```json
{
  "recordType": "game",
  "season": 2025,
  "gamePk": 776318,
  "gameDate": "2025-09-15T22:40:00Z",
  "officialDate": "2025-09-15",
  "gameType": "R",
  "status": "Final",
  "awayTeamId": 112,
  "awayTeam": "Chicago Cubs",
  "awayScore": 4,
  "awayWins": 86,
  "awayLosses": 64,
  "homeTeamId": 134,
  "homeTeam": "Pittsburgh Pirates",
  "homeScore": 0,
  "homeWins": 65,
  "homeLosses": 86,
  "winningTeam": "Chicago Cubs",
  "venueId": 31,
  "venueName": "PNC Park",
  "dayNight": "night",
  "doubleHeader": "N",
  "gameNumber": 1,
  "seriesGameNumber": 1,
  "seriesDescription": "Regular Season",
  "url": "https://www.mlb.com/gameday/776318"
}
```

### Use cases

- **Sports reporting:** Refresh yesterday's scores, build a game recap queue, or compare division races without manually transcribing tables.
- **Fantasy baseball analysis:** Join player season lines to roster records and leader categories. Limit by club or specific player IDs when monitoring a shortlist.
- **Historical research:** Collect the same statistic across several seasons, then compare seasons using the explicit `season` column rather than inferring a year from file names.
- **Schedule applications:** Populate game lists with UTC start times and official dates, then update scores and statuses during a season.

### How much does it cost to scrape MLB?

Price: **$3.20 per 1,000 returned rows** ($0.0032 each). A 30-club `teams` run is about $0.096. A 1,000-row roster or schedule export is $3.20. A 2,430-game regular-season schedule would be about $7.78 if all rows are returned. These examples count emitted records, not source requests; a two-row game-details result costs two result events. Your `maxItems` setting prevents a larger dataset than intended.

### Tips for best results

Choose the smallest useful scope first. A three-day schedule window is easy to inspect, while a full season can include thousands of games. For daily score refreshes, pass a single `date`; for backfills, pass `fromDate` and `toDate`. The scraper splits ranges into calendar-month requests, which keeps source responses manageable. It stops once `maxItems` or the run's result budget is reached.

For leaderboards, choose a category appropriate to the selected `statGroup`. A hitting category such as `homeRuns` belongs with `hitting`; a pitching category such as `saves` belongs with `pitching`. A request for a category the source does not return may yield zero rows. If you need more than the first page, raise `maxItems`; the scraper uses offsets and removes overlaps caused by tied ranks.

### Limits

The scraper reads public data. It cannot fill facts that have not been published: scores before or during a game, missing historical splits, unavailable roster biographies, or empty stat categories. Season coverage varies by mode and statistic. Very early seasons may have fewer fields than recent ones. Current season data can change as games progress and corrections are made.

Game details fetch a box score per game and run slower than schedules. The default 1,000-row cap can truncate league-wide rosters or season schedules.

### Use with automated workflows

Example instruction: “Collect the 2025 regular-season schedule for September 15 through 17, return game IDs, official dates, clubs, final scores, and winners, then sort by official date.”

Example instruction: “Collect 2025 hitting season lines for one selected club, keep player ID, player name, games played, hits, home runs, and on-base percentage, and flag rows where a measure is missing.”

### FAQ

**Is the data public?** The scraper uses public endpoints and does not require an account. Follow the site's terms and applicable law when storing or redistributing data. Avoid using player biographical details for unrelated personal profiling.

**Do I need to supply a proxy or credentials?** No input credential is needed. The scraper uses its standard network path and does not require a user-provided proxy setting.

**How fast is a run?** Teams and standings need few source requests. Rosters and player stats require club requests; game details require one box-score request per game. Run time also depends on the row count and source responsiveness.

**Can I schedule recurring collections?** Yes. Reuse a saved input with a changing `date` or season, and monitor the resulting dataset and run status. Stable IDs make it possible to update earlier records in your own store.

**Can I export to a spreadsheet?** Yes. The rows are flat and can be downloaded as CSV or a spreadsheet-compatible file. A separate export per mode is easiest to analyze because each mode has different columns.

**Why is a score or statistic empty?** A scheduled game has no final score. Some statistics do not apply to every player or season. Check the row's `status`, `statGroup`, `position`, and `season` before interpreting an empty value.

**What happens with tied leaderboard ranks?** The source can return more rows than a requested page size when several players share a rank. The scraper deduplicates by player within a category while continuing through offsets until the result cap is met.

### Integrations

The run input and dataset can be accessed programmatically, sent to a webhook after completion, used in scheduled jobs, or exported as CSV for spreadsheet analysis. For ongoing pipelines, store `gamePk`, `playerId`, or `teamId` with `season` so the next run can update matching records instead of relying on team or player names.

### Support

Open an issue on the Issues tab; we reply within 24 hours and add fields on request. Include the mode, input, season, and a sample identifier so a missing value can be checked against the public source.

# Actor input Schema

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

Choose teams, roster players, games, standings, player season statistics, team game totals, or ranked leaders.

## `seasons` (type: `array`):

Season years to collect. Leave empty for the current year.

## `season` (type: `integer`):

Optional single season year; merged with Seasons when both are set.

## `teamIds` (type: `array`):

Optional club IDs to filter teams, rosters, games, standings, stats, or leaders.

## `teamId` (type: `integer`):

One club ID, merged with Team IDs when both are set.

## `playerIds` (type: `array`):

Player statistics for these player IDs; leave empty to use selected club rosters.

## `playerId` (type: `integer`):

One player ID for player statistics, merged with Player IDs.

## `gamePks` (type: `array`):

Game details for these game IDs; leave empty to discover games from dates or seasons.

## `gamePk` (type: `integer`):

One game ID for game details, merged with Game IDs.

## `date` (type: `string`):

One schedule or game-details date in YYYY-MM-DD format.

## `fromDate` (type: `string`):

First schedule or game-details date in YYYY-MM-DD format.

## `toDate` (type: `string`):

Last schedule or game-details date in YYYY-MM-DD format.

## `leagueId` (type: `string`):

League filter for standings.

## `statGroup` (type: `string`):

Player stats or leaders for hitting, pitching, or fielding.

## `gameType` (type: `string`):

Game classification for schedule, game details, and leaderboards.

## `leaderCategories` (type: `array`):

Statistic categories for ranked leaders, such as homeRuns, battingAverage, strikeouts, or saves.

## `maxItems` (type: `integer`):

Maximum dataset rows to return across all seasons and categories.

## Actor input object example

```json
{
  "mode": "teams",
  "seasons": [
    "2025"
  ],
  "leagueId": "both",
  "statGroup": "hitting",
  "gameType": "R",
  "leaderCategories": [
    "homeRuns"
  ],
  "maxItems": 1000
}
```

# Actor output Schema

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

All scraped items in the default dataset.

# 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 = {
    "seasons": [
        "2025"
    ],
    "leaderCategories": [
        "homeRuns"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mlg14/mlb-scraper").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 = {
    "seasons": ["2025"],
    "leaderCategories": ["homeRuns"],
}

# Run the Actor and wait for it to finish
run = client.actor("mlg14/mlb-scraper").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 '{
  "seasons": [
    "2025"
  ],
  "leaderCategories": [
    "homeRuns"
  ]
}' |
apify call mlg14/mlb-scraper --silent --output-dataset

```

## MCP server setup

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

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/WogSH3t2ZUl736FEG/builds/jbb6a4fOXEpJoJwkP/openapi.json
