---
title: "Sports odds data"
description: "Odds data from sportsbooks and odds comparison sites: pre-match and live lines, spreads, totals and line movement, as timestamped JSON for pricing models."
canonical: https://www.zenrows.com/use-cases/odds-data
updated: 2026-10-18
---

# Sports odds data

Odds data is the price a sportsbook offers on each outcome, such as moneylines, spreads, totals and props, pre-match and live, with the time each line changed. Zenrows collects it from sportsbooks and odds comparison sites, captures the JSON feeds their pages load, and returns timestamped records for pricing models, research and sports data products.

## Sample output: one market across books

```json
{
  "event_id": "example-league-2026-10-24-home-away",
  "sport": "soccer",
  "competition": "Example League",
  "home": "Home Club",
  "away": "Away Club",
  "start_time": "2026-10-24T19:00:00Z",
  "market": "match_result",
  "odds_format": "decimal",
  "captured_at": "2026-10-16T09:15:04Z",
  "books": [
    { "book": "Book A", "home": 2.10, "draw": 3.40, "away": 3.60, "updated_at": "2026-10-16T09:14:51Z" },
    { "book": "Book B", "home": 2.05, "draw": 3.50, "away": 3.75, "updated_at": "2026-10-16T09:13:20Z" },
    { "book": "Book C", "home": 2.12, "draw": 3.30, "away": 3.55, "updated_at": "2026-10-16T09:15:00Z" }
  ],
  "best_price": { "home": 2.12, "draw": 3.50, "away": 3.75 },
  "overround": { "Book A": 1.048, "Book B": 1.021, "Book C": 1.056 }
}
```

An illustrative snapshot of one market. The overround is the sum of implied probabilities (1 divided by each price), which shows each book's margin on the market.

## What odds data teams collect

A single price is rarely the goal. Modellers, data vendors and integrity analysts all need the series: how a line opened, how it moved and where it closed, across several books at once.

| Job | Data you collect | Typical sources |
|---|---|---|
| Line movement history | Opening, current and closing prices with timestamps | bet365, DraftKings, FanDuel, Pinnacle, Betfair Exchange |
| Cross-book comparison | Best available price per outcome, margin per book | Oddschecker, OddsPortal, sportsbooks directly |
| Pricing model inputs | Odds joined to results, lineups, injuries, expected goals | FBref, Transfermarkt, ESPN, league and club sites |
| Live in-play odds | Price, suspended status, score at the moment of change | Sportsbook live event pages |
| Horse racing markets | Runners, prices, non-runners, results | Racing Post, Sportsbet.com.au, tote sites |
| Integrity monitoring | Sharp moves on the same market across books, especially on lower-tier events | Several books polled at short intervals |

## Why scraping sportsbooks breaks

Sportsbook pages are thin shells around live data feeds, and the books restrict who can load them and from where.

| What breaks | What it looks like | How Zenrows handles it |
|---|---|---|
| Odds load from a background feed | The page HTML holds the layout but no prices | Zenrows captures the page's background network calls (XHR) and returns their JSON bodies |
| Country restrictions | A book shows a different market list, or nothing, depending on visitor location | Geotargeting loads the page from the country you study |
| Bot protection | Cloudflare, Akamai or Imperva challenges after repeated requests | Zenrows' stealth gets through Cloudflare, Akamai, Imperva and similar protections, with retries |
| Live prices move in seconds | A polling loop records lines that changed between requests | A Browser session stays on the event page and reads each update as it renders |
| Names differ between books | "Man Utd" on one book, "Manchester United" on another; market names vary too | Store each book's raw names and event ID, and map them to your own IDs |

## How to scrape odds data with Zenrows

1. **Find the feed.** Load one event page with a full browser render, capture its background network calls, and look for the one whose body holds the prices.
2. **Poll pre-match markets.** Fetch the event pages on an interval, more often as kickoff approaches, or send a list of events to Batch.
3. **Stay on live events.** Open a Browser session on an in-play page and read the market every few seconds.
4. **Timestamp and normalise.** Store capture time, the book's own update time if shown, and decimal odds with implied probability.

```python Python
# pip install requests
import json
import requests

params = {
    "apikey": "YOUR_ZENROWS_API_KEY",
    "url": "EVENT_PAGE_URL",
    "js_render": "true",
    "premium_proxy": "true",
    "proxy_country": "gb",
    "wait_for": ".market",  # example selector for the odds panel
    "json_response": "true",
}
data = requests.get("https://api.zenrows.com/v1/", params=params).json()

# Keep the background call that carries the odds and parse its body
odds_call = next(call for call in data["xhr"] if "odds" in call["url"])
markets = json.loads(odds_call["body"])
print(markets)
```

