data·vault_
← Catalog

NFL betting data: what a sports betting dataset contains, and how one is built

Guide to the NFL Games & Betting Lines 1999-2026 pack · where the lines come from: the spread history guide and the free sports data sources review. Historical records only; nothing on this page is betting advice, a pick, or a prediction.

What "NFL betting data" means as a dataset

Strip the word "betting" down to its records and the dataset is modest: one row per game, carrying the closing point spread, the final score, the closing total, and the kickoff conditions. No tips, no systems, no odds feeds. That is what a sports betting dataset is, and the NFL Games & Betting Lines pack is exactly that shape: 7,548 games from 1999 through the full 2026 schedule, 7,276 of them played with a closing line, 46 columns per row. Use it to study what the lines were and what happened next, which is the whole of what historical analysis can honestly do.

The free 22-row sample carries the same 46 columns and downloads here with no signup, so every table and join on this page can be reproduced before buying anything.

The four ingredients of a betting dataset

Column names below come straight from the games CSV:

IngredientColumn(s)Coverage in the pack
Closing point spreadspread_line (stored relative to the home team)every played game since 1999
Final scores and marginaway_score, home_score, result (home minus away)every played game since 1999
Closing totaltotal_line, scored against total (combined points)same rows as the spread
Kickoff conditionsroof, surface, temp, wind (blank for domes)same rows; moneylines and odds reach back to 2006 (5,407 games)

Two rows from the free sample show the shape:

game_idspread_linetotal_lineFinalresultroof
1999_01_KC_CHI-3 (KC favored)38CHI 20-173outdoors
1999_01_BUF_IND-3 (BUF favored)45.5IND 31-1417dome

Read from that: Kansas City closed as a 3-point road favorite and lost outright; Buffalo closed as a 3-point road favorite and lost by 17. The rows record that; what anyone should do next is not in the file. The full column glossary, including rest days and starting quarterbacks, lives in the games.csv column guide.

Where betting data comes from, legally

The pack's source is nflverse-data, a public GitHub project that publishes game results with closing lines as plain CSV, licensed CC BY 4.0. Commercial analysis is allowed with a credit line. The free sports data review verifies that license and four other sources, league by league.

The honest limits on sources: sportsbook sites show current odds but sell no historical bulk downloads, their terms forbid scraping, and the popular aggregators license their data rather than give it away. A public, openly licensed release is the clean route, and it is why this pack's rows are checksummed copies of nflverse output with derived tables built on top.

How the dataset is assembled: joining spreads to results on game_id

Betting datasets are two stories joined per game. The lines are one story, set before kickoff: a spread, a total, an expected margin. The results are the other, known only after: final scores, the actual margin, the actual combined total. The join key is a per-game identifier, game_id, in the format season_week_AWAY_HOME, for example 1999_01_KC_CHI. In the full pack both stories already live in one row of games.csv; the join below is shown because separate spreads and results files are the common situation when you build a betting dataset from raw sources.

Real example, run against the free sample. First the lines and the results are pulled into two tables, each keyed by game_id:

import pandas as pd

games = pd.read_csv("https://jayjex.github.io/data-vault/data/nfl-games/sample.csv",
                    dtype={"game_id": str})
spreads = games[["game_id", "season", "week", "spread_line", "total_line"]]
results = games[["game_id", "gameday", "away_team", "home_team",
                 "away_score", "home_score", "result"]]

Then one merge lines them up per game:

joined = spreads.merge(results, on="game_id", how="inner")
print(joined.shape)   # (22, 11) on the sample
print(joined.head(5).to_string(index=False))

The printed output from that exact run:

spreads: (22, 5) results: (22, 7) merged: (22, 11)
        game_id  season  week  spread_line  total_line    gameday away_team home_team  away_score  home_score  result
1999_01_MIN_ATL    1999     1         -4.0        49.0 1999-09-12       MIN       ATL          17          14      -3
 1999_01_KC_CHI    1999     1         -3.0        38.0 1999-09-12        KC       CHI          17          20       3
1999_01_PIT_CLE    1999     1         -6.0        37.0 1999-09-12       PIT       CLE          43           0     -43
 1999_01_OAK_GB    1999     1          9.0        43.0 1999-09-12       OAK        GB          24          28       4
1999_01_BUF_IND    1999     1         -3.0        45.5 1999-09-12       BUF       IND          14          31      17

On the full file, the same merge is what assembles the history: 7,548 game rows, of which 7,276 played games carry a closing line, and 272 are the scheduled 2026 games still waiting on scores. Run the merged table through result - spread_line and every cover-and-push question from the spread history guide becomes arithmetic; that is also the check worth running on any spread history CSV you download from anywhere.

After the join, the derived tables in the pack save the group-bys: team-records-by-season.csv (861 rows) carries per-team ATS and over/under records, and season-summaries.csv (27 rows, free in full) carries per-season cover and over/under rates. Both are built from this same joined view.

Weather and totals: the columns that make rows researchable

Weather is what separates a betting dataset from a scores list, because totals react to it and any total analysis needs the conditions on the row. In games.csv the columns are roof, surface, temp (Fahrenheit), and wind (mph), recorded at kickoff, blank for dome games. In the 22-row sample, 6 games are domes with blank temp and 16 are outdoors with values, from 67°F in Green Bay to 80°F in Chicago. The stadium weather guide works those columns across the full file, dome vs outdoor scoring included.

Totals follow the same join logic as spreads: total_line is the pre-kickoff number, total is what the two teams actually scored combined, and over/under records in the derived tables are the comparison, counted per season in season-summaries.csv.

What a betting dataset cannot do

The file holds closing lines and finished games. It holds no opening lines, no line movement, no injury reports, and no probabilities for games that have not happened. Closing lines describe what the market priced at kickoff; they are a record of the past, and nothing in a 7,276-row history predicts week 1 of the next season. This page and the pack are for research and analysis of completed games. If you are looking for picks or staking advice, they are not here, and no historical CSV can supply them.

Get the betting dataset

Start free: the 22-row sample CSV (46 columns, spread to weather) and the complete season-summaries.csv download with no signup, and the MCP queries on the for agents page filter the full 7,548-row file at no cost. The full pack adds all rows, the two derived tables, a data dictionary, and SHA-256 checksums. Prefer a notebook? The pandas quickstart loads the sample in two lines, and the Excel and Google Sheets guide covers the spreadsheet route.

Checkout and download run through Getly. The sample and season-summaries download free here, no signup. Source: nflverse game and betting data, CC BY 4.0. Snapshot taken 2026-09-06; results run through the 2025 season.

NFL betting data questions

What data do you need to analyze NFL betting?

Four things, one row per game: the closing point spread, the final score, the closing total, and kickoff conditions. In the games CSV those are spread_line (stored relative to the home team), result (home minus away), total_line, and roof/temp/wind. The full file covers 7,548 games from 1999 through the 2026 schedule, 7,276 of them played with a closing line.

Where can I legally get historical NFL betting data?

nflverse-data publishes game results with closing lines as a direct CSV download on GitHub, licensed CC BY 4.0, which allows commercial use with attribution. On this site, the 22-row sample and the full season-summaries.csv download free under the same license. Sportsbook sites display odds but offer no bulk downloads and forbid scraping, so openly licensed releases are the legal route.

How do you join a spreads CSV to game results?

Merge on a shared per-game key. Here that key is game_id, formatted season_week_AWAY_HOME (example: 1999_01_KC_CHI). In pandas: spreads.merge(results, on="game_id", how="inner"). On the sample the inner join returns all 22 rows with lines and scores side by side; on the full file the same join assembles 7,276 played games from 1999 through 2025.