Oddschecker API: Get Odds Comparison Data as JSON (Free Alternative)

Oddschecker API - OddsPapi API Blog
How To Guides June 24, 2026

Looking for an Oddschecker API? There Isn’t One.

If you have ever tried to build something on top of Oddschecker the odds-comparison grid, the alerts, the “best price” highlight you have hit the same wall every developer hits: there is no public Oddschecker API. The site is an affiliate business, not a data business. The comparison table renders in the browser, the markup is obfuscated, and scraping it gets your IP blocked fast. There is no JSON endpoint, no API key, no docs.

So how do you get the actual data the price for every outcome, across every bookmaker, in a format you can parse? You point at an aggregator that was built API-first. This guide shows you how to pull the exact same multi-bookmaker comparison Oddschecker shows you, as clean JSON, from OddsPapi covering 350+ bookmakers (Oddschecker tracks roughly 30 UK books), with free historical odds and a real-time WebSocket feed on top.

Why Scraping Oddschecker Is a Dead End

Oddschecker is great for a human eyeballing the grid. It is hostile to a program:

  • No API. There is no documented endpoint, no key, no rate-limit contract. Anything you build is reverse-engineering a private frontend.
  • Anti-bot by design. Cloudflare, rotating class names, and JS-rendered prices mean a naive requests.get() returns nothing useful. You end up running a headless browser farm to read a table.
  • UK-centric, ~30 books. The comparison is mostly UK high-street books. No sharps (Pinnacle, SBOBet), no exchanges, no crypto books, no US sportsbooks in any depth.
  • No history. You see the price now. You cannot pull where the line opened or how it moved which is exactly what you need to backtest or measure closing line value.

An aggregator API solves all four. You get one authenticated HTTP call, a documented JSON shape, hundreds of books including the sharp ones, and free price history.

  Scraping Oddschecker OddsPapi API
Access method Reverse-engineer a private frontend Documented REST + WebSocket
Bookmakers ~30 (UK retail) 350+ (incl. Pinnacle, SBOBet, exchanges, crypto)
Output format HTML you have to parse Clean JSON
Sharp books No Yes (Pinnacle, SBOBet, Singbet)
Historical odds No Yes, free tier
Real-time push Polling a webpage WebSocket feed
Blocked at scale? Yes (Cloudflare, IP bans) No (API key)

What the Comparison Data Actually Looks Like

Here is a live example. We pulled the Full Time Result market for England vs Ghana at the 2026 World Cup across every bookmaker OddsPapi had on the fixture (18 books, 15 with an active 1X2 price). This is the same grid Oddschecker would show you only you get it as JSON.

Outcome Worst price Best price Best book Pinnacle (sharp) Payout swing
England 1.19 1.339 fourwinds 1.232 +12.5%
Draw 4.80 7.10 bet365 6.58 +47.9%
Ghana 8.50 15.00 betparx 13.61 +76.5%

Look at the Ghana line: 8.50 at the worst book, 15.00 at the best. Same bet, same outcome, a 76% difference in what you get paid. That spread is the entire reason odds comparison exists and it is invisible if you are locked to a single sportsbook or stuck scraping a grid you cannot reliably parse. Pinnacle’s no-vig fair line on this fixture: England 78.3%, Draw 14.7%, Ghana 7.1%, at a 3.71% margin.

Tutorial: Build Your Own Odds Comparison in Python

Four steps: authenticate, find the fixture, pull every book’s price, build the comparison table. All code below is tested against the live API.

Step 1: Authenticate

OddsPapi uses an API key as a query parameter not a header. Grab a free key and confirm it works:

import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.oddspapi.io/v4"

# apiKey is a query param, NOT a header
r = requests.get(f"{BASE_URL}/sports", params={"apiKey": API_KEY})
print(r.status_code)  # 200

Step 2: Find a Fixture

Soccer is sportId=10. Pull fixtures in a date window (max 10 days apart) and keep the ones with hasOdds=true only those return a price payload.

params = {
    "apiKey": API_KEY,
    "sportId": 10,
    "from": "2026-06-23",
    "to": "2026-06-24",
}
fixtures = requests.get(f"{BASE_URL}/fixtures", params=params).json()

for f in fixtures:
    if f.get("hasOdds") and f["tournamentName"] == "World Cup":
        print(f["fixtureId"], f["participant1Name"], "vs", f["participant2Name"])
# id1000001666457046 England vs Ghana

Step 3: Pull Every Bookmaker’s Price

The /odds endpoint returns one fixture across all available books. The response is deeply nested the top key is bookmakerOdds, then markets (by market ID), then outcomes, then players["0"] for the current price. For soccer, market 101 is Full Time Result with outcomes 101 (Home), 102 (Draw), 103 (Away).

FIXTURE_ID = "id1000001666457046"  # England vs Ghana

data = requests.get(f"{BASE_URL}/odds",
                    params={"apiKey": API_KEY, "fixtureId": FIXTURE_ID}).json()

OUTCOMES = {"101": "Home", "102": "Draw", "103": "Away"}
grid = {label: {} for label in OUTCOMES.values()}

