Work

2025 · Personal build

Archived

Athlytics

NBA player analytics — career stats from the NBA's own API, awards history from a targeted headless-browser scrape, both served through a two-tier cache.

Athlytics interface

A basketball research tool built to answer the arguments that come up constantly and get settled badly: who actually had the better peak, how a season stacks up historically, what the award voting really looked like.

Athlytics was engineered to transform raw, unstructured fitness telemetry into sub-second visual performance analytics. Most of what the app needs — game logs, shot charts, advanced stats, bios — comes straight from the NBA's own stats API. Awards and voting history don't: that page is JavaScript-rendered, so a headless Chrome instance loads it and BeautifulSoup parses what comes back. Both paths land in the same two-tier cache — a Flask-Caching layer in front, and a disk-first JSON cache underneath that checks for a saved record before the scraper ever runs again.

Archived at the point where the data layer worked and the interface had not caught up. Left up because the caching approach — and knowing when to scrape versus when to call an API — is the part worth showing.

What it does


  • Game logs, shot charts, and advanced stats pulled from the NBA's own stats API
  • Awards and voting history scraped from Basketball-Reference via headless Chrome, since that page is JS-rendered
  • Two-tier cache: a Flask-Caching layer plus a disk-first JSON cache keyed by player ID
  • A small utility reconstructs Basketball-Reference's own ID format from a player's name, bridging the NBA API's numeric IDs with the one route that needs BR's slug scheme
  • Client-side fuzzy search (Fuse.js) layered over a server-side search endpoint
  • Recharts line charts for career trends, a Chart.js scatter plot for shot location

What it taught me


  • Reach for scraping only where a real API doesn't cover it, not by default
  • Two caching layers earn their keep when the upstream is both slow and inconsistent
  • Knowing when to archive a side project instead of finishing it