Loading ticker...
Loading… @TheOddsGap

The Odds Gap Data

Historical Sports Betting Odds Data

Every price we scan across US sportsbooks and prediction markets, in one clean CSV. Fair odds and a best-price flag on every row, ready for models, research and backtests.

A sample week, September 15 to 21, 2026, is free to test with. No signup, no key.

This week's lines are free on the Linesheet; past lines are in the data files.

What's in the File

Every Price, Every Scan

Game Lines

Moneyline, spread and total from every book, one row per snapshot.

Player Props

First seen, six hours out, one hour out and the close.

Fair Odds

De-vigged probability on every row, with the method published.

Exchange Prices

Prediction-market prices, with any taker fee already applied.

Download

Get the File

Download CSV

One request, one streaming CSV. Without a key, every request returns the same sample week, September 15 to 21, 2026 (ET game dates), whatever window it asks for, and says so in an X-Data-Sample header; recent and ongoing data need a paid key.

  • CSV: the default, and it opens in any spreadsheet.
  • JSON: the same rows as objects, with the column list and window in meta, for developers and agents.
  • Parquet: the same rows, typed and compressed, for pandas, polars or DuckDB.

Every file comes in all three with the same rows and columns: change .csv to .json or .parquet, or add format=.

From the Command Line

curl -o mlb.csv "https://theoddsgap.com/api/odds-export.csv?sport=baseball_mlb"

Straight Into Pandas

import pandas as pd
df = pd.read_csv("https://theoddsgap.com/api/odds-export.csv?sport=baseball_mlb&market=ml")

Player Props as JSON

curl "https://theoddsgap.com/api/props-export?player=judge&anchor=close&format=json"

Access

Free to Start, Full History When You Need It

Free

$0

  • Free, no signup: a sample week, September 15 to 21, 2026, to test with. No email, no key, no friction.
  • Game lines and player props
  • Trends data: team results, player game logs, graded player props, game conditions and line moves
  • Every book, every scan
Download Free

The site stores each scan for 45 days, then it rolls off the per-scan file. Older scans stay in the full archive, one file per day back to June 4, 2026. Also kept for good: the Pinnacle open for each game, each finished game's closing prices on its game page, and each book's earliest and closing price at every line in the history file, back to June 4, 2026.

Reference

Technical Reference

Long (tidy) format: one row per snapshot, book, market and side. Everything a modeler needs is below.

Columns

Long (tidy) format. Long is the modeling standard, and a wide layout with a column per book breaks every time a book is added or removed. Need wide? Pivot on book, or ask us and we will add it.

ColumnMeaning
snapshot_tsUTC ISO timestamp of the scan that captured this price.
sportSport key, e.g. baseball_mlb, basketball_nba.
away, homeTeam names as the odds feed supplies them.
commence_timeUTC ISO scheduled start. Rows where this is later than snapshot_ts are pre-game.
marketml, spread, or total.
sidehome / away / draw for moneyline, home / away for spread, over / under for totals.
lineThe spread or total number. Blank on moneyline rows.
bookBook key, e.g. draftkings, pinnacle, kalshi.
american_oddsExecutable American odds. Exchange taker fees are already applied, so this compares directly to a sportsbook price.
devig_fair_probFair probability from 0 to 1 (not a percentage), from de-vigging this book's own two sides with the power method. Soccer moneylines are normalized across all three outcomes. Blank when the book posted only one side of the market, because there is no vig to strip and we will not invent a number.
best_price_flag1 if this book tied or beat every other book in the best-price set on the same market, side and line at that snapshot. Ties all get a 1.

Three Things to Know About best_price_flag

  • Only books a US bettor can use compete for it by default: the legal US sportsbooks plus Kalshi, Polymarket US, ProphetX and Novig. Offshore books and Pinnacle still have every row in the file, they just never carry the flag. Choose your own set with books= or exclude_books=, and the X-Best-Books header says which set was used.
  • Books are only compared at the same line. A -1.5 at one book is not the same bet as a -2.5 at another, so they never compete for the flag.
  • That means a book sitting alone at an unusual line is trivially the best price at that line and gets a 1. If you are ranking books, group by (market, side, line) and require more than one book in the group.
