Where the data comes from
Everything comes from the NHL's public APIs. Most of it is keyed on NHL player and team ids:
- Shift charts: when every player stepped on and off the ice.
- Box scores: score, goals, assists, shots, hits, blocks, saves and decisions.
- Play-by-play: every shot attempt with its location and type, every penalty, and the on-ice situation (5v5, power play and so on) at each event.
- Schedule and current rosters.
A job runs every hour. It collects each game once it's official (the NHL marks it "OFF"), rebuilds lines and projections, and refreshes the next two weeks of schedule. The rest of the season's schedule is refreshed once a day.
A few games never get a shift chart in the API. For those, shifts are read from the NHL's official HTML time-on-ice reports. On a game that has both, the two sources matched shift for shift.
Fantasy stats and projections use regular-season games only. 2025-26 is loaded too, as the "last season" in projections.
Lines, pairs and goalies
Who plays with whom comes from 5v5 time only, so power-play and penalty-kill deployment doesn't blur even-strength lines. For each team's latest game:
- Players are ordered by their 5v5 ice time in that game.
- Going down that list, each forward is grouped with the two forwards he spent the most 5v5 time with, out of those not already placed. If only one is left, that makes a 2-man line, as in an 11 forward / 7 defense game.
- Each defenseman is paired with the defenseman he played most with.
- Each goalie is listed alone.
Line numbers (line 1, pair 1, …) rank those groups by their players' average total ice time per game over the last 5 games, in all situations. That's the usual sense of "top line". So a pair that played a lot of 5v5 one night, while the real top pair was on the power play, doesn't jump to pair 1. Groups of one always come last.
- Match (e.g. 3/5): how many of the team's last 5 games had this exact group together.
- Avg TOI: average 5v5 time together in the games the group was together. For a 3-man line that's the weakest of its pairs.
- Not in lineup last game: a skater on the current roster who didn't play the latest game (scratched, injured or just called up), with how many of the last 5 he did play.
- "7th D" / "11F / 7D game" badges: the team dressed an unusual lineup, so a pair or line is short.
Power-play and penalty-kill units
Strength comes from the play-by-play's on-ice situation at every event:
- 5v5: five skaters a side. A pulled goalie's extra attacker isn't counted, so 6-on-5 still counts as 5v5.
- PP / PK: one side has more skaters.
- Other: 4-on-4, 3-on-3 and similar.
When a penalty ends during play, the change is moved back to the penalty's expiry time. Otherwise it would only show at the next whistle. Checked against the NHL's own PP and PK ice time on 10 games, the totals were within 0.9%.
- PP units: the two most-used groups of 5 skaters on the power play. The second may share one player with the first.
- PK forwards / PK defense: up to three most-used forward pairs and defense pairs on the penalty kill. They're listed separately because they rotate independently.
- Units come from the most recent game where the team had that situation. Their match count is out of the games that had it.
On-ice stats: GF, GA, CF, CA, CF%
A player is "on the ice" for an event at second t if one of his shifts started before t and ended at or after it. So a player whose shift ends at the goal was on for it, and players coming on for the next faceoff weren't.
- GF–GA (goals for – goals against): goals by his team, then goals by the opponent, while he (or the whole group) was on the ice.
- CF–CA (Corsi for – against): every shot attempt (goals, shots on goal, missed and blocked shots) for, then against. There are about ten times more attempts than goals, so it shows who tilts the ice well before goals catch up.
- CF% = CF ÷ (CF + CA). 50% is even. PK units sit well below 50% because they're shorthanded.
For a line or pair, only events with every member on the ice together count, at the group's own strength: 5v5 for lines and pairs, the power play for PP units, the penalty kill for PK units. Empty-net events are always left out. A player's "5v5" numbers are his own on-ice totals at 5v5.
Line history
Each game's own lines are saved when the game is collected, using the same grouping run on that game alone with the players who dressed. The history page then shows:
- Most-used groups over the last 5, 10 or 20 games or the season.
- Games: how often the group was together.
- Slot: its usual line number.
- TOI: total time together.
- On-ice results: over those same games.
- Game by game: each game's lines.
Fantasy scoring
Points use your league's settings:
| Skaters | Pts | Goalies | Pts |
|---|---|---|---|
| Goal | 4 | Win | 2 |
| Assist | 2.3 | Goal against | -1 |
| Power-play point | 0.5 | Save | 0.3 |
| Shorthanded point | 1.5 | Shutout | 2 |
| Shot on goal | 0.5 | ||
| Faceoff won / lost | 0.2 / -0.2 | ||
| Hit | 0.5 | ||
| Blocked shot | 0.8 |
- PPP and SHP: a goal or assist scored while his team was on the power play or shorthanded. They add to the goal and assist points.
- Faceoffs: counted from the play-by-play.
- Shutout: no goals against by the team's only goalie that game. As the NHL counts it, a 0–0 game lost in a shootout is still a shutout, because shootout goals don't count.
Checked against the NHL's own stats, every one of these matched exactly for all skaters and goalies through Oct 10.
Fantasy page columns
- GP, FP/GP and the stat columns cover the recent window you pick (last 7, 14 or 30 days), counted back from the latest game with data.
- Trend = recent FP/GP − season FP/GP. Early in the season the window covers every game, so it reads 0.
- Last 5: fantasy points in each of the last 5 games, newest first.
- Proj/G: see Projections.
- G−xG: season goals minus expected goals. Green (−1.5 or lower) means due to score more; red (+1.5 or higher) means running hot.
- TOI: average ice time over the last 3 games. ▲/▼ when it's a minute or more above/below his season average.
- PP: his current power-play unit and his share of the team's power-play time over the last 5 games.
- Games, Sched, Proj: see Schedule score and Proj.
- Players filter: "Available in my league" uses the Yahoo snapshot.
Expected goals (xG)
Every unblocked shot attempt (goals, shots on goal, missed shots) gets a probability of being a goal. The model is fitted on every shot stored, this season and last, around 126,000 shots. It uses:
- Distance and angle from the net being attacked.
- Shot type: wrist, snap, slap, backhand, tip or deflection, wraparound.
- Rebound: the same team had an attempt in the previous 3 seconds.
- Rush: the previous event, within 4 seconds, was outside the attacking zone, and this shot came from inside it.
- Strength: 5v5, power play, shorthanded, other.
How it's fitted: a shot's probability is a base rate multiplied by one factor per feature. The factors are adjusted in turn until, for every level of every feature, expected goals add up to actual goals (iterative proportional fitting). Each factor is pulled toward "no effect" by smoothing, so rare combinations can't swing wildly, and no single shot is rated above 45%.
Empty-net shots get their own rate by distance. Blocked shots aren't rated, since their recorded location is where they were blocked.
Across all shots, expected goals add up to actual goals. Grouped by predicted chance it's well calibrated: shots rated under 2% go in about 1.0% of the time, and shots rated 10–20% about 14%. It's refitted daily.
Individual xG (ixG) is the sum of a player's own shots' xG. On-ice xG is the sum of his team's shots' xG while he was on the ice.
Shot map (player pages): every unblocked attempt over the last 10 games, this season or last season, drawn attacking the right-hand net. The dot size grows with xG. Which net was attacked isn't stored, so it's worked out from the shot's recorded distance. Show blocked adds the player's blocked attempts as ✕ marks, at the spot where they were blocked (that's all the NHL records); they aren't in xG or the distance table. Goalies get a shots-faced map (empty-net shots excluded), and GSAx there is xG against minus goals against.
Luck-adjusted points
Actual fantasy points with the two parts luck swings most, goals and assists, replaced by what the chances say. Shots, hits, blocks, faceoffs and PPP/SHP stay exactly as they happened.
luck-adjusted = actual − 4 × (goals − expected goals) − 2.3 × (assists − expected assists)
- Expected goals = ixG × finishing rate.
- Finishing rate = (last season's goals + 10) ÷ (last season's xG + 10), kept between 0.7 and 1.4.
- So a proven finisher keeps some credit, but a few lucky goals don't count as skill.
- Expected assists = assists × (on-ice xG for + 5) ÷ (on-ice goals for + 5), kept between 0.6 and 1.6.
- If his team has scored far more than its chances while he's on the ice, his assists are scaled down. If it's been snakebitten, they're scaled up.
- Goalies: luck-adjusted = actual + ½ × (goals against − expected goals against) × 1.3.
- Only half the gap counts as luck, because goaltending skill persists.
- The 1.3 is each goal's −1 plus the 0.3 save it cost.
Example: 0 goals on 1.54 xG in 5 games adds back about 4 × 1.5 ≈ 6 points, about 1.2 a game.
Projections (Proj/G)
Projected fantasy points per game, rebuilt every hour:
- Start from luck-adjusted points per game this season.
- Blend with last season's points per game, which counts as 15 games' worth:
(GP × this season + 15 × last season) ÷ (GP + 15).
- After 5 games this season is 25% of the result; after 45 games, 75%.
- With fewer than 10 games last season, it blends toward the average for his position (forward, defense or goalie) with 8 games' weight instead.
- Adjust for ice time: compare his last 3 games' ice time with his season average. The change is capped at ±15% and half of it is applied. A player promoted to the top line moves up right away.
Last season's numbers line up with Yahoo's (e.g. Ekholm 3.71 vs Yahoo's 3.70 FP/GP), so the scoring and data agree.
Goalie stats: GSAx and starts
- GSAx (goals saved above expected) = expected goals against − goals allowed this season. It counts unblocked, non-empty-net shots he faced. Positive means he stops more than the shots deserve.
- Starts: share of the team's last 10 games where he played 30+ minutes. A goalie's Proj is multiplied by this, because he only scores when he starts.
Schedule: weeks, off-nights, back-to-backs
- Fantasy weeks run Monday to Sunday. The first starts on opening day, and the last ends on the final regular-season day. A week with fewer than 16 games (a league break) is folded into the week after, which matches Yahoo's week list (e.g. Week 19, Feb 1–14).
- Off-night: a day when fewer than half the league plays (under 16 teams). Fewer games compete for your lineup spots, so those games are easier to use.
- B2B: the team also played the day before, the second night of a back-to-back.
- 😴: the opponent played the day before.
- Compare teams: the row at the bottom counts how many of the picked teams play each day. Red means none of them do.
Schedule score and Proj
Each game adds:
- its matchup factor: the opponent's fantasy points allowed per game to skaters ÷ the league average, kept between 0.75 and 1.25;
- × 1.5 on an off-night;
- -0.1 on the second night of a back-to-back;
- +0.1 against a tired opponent.
So it reads roughly as "useful games": four average games ≈ 4.0. On the fantasy page only games not yet started count (Games shows them, with off-nights in brackets).
Proj = Proj/G × schedule score (× start share for goalies)
It's the default ranking: players scoring well whose team has a heavy or soft schedule rise to the top.
Team FP for and allowed
Per game, in the recent window:
- Skater FP: fantasy points the team's own skaters score.
- Allowed: points opposing skaters score against the team.
- Goalie FP / G allowed: the same for goalies.
Green and red mark values at least 15% better or worse than the league average for a fantasy manager. For example, a team that allows a lot is good to stream against. The matchup factor in the schedule score uses the season version of "Allowed".
Yahoo league availability
A snapshot of your league's free agents and waivers (players who've played this season), saved from Yahoo's player list. It's matched to NHL players by name, team and position, with accents, short first names and Yahoo's team codes handled. The snapshot time shows on the fantasy page, which flags it once it's over a day old. Pickups by other managers since then won't show until it's refreshed.
How the numbers are checked
- Ice time: each game's shift totals are compared with the box score. Differences over 30 seconds are logged.
- On-ice matching: plus/minus rebuilt from on-ice goals is compared with the box score every game. It matched 863 of 864 skaters on the first 24 games tested.
- Fantasy stats: every scoring stat matched the NHL's stats API exactly.
- Expected goals: they add up to actual goals across all shots and are calibrated by band.
- Names: some older NHL data garbles accented names ("Stützle"). Every run repairs them.