for slug, book in data["bookmakerOdds"].items():
    market = book.get("markets", {}).get("101")  # Full Time Result
    if not market:
        continue
    for oid, outcome in market["outcomes"].items():
        player = outcome.get("players", {}).get("0")
        # always filter on active price
        if player and player.get("active") and player.get("price"):
            grid[OUTCOMES[oid]][slug] = player["price"]

print(f"{len(data['bookmakerOdds'])} books on this fixture")

Always filter on active. A book can leave a suspended price in the payload with active=false. If you do not filter, a stale price will win your “best odds” comparison and send you to a market that no longer exists.

Step 4: Build the Comparison Table

Now find the best price per outcome the part Oddschecker charges affiliates to send traffic for:

for outcome, prices in grid.items():
    if not prices:
        continue
    best_book = max(prices, key=prices.get)
    worst = min(prices.values())
    best = prices[best_book]
    swing = (best / worst - 1) * 100
    print(f"{outcome:6} best {best:>6} ({best_book:12}) "
          f"worst {worst:>6}  swing +{swing:.1f}%")

# Home   best  1.339 (fourwinds   ) worst   1.19  swing +12.5%
# Draw   best    7.1 (bet365      ) worst    4.8  swing +47.9%
# Away   best   15.0 (betparx     ) worst    8.5  swing +76.5%

That is the whole product. Twenty lines of Python and you have programmatic odds comparison across hundreds of books no headless browser, no Cloudflare fight, no parsing obfuscated HTML.

Bonus: The Sharp Benchmark Oddschecker Never Shows

Because OddsPapi carries Pinnacle and SBOBet sharp books that move the market first you can de-vig the sharp line and measure whether any soft book is actually offering value, not just a higher number:

pin = {OUTCOMES[o]: grid[OUTCOMES[o]].get("pinnacle")
       for o in OUTCOMES}

if all(pin.values()):
    overround = sum(1 / p for p in pin.values())
    vig = (overround - 1) * 100
    print(f"Pinnacle margin: {vig:.2f}%")
    for outcome, price in pin.items():
        fair_prob = (1 / price) / overround
        print(f"  {outcome:6} fair {fair_prob*100:5.1f}%  "
              f"fair odds {1/fair_prob:.3f}")

# Pinnacle margin: 3.71%
#   Home   fair  78.3%  fair odds 1.277
#   Draw   fair  14.7%  fair odds 6.821
#   Away   fair   7.1%  fair odds 14.123

Oddschecker can tell you bet365 has 7.1 on the draw. It cannot tell you Pinnacle’s fair line is 6.82 so the 7.1 is a genuine +EV price, not just a marketing number. That is the difference between an affiliate grid and a real data feed.

Free Historical Odds (Another Thing Oddschecker Can’t Give You)

Need to see how a line opened and moved? The /historical-odds endpoint returns the full price history per outcome free on the developer tier. The shape differs from live odds: the top key is bookmakers (not bookmakerOdds) and players["0"] is a list of snapshots, max 3 books per call.

hist = requests.get(f"{BASE_URL}/historical-odds", params={
    "apiKey": API_KEY,
    "fixtureId": FIXTURE_ID,
    "bookmakers": "pinnacle,bet365,sbobet",  # max 3
}).json()

book = hist["bookmakers"]["pinnacle"]["markets"]["101"]
for snap in book["outcomes"]["101"]["players"]["0"]:
    print(snap["createdAt"], snap["price"])

That is what powers closing-line-value analysis and model backtesting and it is the data Oddschecker’s affiliate model has no reason to ever expose.

When to Use Which

If you are a bettor who wants to eyeball today’s best price, Oddschecker (or a player-prop screener like jedibets for props with Discord alerts) is fine. If you are building anything an alert bot, a value scanner, a dashboard, a model you need a structured feed, not a webpage. That is where an API-first aggregator wins.

FAQ

Does Oddschecker have a public API?

No. Oddschecker does not offer a public, documented API or developer key. It is an affiliate odds-comparison site, and its data is only available through the website. To get comparison data programmatically you need an aggregator like OddsPapi that exposes a REST and WebSocket feed.

Can I legally scrape Oddschecker?

Scraping Oddschecker violates its terms of service, and the site uses anti-bot protection (Cloudflare, JS-rendered prices, rotating markup) that blocks automated access. A licensed odds API is the reliable, terms-compliant way to get the same data.

How many bookmakers does OddsPapi compare versus Oddschecker?

OddsPapi aggregates 350+ bookmakers including sharp books (Pinnacle, SBOBet), exchanges, and crypto sportsbooks. Oddschecker tracks roughly 30, mostly UK high-street books, with no sharp or exchange depth.

Is the odds comparison data free?

Yes. OddsPapi has a free developer tier that includes live odds across hundreds of books and free historical odds for backtesting. The API key is passed as a query parameter, not a header.

What format is the odds data returned in?

Clean JSON. Each price is pre-converted to decimal, American, and fractional formats, so you do not need to write your own odds converter.

Stop Scraping. Get the Feed.

You do not need a headless browser farm to read an odds table. Get your free OddsPapi API key and pull comparison data across 350+ bookmakers as JSON in your next request.