Parameters and Headers
ParamMeaning
sportRequired. One sport key, tennis for every rotating tennis key, or all. Keys: americanfootball_ncaaf, americanfootball_nfl, baseball_mlb, basketball_nba, basketball_ncaab, basketball_wnba, icehockey_nhl, mma_mixed_martial_arts, soccer_epl, soccer_fifa_world_cup, soccer_france_ligue_one, soccer_germany_bundesliga, soccer_italy_serie_a, soccer_spain_la_liga, soccer_uefa_champs_league, soccer_usa_mls, tennis_atp_paris_masters, tennis_atp_swiss_indoors, tennis_atp_vienna_open, tennis_wta_pan_pacific_open.
startYYYY-MM-DD or a full ISO timestamp. Defaults to the start of your window. Without a key the window is the sample week, and a start outside it returns the whole week.
endYYYY-MM-DD or a full ISO timestamp. Defaults to now, or to the end of the sample week without a key.
marketml, spread, total, a comma-separated list, or all (default).
formatcsv (default), json or parquet, or use the .json or .parquet path. long still means CSV. Rows are long in every format.
books, exclude_booksComma-separated book keys deciding which books may carry best_price_flag. Every book's rows still appear. Part of paid access.

Response headers carry the window that was actually served: X-Window-Start, X-Window-End, X-Access-Tier, and X-Window-Clamped when a requested start or end fell outside your window. A file from the free sample week also carries X-Data-Sample: 1, its dates in X-Sample-First-Day and X-Sample-Last-Day, and the same note in the JSON meta. Very large pulls are capped, and X-Next-Start hands back the timestamp to resume from. X-Provenance-Missing names any day in your window we do not hold, rather than leaving a silent hole.

Player Props File

A second export covers player props: /api/props-export. Different shape from the file above, on purpose. Props are recorded at up to four fixed checkpoints per prop rather than on every scan: when we first see it, around six hours before the game, around one hour before, and at the close. The close is the last scan before the game starts, and props rescan every hour on the live board, so it lands inside that final window rather than at the literal last tick. Most vendors' closing lines work the same way; we would rather say it than let you assume otherwise. Each row carries the consensus fair probability (the median of every quoting book's de-vigged price, minimum three books), the best price on the board at that moment, which book had it, and how many books were quoting. There is no per-book ladder in it; the checkpoints are what we store.

Every row quotes the Over side: consensus_fair is the de-vigged probability of the Over in percent, and best_odds is the best Over price. The Under fair is 100 minus consensus_fair.

Touchdown scorer markets are Yes-only at the sportsbooks, so the Over is the Yes. First and Last Touchdown Scorer have one winner per game, so each sportsbook's full list is de-vigged together like a moneyline and the fair is the median across three or more sportsbooks. Anytime Touchdown Scorer can have several winners, so no book's list can be de-vigged on its own: consensus_fair is blank on those rows until three or more sportsbooks also post the No, and best_odds is still the best Yes price.

Pull a player's closing lines as CSV or JSON:

curl "https://theoddsgap.com/api/props-export?player=judge&anchor=close"
curl "https://theoddsgap.com/api/props-export?player=judge&market=batter_hits&anchor=close&format=json"

Every row also carries a player_id column (the last column in the CSV): the league and the name as the feed spells it, lowercased with spaces and punctuation turned into hyphens, so it stays the same on every pull. Pass it back to get exactly one player:

curl "https://theoddsgap.com/api/props-export?player_id=nfl:amon-ra-st-brown&anchor=close"

To find a player's player_id, search by name. Returns each match with the markets they appear in and their last game date:

curl "https://theoddsgap.com/api/props-export/players?sport=nfl&q=st.%20brown"

To see every market key we have captured, with a plain-English label, the sport, the row count and the first and last game date:

curl "https://theoddsgap.com/api/props-export/markets"

Name searches are case-insensitive substrings, with spaces URL-encoded and punctuation as the feed spells it, so st.%20brown finds Amon-Ra St. Brown and st%20brown does not. Rows captured before September 14, 2026 on a market two leagues share (NFL and college, NBA and WNBA) sometimes cannot be pinned to one league; their player_id starts with the sport instead, like football:, rather than a guess.

Parameters: player (name substring, case-insensitive), player_id (exact), market (exact market key, e.g. batter_hits), anchor (first_seen, t6, t1, close, or all), start and end (game dates), format (csv, json or parquet), books and exclude_books. Access tiers match the file above: a sample week, September 15 to 21, 2026, free with no signup, recent data and the full window with paid access.

Which book is named best: each row stores the one best price seen when it was captured. It is shown when that book is in the best-price set (by default the same set as the file above, so never an offshore book or Pinnacle) and left blank when it is not. We do not fill the gap with a second-best, because we never stored one.

Honesty notes: the site stores each day of props for 45 days, so the oldest day in this file is that far back, and older days are in the full archive, back to August 4, 2026. Only props quoted by three or more books have a consensus fair, so thin markets are absent by design. ProphetX prices captured before the 2026-08-26 repair were not always takeable at $100 (see the exchange price autopsy), so a ProphetX best price from before then is left blank, and consensus fairs from those days lean on those prices too.

