How we handle stats
Statsmith answers plain-English questions with real numbers. This page is the long version of what that sentence means — where the numbers come from, how the computed ones are built, and every place ours differ from the numbers you'd find elsewhere. The disagreements are on this page on purpose. A stats site that hides them is a stats site you can't check.
The approach
The model routes and phrases. Postgres computes.
Every number that reaches you is computed from source game data — never generated or estimated by AI. A language model reads your question, decides which data it needs, and writes a query; the database runs it and returns rows. The model never types a figure into an answer.
That holds even for the sentence you read at the top of an answer. The
model writes a template — "Bonds hit {home_runs} home
runs in {season}" — and the values are substituted server-side
from the actual result row. A template that names a column the result doesn't
have, or a column that came back empty, is thrown away and replaced with a
plain summary of the rows. So is a template with no placeholders at all:
a sentence with nothing bound to the data is the model's claim, however
plausible it reads. Counts and records ("went 5-4 in these 9 games") are
derived in code from the rows, not inferred by a model that can't see them.
The worst case is a clumsy sentence. It is never a wrong number.
Every answer says what it computed
Alongside the answer is an interpretation of the question we actually answered — the seasons covered, the qualification floor applied, whether it's regular season or includes playoffs. Leaderboards say their floor out loud, because a career batting-average board with no floor hands the all-time record to a man who went 1-for-1 and never batted again.
A filter we can't apply is announced, not silently dropped
Ask for "the most goals Gretzky scored on a Monday night" and you'll get his Monday best plus a note saying "night" wasn't applied — because our hockey game records carry no start time at all. We answer anyway (most people saying "Monday night" mean Monday), we keep the unapplied word out of the answer sentence, and we tell you it was dropped. The rule is general: any qualifier the data can't express gets named. Silence isn't an option.
For the record: NHL, NBA and NFL game records have no start-time column. MLB has a first-pitch time for about 70% of games, mostly missing on older ones — so filtering on it would quietly discard a third of history, which is worse than not filtering. We treat it as unavailable unless the answer names what was excluded.
We refuse rather than guess
When the data can't support an answer, you get a refusal that names what's missing — not a plausible-looking number. Concretely:
- Below a recording floor, the value doesn't exist. The NHL didn't record shots on goal until 1959-60. Gordie Howe debuted in 1946-47, so his career shooting percentage isn't a number anyone has; we store NULL and refuse the question naming the floor, rather than computing 21% from the half of his career that happens to be covered.
- Metrics frozen in time are gated to explicit mentions. We hold FiveThirtyEight's RAPTOR archive, which stops at 2022. It never appears as a default ranking column; it answers only when you say "RAPTOR", only for seasons it covers, always labeled with its window.
- Proprietary data stays out. Statcast velocity and spin, tracking and matchup data, PFF grades, DRS/UZR/OAA defensive ratings, Next Gen Stats — we don't hold them and don't approximate them. "Best defensive shortstop" as a rating is a refusal, not a gap we paper over. (Basic fielding counts by position — games, putouts, assists, errors, double plays — we do have, and say so.)
The record book beats our own reconstruction
Where an authoritative season total exists, we serve it instead of re-adding our own parts. Anything rebuilt from parts silently inherits every hole in the parts: a player-season line assembled from the games we'd ingested once reported a Red Sox outfielder playing 26 games in 2024, because the ingest was 402 games into a 2,430-game season. Season lines now read from the record book through the last archived season and from our own live rollup only after it — and the boundary is a query, not a hardcoded year, so it moves itself when the annual refresh lands.
Same rule in basketball: team-season totals come from the archive's own team file rather than summing player lines, because roughly 5% of turnovers are charged to the team (shot-clock, backcourt, too-many-men) and belong to no player at all. Summing players gave Milwaukee 1,137 turnovers in 2022-23 against a true 1,199 — and inflated every usage rate built on that denominator.
Rate stats are ratios of totals, never averages of rates
Each stat we serve is declared once — its formula over totals, its qualification floor, its exposure column, its era floor, and the caveat that must ride along with it. The database columns, the instructions the query model reads, and our own regression tests are all generated from that one declaration, so they can't drift apart. Averaging season rates to get a career rate is structurally impossible for these stats, which is the single most common way a career number comes out wrong.
Baseball
The metric names are open and the formulas are published; what varies between sites is the inputs. Ours are our own. Every value below is our implementation of a published method, computed from the SABR Lahman Database for season lines and league constants and from our own full-history games table (1901+) for park factors. We never copy computed values from Baseball-Reference, FanGraphs, or anyone else. Because our measured inputs differ from theirs, our values differ from theirs by a few points. That's expected, not a bug.
League constants, re-derived per season
Every batting constant is computed per season and league from non-pitcher batting rows, so pitchers hitting doesn't deflate the baseline that hitters are measured against. Era adjustment falls out by construction — a 1930 hitter is measured only against 1930.
- Linear weights — Palmer-style event run values
(
.47·1B, .78·2B, 1.09·3B, 1.40·HR, .33·(uBB+HBP)) with the out value derived per season and league so league batting runs sum to zero. - wOBA — Tango's published method, over the published denominator
AB + BB − IBB + SF + HBP, with the scale chosen per season and league so that league wOBA equals league OBP, the defining normalization of the stat. - wRC+ — the published park-and-league-adjusted form. The PA-weighted league mean is exactly 100, by construction.
- OPS+ — Baseball-Reference's formula, with the league rates park-adjusted by the square root of the park factor each (a run factor splits multiplicatively across OBP and SLG). Traded players are aggregated PA-weighted across stints, and every stint uses its own league's constants and its own team's park.
- FIP —
(13·HR + 3·(BB+HBP) − 2·K)/IP + C, with C derived per season and league so league FIP equals league ERA. FIP− and ERA+ are the park- and league-adjusted forms; league aggregate ERA+ is exactly 100.
A pitcher with zero earned runs would have infinite ERA+, so ERA+ is empty for those seasons, and leaderboards apply an innings floor we state in the answer (Lahman has no official-qualifier column, so we derive qualification ourselves and say which rule we used).
Park factors — ours, from our own games
For every team-season we can match to our games table, we compute runs per game at home against runs per game on the road, counting both teams' runs:
pf_raw = (runs/game in home games) / (runs/game in road games)Then it's pooled over a centered three-season window, regressed toward 1.0
with an 81-game prior (pf = (pf_raw·G + 81) / (G + 81)), halved
for application because players play about half their games at home, and
normalized per season and league so the exposure-weighted mean applied factor
is exactly 1.0. That last step is what makes the league-mean invariants above
exact. Sanity checks land where they should: Coors 1997 ≈ 1.20, Dodger Stadium
1966 ≈ 0.92, PacBell 2002 ≈ 0.95. Teams we can't match — pre-1901, the Federal
League, some Negro Leagues seasons — get a neutral 1.0, and a mid-window
stadium move smears across one season, which we accept and disclose.
sWAR
sWAR is our own WAR implementation, built from published components:
- Batting runs — linear-weight runs against the peer group: position players against non-pitchers, and pitchers' batting against other pitchers, which is the WAR convention. (It matters: Randy Johnson's bat cost him 107 runs measured against the whole league and 13 against fellow pitchers.) Park-adjusted.
- Pitching runs — runs prevented,
(lgERA × parkFactor − ERA)/9 × IP, earned-run based. - Positional adjustment — Tango's published values per 150 games (C +12.5, SS +7.5, 2B/3B/CF +2.5, LF/RF −7.5, 1B −12.5, DH −17.5), prorated by games at each position.
- Replacement level — the published 2013 bWAR/fWAR accord, adopted
verbatim: 1,000 WAR per 2,430-game season, 57% to position players and 43%
to pitchers, allocated over plate appearances and innings. The derived
batter constant lands around 18–20 runs per 600 PA in the modern game,
consistent with the published rule of thumb. Because the pool is fixed,
total sWAR in a league-season equals
1000/2430 × gamesin every era by construction (2019 check: 999.6). - Runs per win — Tango's published
1.5 × (league runs per team game) + 3, about 10.2 in 2019 and 8.1 in 1968, per season and league.
There is no fielding component yet. A TotalZone-style build from our play-level data is planned; until it lands, defense-first careers — Ozzie Smith, Mazeroski, Andruw Jones — are understated by exactly their fielding value, and we refuse "best defensive X" outright rather than answer it badly. Our play-by-play carries per-play fielder credits from 1950 onward, which is also roughly where the industry's TotalZone era begins.
sWAR is not bWAR and it is not fWAR. Different park factors, different inputs, no fielding term, earned runs where bWAR uses total runs allowed. Answers that serve it say so. Here is what that actually costs, measured against the published values:
| Season | Ours | Published |
|---|---|---|
| Ruth 1923 sWAR | 13.6 | 14.1 bWAR |
| Bonds 2001 sWAR | 12.8 | 11.9 bWAR / 12.9 fWAR |
| Gibson 1968 sWAR | 10.9 | 11.9 bWAR |
| Pedro 2000 sWAR | 9.5 | 11.7 bWAR / ~9.9 fWAR |
| Bonds 2002 wRC+ | 253 | 244 FanGraphs |
| Ruth 1920 wRC+ | 244 | 239 FanGraphs |
| Bonds 2002 OPS+ | 269 | 268 B-Ref |
| Gibson 1968 ERA+ | 259 | 258 B-Ref |
| Pedro 2000 ERA+ | 288 | 291 B-Ref |
| Pedro 1999 FIP | 1.46 | 1.39 FanGraphs |
The park-normalized stats land within a point or two. wRC+ runs about five to nine points high at the extremes — a weights-and-scale lineage difference, visible only where the values are already absurd. The top of our career sWAR table is Ruth 180.3 (bWAR 182.6), Cobb 153.6, Cy Young 141.2, Walter Johnson 139.8, Bonds 137.1: the inner circle, in a familiar order, with pitchers and pre-integration stars sitting a few wins off bWAR for the reasons above.
Career rate stats
Career BA/OBP/SLG/OPS, ERA, WHIP, K/9 and stolen-base success rate are formed from career component sums, with the published leaderboard floors (3,000 PA for batting, 1,000 IP for pitching) stated in the answer. Ted Williams' .4817 OBP matches the published all-time record exactly. Where the historical record is thin, the formula follows it rather than patching it: Lahman records no sacrifice flies before 1954 and no hit-by-pitch before 1884, so older OBP denominators omit them, and caught stealing is largely unrecorded before 1951, so stolen-base success rate carries a 1951 floor instead of a flattering number.
One disagreement to know about: our source's Negro Leagues coverage differs from MLB's official record book, which credits Josh Gibson with a .372 career batting average as the all-time record. Ours comes out .364, behind Cobb. That is a coverage difference, not a verdict, and answers say the values follow our data.
Hockey
Era-adjusted points
Our own metric, not an official NHL stat, and answers that serve it say so. For each season of a career:
era_adjusted_points = points × (reference_gpg / league_gpg_that_season)where league goals per game comes from our own game finals and the reference is the plain mean across all seasons. One correction matters: NHL final scores include the shootout winner's extra goal, which is a standings artifact nobody scored. Leaving it in overstated league scoring by 1–2.6% in every season since 2005-06 and therefore deflated every shootout-era player's career value. We subtract one goal per shootout-decided game.
Career rates from raw components
Career save percentage and goals-against average are computed once from
career component sums — saves over shots against, and
3600 × goals_against / seconds_played — never by averaging season
rates. Hasek's .9223 and Alec Connell's 1.92 GAA match the published all-time
records, on the standard 250-goalie-game floor. Skater boards use 400 games
for points and assists per game and 200 career goals for goals per game and
shooting percentage, which is where Gretzky's 1.921 and Bossy's .762 sit as
published.
Era guards are structural, not advisory. Goals against and minutes exist from 1917-18, so GAA is a clean full-history ratio. Saves and shots against were only recorded from 1955-56, and skater shots from 1959-60 — so a career that began earlier stores no value at all, and the question is refused with the floor named. Sawchuk and Plante have no career save percentage here, because they have none anywhere. Separately, all-time GAA boards are dominated by the low-scoring 1920s and 30s; when you mean the modern game, we'll say so and offer the filter.
Basketball
Usage and the team-share family
Usage rate, assist percentage, rebound percentage and the rest all measure a player's box line against his team's totals, so they're only as good as the team denominator — which is why those totals come from the archive's authoritative team file rather than a sum of player lines (see above). Usage is the published box-score formula:
USG% = 100 × ((FGA + 0.44·FTA + TOV) × (team MP / 5)) ÷ (MP × (team FGA + 0.44·team FTA + team TOV))Turnovers weren't recorded before 1977-78, so usage and every
turnover-dependent share carry a 1978 floor and are refused below it.
Efficiency stats follow their published definitions exactly —
TS% = PTS / (2 × (FGA + 0.44·FTA)),
eFG% = (FG + 0.5·3P) / FGA — over career sums, on the
record-book floors (400 games for per-game boards, 2,000 field goals made for
shooting boards, 1,200 free throws made, 250 threes made).
Era floors and league span
Rebounds are recorded from 1950-51, steals, blocks and the offensive /defensive rebound split from 1973-74, turnovers from 1977-78, and the NBA three-point line arrives in 1979-80 (the ABA had it from 1967-68, and those threes are counted). Rebounds per game divides by games in rebound-recorded seasons, so a career straddling 1950-51 — George Mikan's — comes out at his published 13.4 rather than being quietly understated. Career totals span NBA, ABA and BAA regular-season play combined, which is why Julius Erving's scoring average here is his combined 24.2 and not his NBA-only 22.0; the answer says so.
Win Shares are our own computation of the published Kubatko method across all leagues from 1947 — the same tier as public Win Share boards, not the same numbers, and labeled as ours.
Football
Passer rating, computed exactly
Career passer rating uses the published NFL formula over career sums, with each of the four terms clamped to the 0–2.375 range the formula specifies — which is precisely why it can't be expressed as a simple ratio and is computed in its own pass. It checks out against the published figures: Brady 97.2, Brees 98.7.
The 1999 floor, and what it does to careers
Our football archive starts in 1999. Every career number is therefore a "since 1999" number, and we say it in the answer:
- Careers entirely before 1999 are absent — Jim Brown's 5.2 yards per carry isn't a number we can serve, and we refuse it naming the floor.
- Careers that began before 1999 are partial, and the answer discloses it. Peyton Manning's career passer rating reads 98.1 here against a published 96.5, entirely because his 1998 rookie season is outside the archive.
Where our source disagrees with the official record
- Targets are missing for 2003–2008. Not a floor — a hole: season totals run 16,000–18,000 in surrounding years and 0–67 in those six. Any career touching that span stores no target total and no catch rate at all, and catch-rate leaderboards start in 2009. We don't approximate it.
- Sacks and games played are derived from play-by-play and can differ from the official record by about half a sack or one game. DeMarcus Ware reads 139.0 here against an official 138.5; Aaron Donald's 111.0 and J.J. Watt's 114.5 match exactly.
- Team-season yardage is reconstructed from play-by-play and can differ from official NFL figures by about 1%. Answers describe it that way.
- Three games in the archive have no play-by-play at all, so they carry no player lines — which is why Kurt Warner's 1999 passing total runs 309 yards short of official. That's upstream of us, and documented rather than patched.
What we have, by sport and era
Coverage is not one number per sport. Each layer — final scores, box scores, play-by-play, on-ice units — has its own floor, set either by the season the league started recording the thing or by the season our source starts carrying it. Those floors don't line up, and pretending they do is how a site ends up serving a career total that quietly covers half a career. The spans below were measured against the loaded database, not copied from a source's own description of itself. Below a floor we refuse and name it.
Baseball
Three depths, deliberately kept apart: the record book reaches 1871, our own game log starts in 1901, and play-by-play starts in 1950.
| Layer | Covered |
|---|---|
| Final scores, team records, our own game log | 1901 → |
| Player box lines, batting and pitching | 1901 → |
| Play-by-play: game state, comebacks, win probability | 1950 → |
| Season stat lines, official team records, standings, All-Star, Hall of Fame | 1871 → |
| Award winners | 1877 → (voting detail 1911 →) |
| Amateur draft | 1965 → (the first draft) |
| Fielding by position — games, putouts, assists, errors, double plays | 1871 → |
| Per-play fielder credits (the input a future defensive metric needs) | 1950 → |
| Statcast velocity/spin/exit velocity, DRS/UZR/OAA | never — proprietary |
Football
One hard floor and a few later ones. Everything about the NFL here is a "since 1999" number, said out loud in the answer.
| Layer | Covered |
|---|---|
| Games, play-by-play, game state, win probability | 1999 → |
| Player stat lines, per game and per season | 1999 → |
| Team-season totals | 1999 → |
| Head coaches, stadium, roof, surface, weather, rest days, referee, closing spread | 1999 → |
| Kickoff time and weekday | 2000 → (blank for 1999) |
| Closing moneyline | 2006 → |
| Snap counts | 2013 → (the source's 2012 file is a broken stub; we don't claim it) |
| Draft picks | 1980 → |
| Award winners — AP MVP | 1957 → (DPOY 1971 →, OPOY 1972 →, rookie awards 1967 →) |
| Targets and catch rate | 1999 → (2003–2008 missing entirely — see below) |
| PFF grades, Next Gen Stats tracking | never — proprietary |
Basketball
Box scores go back to the BAA; play-by-play starts fifty years later. The gap between those two lines is where most basketball refusals come from.
| Layer | Covered |
|---|---|
| Game finals, including the BAA years and defunct franchises | 1946-47 → |
| Player box lines | 1946-47 →, complete from 1954-55 (1946-47 has box lines for 18 of 350 games) |
| Play-by-play: game state, per-quarter scoring, five-man on-court units | 1996-97 → |
| Authoritative team-season totals | 1946-47 → |
| Season stat lines and our computed Win Shares | 1946-47 → |
| Draft; All-Star selections; MVP voting | 1947 →; 1950-51 →; 1955-56 → |
| RAPTOR; DARKO | 1977–2022 (frozen); 1996-97 → |
| Per-stat recording floors | rebounds 1950-51, steals/blocks and the offensive-defensive rebound split 1973-74, turnovers 1977-78, three-pointers 1979-80 |
| Overtime flag | unknown for many games before 1996-97 — OT counts there are refused, not guessed |
| One player's own minutes, fouls or plus-minus in a single game | not carried (lineup minutes and lineup plus-minus are) |
| Tracking, who-guarded-whom, RAPM / EPM / LEBRON | never — proprietary |
Hockey
The deepest history we hold, and the widest spread between layers: the goal-by-goal record runs to 1917-18, the real box score to 1948-49, and the modern tracked columns only to the late nineties.
| Layer | Covered |
|---|---|
| Official finals, goal-by-goal sequences, comebacks and blown leads | 1917-18 → (2004-05 was cancelled by the lockout — no games exist) |
| Team-season lines: standings points, W/L/T/OTL, goals, shots, penalties | 1917-18 → |
| Power play and penalty kill | 1977-78 → (earlier seasons are junk at the source, so we null them) |
| Team hits and blocked shots | 2005-06 → |
| Playoff series structure — round, participants, series winner | 1917-18 → |
| Player season lines, career totals and rates | 1917-18 → |
| Per-game scoring lines, derived from the goal events | 1917-18 →, except 1934-35 and 1935-36, whose assist records don't reconcile with the official totals and are excluded |
| Full per-game box: games played, goalie line, penalties | 1948-49 → |
| Shots on goal and plus-minus, per game | 1959-60 → |
| Skater ice time, hits, blocks, giveaways, takeaways, faceoff % | 1997-98 → (goalie ice time is carried at every era) |
| On-ice five-man units by strength — 5v5, power play, penalty kill, 3-on-3, empty net | 2010-11 → |
| Draft; trophies, winner / runner-up / finalist | 1963 → (the first draft); 1917-18 → |
| Award vote shares | not published in the source — winner status only |
One cross-sport gap worth naming
Win probability exists for baseball and football only. Both carry a per-play model estimate on every play we hold. The hockey and basketball models aren't fitted yet, so "most improbable win" in those two sports is a refusal that says the stat is coming — not a number we invented in the meantime.
Known limits
These are real, and we'd rather print them than let you discover them:
- Pre-play-by-play eras are finals-and-box-scores only. Comebacks, lead changes, game-state and per-quarter questions exist only where play-by-play exists; outside that, the answer is a bounded one or a refusal, never an extrapolation. Basketball quarter data is play-by-play-era only, so a question about George Gervin's 33-point quarter is answered with its bounds stated.
- Archival basketball box scores disagree with other references before 1984, at material rates — points match exactly about 82% of the time in 1955–73. Those answers carry a "per the archival box score" caveat. Famous lines verify exactly, and where a game's player lines don't reconcile against the team total we exclude it rather than serve it — which is why Wilt Chamberlain's 55-rebound game is missing, and the system discloses the absence instead of quietly rounding it away.
- Some seasons are simply not in the source. NHL player scoring for 1934–36 is excluded wholesale. NBA game results exist for the NBA and BAA but not the ABA, even though ABA player seasons do.
- Our advanced baseball metrics run on the annual record-book refresh, so they're empty for a season still being played until that lands. Empty and honest beats provisional and unlabeled.
- Our numbers are computed from public data, not official league records. We don't warrant they match official records in every case. If you find one that looks wrong, we genuinely want to know — that link is a box you type into, no account, no email required.
Where the data comes from
- MLB — MLB Advanced Media (© MLBAM) for games and play-by-play; the SABR Lahman Database for season lines, league constants and the historical record book.
- NFL — nflverse (CC-BY-4.0), 1999 onward.
- NHL — the NHL's public statistics interfaces.
- NBA — public archival datasets, plus FiveThirtyEight's RAPTOR archive (CC-BY-4.0, 1977–2022, frozen and explicit-mention only).
Full attribution, the affiliation disclaimer and the privacy practices live on the terms page. We never redistribute raw source feeds — answers are computed results with their provenance, not data dumps.