# Changelog of NBA Stats Scraper for espn.com (`blackfalcondata/espn-nba-scraper`) Actor

- **URL**: https://apify.com/blackfalcondata/espn-nba-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/blackfalcondata/espn-nba-scraper.md

## Changelog

### 0.1.0 — 2026-09-03

First release.

- NBA box scores from espn.com: one row per player per game, carrying the
  player's full statline **and** that team's totals. The two closest
  competitors sell those as two separate actors.
- 93 columns. Minutes, points, field goals / three pointers / free throws as
  made, attempted and percentage, offensive and defensive rebounds, assists,
  turnovers, steals, blocks, personal fouls, plus/minus. Team totals add
  largest lead, technical and flagrant fouls, team turnovers and the
  assist-to-turnover ratio. Every row also names the opponent, the venue, the
  score, the margin and the result.
- `query` takes a season (`season:2025`), a date (`2025-03-15`), a range
  (`2025-03-14..2025-03-16`) or one game (`game:401705534`). Empty means the
  current season.
- Incremental mode delivers and charges only for rows that are new or whose
  content moved. The change signature covers the whole delivered row, so a
  statline ESPN corrects after the final whistle is caught.
- Notifications: Telegram, Slack, Discord, WhatsApp Cloud API, generic webhook.
- Transport: one request per game returns both rosters and both teams' totals.
  No proxy, no browser, no custom headers. Measured 2026-09-03 from a bare
  datacenter IP: 4 requests, 82 rows, 2.0 s.
- Retries a throttled response. Measured 2026-09-03: a burst at 50 concurrent
  requests leaves ESPN returning a **flapping 403** — the same URL alternating
  403 / 200 / 403 for minutes. Unretried that killed the run, so 403 is treated
  as a rate limit and retried with backoff, while a 404 is not. Concurrency is
  set from the measured ceiling (20 held at 100%, 50 collapsed to 40%).

### 0.1.4 — 2026-09-03

Three additions, all measured against what rivals with real traction actually
ship (audit of 11 competitor input schemas and READMEs).

- **`teams` filter.** Only games involving the teams you name — abbreviation or
  name both work (`BOS`, `Celtics`, `Boston Celtics`). Applied when the calendar
  is listed, **before any game is fetched**, so you are not charged for the
  other 29 teams. The three rivals with the most users between them make a team
  selector their primary input; we had no way to say "just the Lakers" without
  pulling a whole season.
- **Quarter-by-quarter score**, both sides: `teamQ1Points`..`teamQ4Points`,
  `teamOvertimePoints` and the matching `opponent*` columns. It rides along in
  the payload we already fetch, so it costs nothing extra. Overtime is summed,
  so a double-OT game keeps both periods.
- **`teamHomeAway` and `teamIsHome`.** Which side of the court the row's team
  was on. An earlier pass left this out on the reasoning that team-versus-
  opponent already said it — it does not, that pairing is symmetric, and
  home/away splits are one of the first cuts anyone makes on a box score.
- **`teamVenueCity` and `teamVenueState`** alongside the arena name.

Also: unplayed games are now dropped when the calendar is read. A scheduled
game's box score is empty (measured on 401909834, 2026-10-21), so a query over
a future window used to pay one request per game and deliver nothing.

Considered and NOT added: broadcast networks. The source returned an empty list
on every game we measured, and a column that is null on every historical row is
worse than no column at all.
