Loading ticker...
Loading… @TheOddsGap

Historical Odds Data

Every price this site has scanned, as a plain CSV. One row per snapshot, book, market and side, with the de-vigged fair probability and a flag marking who had the best price at that moment. No API key, no signup for the last 7 days.

What this is: the same raw_snapshots table the Line Shop, the closing-line math, and the book comparison all read from. It is the site's own source data, not a summary of it. Prediction-market prices are fee-adjusted, so an exchange price in this file is what a taker actually pays, not the raw ask.

Get the file

One request, one CSV. It streams, so a long window starts downloading immediately instead of waiting on the server to build the whole thing.

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

Last seven days of MLB, every market. To narrow it down:

curl -o mlb-ml.csv "https://theoddsgap.com/api/odds-export.csv?sport=baseball_mlb&market=ml&start=2026-07-25&end=2026-08-01"

Straight into pandas, if that is where it is going:

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

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 on the same market, side and line at that snapshot. Ties all get a 1.

Two things to know about best_price_flag

Parameters

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_fifa_world_cup, soccer_uefa_champs_league, soccer_usa_mls, tennis_atp_canadian_open, tennis_atp_washington_open, tennis_wta_canadian_open.
startYYYY-MM-DD or a full ISO timestamp. Defaults to the start of your window.
endYYYY-MM-DD or a full ISO timestamp. Defaults to now.
marketml, spread, total, a comma-separated list, or all (default).
formatlong. The only value in v1.

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 was older than your window allows. Very large pulls are capped, and X-Next-Start hands back the timestamp to resume from.

How far back you get

The beta is free as well, it just wants an email. Drop it here and the same URL starts returning 90 days.

Snapshots roll off after 90 days, so this window is everything there is. Openers and closing lines are captured separately and survive the rollover.

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 9pm ET, and a game can appear at one line at one book and a different line at another. Nothing is backfilled or smoothed.

Using it

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: admin@theoddsgap.com.

Live JSON instead of history: API docs.