```javascript Node.js
// npm install puppeteer-core
import puppeteer from "puppeteer-core";

const browser = await puppeteer.connect({
  browserWSEndpoint: "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY",
});
const page = await browser.newPage();
await page.goto("LIVE_EVENT_URL", { waitUntil: "domcontentloaded" });
// Example selectors: match them to the book's event page
await page.waitForSelector(".market");

// Read the market every 10 seconds for 5 minutes
for (let i = 0; i < 30; i++) {
  const prices = await page.$$eval(".selection", (rows) =>
    rows.map((row) => ({
      outcome: row.querySelector(".name")?.textContent.trim(),
      odds: row.querySelector(".price")?.textContent.trim(),
    }))
  );
  console.log(new Date().toISOString(), prices);
  await new Promise((resolve) => setTimeout(resolve, 10_000));
}
await browser.close();
```

```bash CLI
npx -y @zenrows/cli init
# Pre-match snapshot from the UK, once the odds panel has loaded
zenrows extract EVENT_PAGE_URL --proxy-country gb --wait-for ".market" \
  --css '{"outcomes":".selection .name","odds":".selection .price"}'
# Every event on the fixture list as one job
zenrows batch create events.jsonl --wait
```

```text Claude Code (MCP)
# Connect once
claude mcp add zenrows -e ZENROWS_API_KEY=YOUR_ZENROWS_API_KEY -- npx -y @zenrows/mcp

# Then ask:
Use Zenrows to open the Oddschecker page for Arsenal v Chelsea, wait for the match
result market to load, and return every bookmaker's decimal odds for home, draw and
away as JSON, with the time you read them.
```

## Which Zenrows product fits

| If you need to | Use | Why |
|---|---|---|
| Snapshot pre-match odds for an event | [Fetch](/products/fetch) | One request returns the page, or its odds feed captured from the background network calls |
| Follow a live event minute by minute | [Browser](/products/browser) | One session stays on the page and reads each update as it renders |
| Snapshot every event on a fixture list at once | [Batch](/products/batch) | All event URLs run as one job, results by webhook |

## What success looks like

| Measure | What good looks like | How to check it |
|---|---|---|
| Capture latency | For live markets, seconds between a book's update and your record | Compare the book's update time with your `captured_at` |
| Snapshot completeness | Every tracked book returns a price for every tracked market each cycle | Count missing book and market pairs per cycle |
| Closing line capture | A final pre-match price is stored for every event | Check for a snapshot within your cutoff before `start_time` |
| Mapping accuracy | Every event and team maps to your own IDs across books | Count unmapped names after each run |
| Stale prices | No stored price is older than your poll interval when the market is open | Alert when a book and market pair has no new snapshot within one interval |

## Odds data FAQ

### What is odds data?

Odds data is the set of prices bookmakers and exchanges offer on sporting outcomes, with timestamps. It includes moneylines or match result prices, point spreads and handicaps, totals, player props and futures, both pre-match and in play. Converted to implied probability, it is the market's estimate of each outcome.

### Is there an odds data API?

Several commercial odds feeds exist, each covering a fixed list of books and markets. Zenrows is the API over the books you choose: you send an event page and get its odds back as JSON, including from regional books and markets a packaged feed may not carry.

### Is it legal to scrape betting odds?

Odds are prices shown publicly on each book's site, and collecting them for analysis and data products is common. Each sportsbook sets terms of use, some jurisdictions restrict access to gambling sites, and official league data can carry its own licensing. Check those for the books and markets you collect, and ask your legal team about your specific use.

### How often should I collect odds?

Pre-match lines move slowly days out and quickly in the last hours, so a common pattern is hourly polls early in the week and polls every few minutes near the start. Live markets change in seconds, which is why in-play collection works best from a Browser session that stays on the page.

### How do I build line movement data?

Store every snapshot, not just the latest price. Each record needs the event, book, market, outcome, decimal odds and capture time. Sort by time per outcome and book to get the series: the first record is the opening line, the last before the start time is the closing line, and the differences in between are the movements. Flag moves larger than your threshold that happen on several books within a few minutes, since those usually carry information.

### Can I collect odds from sportsbooks in other countries?

Yes. Use geotargeting to pick the country the request comes from, for example the UK for UK books or Australia for Australian racing markets, so each book shows the markets and prices offered there. Store the market with every record, because the same book can price an event differently by country.

### What is the difference between odds data and sports data?

Sports data describes what happens on the field: fixtures, scores, lineups, player and team statistics. Odds data describes what the market expects to happen. Models usually need both, joined on event and time, and both are collected the same way with Zenrows.

## Related use cases

- [Financial data scraping](https://www.zenrows.com/use-cases/financial-data-scraping.md): Rate tables, IR pages, filings, fund data and central bank releases, as JSON tables and Markdown documents.
- [Alternative data for investors](https://www.zenrows.com/use-cases/alternative-data.md): Hiring, pricing, app ranks, reviews and store counts per ticker, collected weekly as point-in-time series.
- [Competitor price scraping](https://www.zenrows.com/use-cases/price-scraping.md): Competitor prices, promotions, shipping and stock per SKU from retailers and marketplaces, refreshed on your schedule.
- [News scraping](https://www.zenrows.com/use-cases/news-scraping.md): Full-text articles, headlines, bylines and dates from publishers, Google News and wires, as clean Markdown or JSON.

Start free: https://app.zenrows.com/register. Docs: https://docs.zenrows.com
