# Changelog of ESPN Sports Data Scraper — Scores, Standings, Rosters, News (`teodor_banea/espn-sports-data-scraper`) Actor

- **URL**: https://apify.com/teodor_banea/espn-sports-data-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/teodor_banea/espn-sports-data-scraper.md

## Changelog

### 0.1.2 (2026-10-08)

- A dataset write that fails releases the claims of its rows so the retried handler can
  claim and write them again instead of ending the run short.
- Platform re-verification of 0.1.1 (14 hard aborts, 0 duplicate or missing rows): a run
  with `includeGameDetails` now costs $0.014 per 1,000 rows (build 0.1.2: $0.140).

### 0.1.1 (2026-10-08)

- Platform fix: ESPN serves the team list as `application/ld+json` for some leagues (NFL,
  NBA, MLB, EPL, college football), which the crawler rejected — `teams` mode and the
  league-wide fan-out of `rosters`/`schedule` without `teamIds` returned nothing for them.
- HTTP 403 is retried: ESPN's CDN answers a transient 403 now and then (1 in 671 summary
  requests on the platform); it used to be terminal and the game lost its details.
- Dataset rows are written in batches (25 rows or 1.5 s) with one STATE write per batch
  instead of two per row — key-value-store writes were 80% of the cost of a run with
  `includeGameDetails`. A batch is recorded before its write and reconciled against the
  dataset on restart; keys of written rows are persisted so a request re-run after an
  interruption never writes (and bills) a row twice.
- Game details and team details are fetched inside the scoreboard / team-list handler
  (in parallel, with their own retries) instead of as one request-queue entry per row:
  queue writes were 58% of a details run's cost ($0.14 per 1,000 rows on build 0.1.2).
- Restart reconcile decides from the dataset item listing at the saved offset instead of
  the dataset's `itemCount`, which lags real writes by several seconds on the platform
  (0 reported with 40 rows listed 1 s after a hard abort) and could have re-written a batch
  that was already there.
- A league-wide fan-out stops fetching once the target's cap is reached.
- Postponed and canceled games carry `null` scores instead of ESPN's 0-0.
- Standings rows without a link of their own (F1 drivers) point at the league's standings page.
- The failure message for an unknown league names the slug; the Actor title fits the
  platform's 63-character limit; the User-Agent no longer contains "scraper" (Akamai 403).
- Measured on the platform: $0.01 per 1,000 rows for scores, standings, rosters, stats and
  news; with game details $0.178 (build 0.1.1) → $0.140 (0.1.2, batched writes) → $0.014
  (0.1.3, in-handler details) per 1,000 rows.

### 0.1.0 (2026-10-08)

- Initial release.
- Seven modes over ESPN's public JSON API, no login and no proxy: scores and results by
  date, team schedules, standings, teams, rosters, athlete season stats and news for 42
  registered leagues plus any custom `sport/league` slug.
- Flat typed rows with a constant key set per record type; game rows aligned with our
  Sofascore actor (`statusType` vocabulary, `startTime`, `homeScore`/`awayScore`, decimal
  `homeOdds`/`drawOdds`/`awayOdds`); pre-game odds from the scoreboard and closing lines
  from the game summary when `includeGameDetails` is on.
- Verified API quirks recorded in `constants.ts`: scoreboard date ranges answer 400 (one
  request per day, rows de-duplicated across the US/Eastern day boundary), college
  scoreboards need `groups=50`/`80`, news is capped at 50 articles, team schedules carry
  object scores and soccer needs `fixture=true` for upcoming games, rosters are grouped by
  position for NFL/NHL/MLB, athlete stats exist for nba/wnba/nfl/nhl/mlb only (soccer uses
  the overview endpoint, unknown ids answer 500).
- Run-wide cap split evenly across leagues/teams/athletes and reserved synchronously;
  honest per-target shortfalls in the status message; failures under the `ERRORS` key.