Earliest and Closing Prices, Back to 2026-06-04

A third file, /api/odds-history.csv, keeps one row per game, market, side, line and book: the earliest price we captured for that book at that line, its last price before the game started, and the movement between them in probability points. It reaches back well past what the file above stores, to 2026-06-04.

curl -o nfl-history.csv "https://theoddsgap.com/api/odds-history.csv?sport=americanfootball_nfl"

Earliest means the first price this site saw, not the market's opening line. close_best_flag works like best_price_flag above, over the same default set or your own books=. The marks column notes ProphetX prices captured before the 2026-08-26 repair, and ProphetX prices from before August 6, 2026, which had the venue's 2% commission applied on the way out. The X-Provenance-Missing header names any scan day we could not read, so a gap is never silent.

The last four columns, pinn_open_state, pinn_open_line, pinn_open_price and pinn_open_ts, carry the game's PINN Open for that market and side, the same price game pages show: open when Pinnacle priced the game the moment it was first listed, first_sharp when it is Pinnacle's earliest price after the listing, with Pinnacle's own quote time. They are blank when we hold neither, which includes every game before August 5, 2026.

Full Archive, Every Scan Since June 4, 2026

Every scan we have captured, one file per day. Game lines start on June 4, 2026 and player props on August 4, 2026. Each file has the same columns as the matching file above, plus a marks column at the end, so a day stacks under a recent export with no mapping.

The archive is part of paid access. Send your key as the X-OddsGap-Data-Key header, or as key= in the URL. A day is one UTC calendar day, and it can be downloaded 24 hours after it ends.

curl -H "X-OddsGap-Data-Key: YOUR_KEY" -o odds-2026-06-04.csv.gz "https://theoddsgap.com/api/archive/odds/2026-06-04.csv.gz"
curl -H "X-OddsGap-Data-Key: YOUR_KEY" -o props-2026-08-04.csv.gz "https://theoddsgap.com/api/archive/props/2026-08-04.csv.gz"

Files are gzip CSV. Two downloads can run at once across the site, and one key can take 300 files a day. The list of days is at /api/archive/days.

Known Issues Travel With the Data

Some older prices have known problems, and we would rather you knew which. The marks column names the known issue on any row one touches, and the notes file lists every known issue by date range. The main ones:

  • ProphetX prices captured before the August 26, 2026 repair were not always takeable at $100. That date is where the repaired prices start.
  • ProphetX prices from before August 6, 2026 were stored without the venue's 2% commission. It is applied on the way out, and the row says so.
  • We read Novig order sizes 100 times too large until September 28, 2026, so a Novig price from before then may not have been takeable at $100.
  • Exchange prices from before July 23, 2026 are the top of the order book, with no check on the size behind them.
  • Before September 29, 2026 we could attach a Kalshi spread or total to another game between the same two teams.
  • Most June 2026 World Cup moneylines were stored without the draw, so their fair probability is not comparable with a three-way row.

Two kinds of row are left out instead of marked: college rows from Novig, ProphetX and Polymarket US whose match to a game cannot be verified, and exchange moneylines whose two sides could not be a real pair of prices.

Days on File

Open this section to load the list of days.

Sizes are each day's stored file. The CSV download is a different encoding of the same rows and runs larger.

Where the Numbers Come From

Prices are captured on every scan across the books we cover, stored raw, and served back unchanged apart from the exchange fee adjustment. The de-vig, the fee model, and the line-selection rules are all written out on the methodology page, including why the power method is used instead of simple multiplicative scaling.

Coverage gaps are real and we would rather you knew: a book that was not returning a price at a given scan simply has no row, scanning runs 7am to 1am ET, and a game can appear at one line at one book and a different line at another. Nothing is backfilled or smoothed.

Terms of Use

Quoting It

Quoting any figure or finding published on this site is welcome, with attribution to The Odds Gap and a link to the page it came from. Our measurements, the matched-lines comparisons, the staleness and dispersion studies and the captured opening lines, are our own work and are licensed on that basis. The underlying odds are facts we aggregate from sources with their own terms. Bulk or automated reuse of the underlying data, rather than quoting a published figure, needs a conversation first: [email protected].

Using It in Bulk

Free for research, modeling, and writing, with attribution to The Odds Gap and a link to theoddsgap.com. Not permitted: reselling the data, repackaging it as your own feed or product, or sustained bulk scraping (rate limits are enforced). Portions arrive through licensed feeds, so this exists for people who want to study the market, not as a data source for another product. Heavier or commercial use: [email protected].

Live JSON instead of history: API docs.

These terms are also part of our full Terms of Service.

Start With the Free File

A sample week, September 15 to 21, 2026, every book, no signup.

Download Free