unofficial SDK for the NHL API
Project description
NHL Stats SDK
An unofficial Python SDK for the NHL API. Personal side project built for fun — no guarantees on cadence, but actively maintained.
Only possible due to the great work by Zmalski documenting the NHL API. Full Postman collection for manual testing available here.
Requirements
- Python 3.13+
Installation
pip install nhl-stats
Or clone the repo and install in editable mode for local development:
git clone https://github.com/PandaBacon21/nhl-sdk.git
cd nhl-sdk/nhl_stats
pip install -e .
Quick Start
from nhl_stats.client import NhlClient
client = NhlClient()
# --- Players ---
player = client.players.get(8477492) # Nathan MacKinnon — gateway object, player ID baked in
print(player.profile.first_name) # biographical info
print(player.stats.career) # career totals from landing
pp = player.stats.powerplay() # one of 20+ named api_stats reports (season, game_type optional)
log = player.stats.game_log(season=20242025, game_type=2)
print(player.achievements.awards) # awards, badges, HHOF status, top-100
milestones = player.achievements.milestones()
# Collection-level — spotlight, stat leaders, league-wide milestones
spotlight = client.players.spotlight
leaders = client.players.leaders
milestones = client.players.milestones(milestone="Goals", position="s") # skaters only
# --- Teams ---
team = client.teams.get("COL") # Team gateway — abbreviation and team ID baked in
stats = team.stats.get_team_stats()
summary = team.stats.get_summary() # api_stats aggregate (PP%, PK%, goals for/against, etc.)
roster = team.roster.get_team_roster()
schedule = team.schedule.get_schedule()
standings = client.teams.standings.get_standings()
# --- League ---
schedule = client.league.get_schedule(date="2025-01-15")
seasons = client.league.get_seasons()
season_details = client.league.get_season_details()
# --- Games ---
game = client.games.get(2024020001) # Game gateway — game ID baked in
pbp = game.pbp()
landing = game.landing()
shifts = game.shifts()
scores = client.games.scores.get_daily_scores(date="2025-01-15")
scoreboard = client.games.scoreboard.get_scoreboard()
# --- Draft ---
rankings = client.draft.rankings.get_rankings()
picks = client.draft.picks.get_all(year=2024)
tracker = client.draft.tracker.get_tracker_now()
# --- Playoffs ---
carousel = client.playoffs.carousel.get_carousel(season=20242025)
bracket = client.playoffs.bracket.get_bracket(year=2024)
# --- Misc ---
meta = client.misc.meta()
location = client.misc.location()
countries = client.misc.countries
ping = client.misc.ping()
# --- NHL Edge ---
# Player edge — returns SkaterEdge or GoalieEdge based on position
edge = player.stats.edge()
speed = edge.skating_speed()
# Team edge — per-team detail
distance = team.stats.edge.skating_distance.get_skating_distance()
# Team edge — league-wide leaderboards
dist_top = client.teams.edge.skating_distance_top_10.get_top_10()
What's Included
| Namespace | What it covers |
|---|---|
client.players |
Player gateway (profile, stats, achievements), stat leaders, spotlight, league-wide milestones, player list query |
client.teams |
Team gateway (stats, roster, schedule), standings, all-teams reference list |
client.league |
League schedule, schedule calendar, season list, season details, component season |
client.games |
Game gateway (pbp, landing, boxscore, story, shifts), daily scores, scoreboard, TV schedule, odds, streams |
client.draft |
Prospect rankings, live draft tracker, picks, all-picks, draft query |
client.playoffs |
Series carousel, per-series schedule, full bracket |
client.misc |
Location, postal lookup, meta, game rail, replays, WSC play-by-play, reference data (countries, franchises, glossary, config) |
Player stats — Player.stats exposes career totals, season splits, and game logs from the landing endpoint, plus 20 named per-player reports sourced from the NHL Stats API (summary, bio, faceoff, penalties, TOI, power play, penalty kill, realtime, and more). NHL Edge per-player data is available via Player.stats.edge().
Team stats — TeamStats covers per-player skater/goalie stats, aggregate team summaries (PP%, PK%, goals for/against), and team reference data. NHL Edge per-team detail is via TeamEdge and league-wide leaderboards via TeamsEdge.
Configuration
NhlClient accepts optional keyword arguments. All fields have defaults and can be overridden individually or via a BaseConfig object.
from nhl_stats.client import NhlClient
client = NhlClient(
log_name="my_app", # logger name (default: "nhl_sdk")
log_level="INFO", # DEBUG|INFO|WARNING|ERROR (default: "WARNING")
log_file="/tmp/nhl.log", # log file path; None = stdout only (default: None)
lang="en", # response language (default: "en")
cache=my_cache, # custom BaseCache impl (default: MemCache)
)
By default, logs are written to stdout only (log_file=None). Pass any file path string to write to a file instead.
Custom Config Object
from nhl_stats.core.config import DefaultConfig
from nhl_stats.client import NhlClient
config = DefaultConfig(log_level="WARNING", log_file=None)
client = NhlClient(config_from_object=config)
Custom Cache
Implement BaseCache to plug in any backend (Redis, file-based, etc.):
from nhl_stats.core.cache.base_cache import BaseCache
class MyCache(BaseCache):
def get(self, key): ...
def set(self, key, data, ttl): ...
def delete(self, key): ...
def clear(self): ...
API Reference
Full method and property documentation is in docs/api-reference.md.
Error Handling
The NHL API is public and requires no authentication. As this is an unofficial SDK against an undocumented API, there is no guarantee that endpoints or response structures won't change, and unexpected errors outside those listed below may occur.
On HTTP 429, the SDK automatically retries up to 3 times with exponential backoff. The Retry-After response header is respected when present, capped at 60s with a minimum of 1s per retry. RateLimitError is raised only after all retries are exhausted. In practice, the NHL API returns Retry-After: 60 on rate limit and counts it down across successive 429 responses in the same window.
from nhl_stats.core.errors import NotFoundError, RateLimitError, NhlApiError
try:
player = client.players.get(9999999)
_ = player.profile
except NotFoundError as e:
print(f"Player not found: {e} (status {e.status_code})")
except RateLimitError:
print("Rate limited — retries exhausted")
except NhlApiError as e:
print(f"API error: {e}")
| Exception | HTTP Status |
|---|---|
NotFoundError |
404 |
RateLimitError |
429 |
ServerError |
5xx |
NhlApiError |
Base class / other |
License
MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nhl_sdk-0.1.0.tar.gz.
File metadata
- Download URL: nhl_sdk-0.1.0.tar.gz
- Upload date:
- Size: 110.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6dcf07e4092f0aee353c514566a1979c6e3fb7dace3dbf9ccd79d15879321762
|
|
| MD5 |
e920dd396f1a6141c42a8e6a5eacf1fd
|
|
| BLAKE2b-256 |
479f0010181b922a05bb76c3c6c3b63d99616d2cb6938f05935cf86b6dae7911
|
File details
Details for the file nhl_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nhl_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 234.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8925b5af7410d078047bc383c61cc0041b1e11381444dbf33895d047a5b8d81e
|
|
| MD5 |
661db0b78b553ad6960d4a8a9a56b8a1
|
|
| BLAKE2b-256 |
555b1d9081d6c87df5e842dae28a15ee9a7b10adb109229c61bcabc2e2ca9922
|