Sports Projections

Building a Real-Time World Cup Prediction Dashboard: Polymarket API + Python + Live Odds

Every line of code in this article was executed against the live Polymarket API while writing it, and every number you see in the output blocks is real market data from the World Cup 2026 winner market.

Ezekiel Njuguna
Ezekiel NjugunaEditor-in-Chief
May 28, 202512 min read
Building a Real-Time World Cup Prediction Dashboard: Polymarket API + Python + Live Odds

The Polymarket World Cup Winner market has processed $1.96 billion in trading volume, which makes it the largest prediction market event ever run. Forty-eight national teams, each with its own order book, each repricing continuously as money flows in. Spain trades at 16.95 cents. France sits at 16.05. England and Portugal are deadlocked at 10.85. These numbers move every few seconds, and if you are watching them through Polymarket’s web interface, you are seeing one market at a time through a UI built for clicking buttons, not for analysis.

This tutorial fixes that. You will build a real-time World Cup prediction dashboard in Python that pulls live odds from the Polymarket API, converts contract prices into proper probabilities, visualizes probability shifts over time, inspects order book depth before you trade, and runs an arbitrage scanner across all 48 outcomes. Every line of code in this article was executed against the live Polymarket API while writing it, and every number you see in the output blocks is real market data from the World Cup 2026 winner market.

You need intermediate Python and nothing else. No Polymarket account, no API key, no wallet. Reading market data from Polymarket is completely unauthenticated. You only need credentials when you start placing orders, and this article stops one step short of that line on purpose. A dashboard that helps you see the market clearly is worth more than a bot that trades it blindly.

Here is the full build, in seven steps:

  • Pull all 48 World Cup markets through the Gamma API

  • Convert prices to implied probabilities and strip the overround

  • Read order book depth through the CLOB API and compute real execution prices

  • Chart probability shifts with historical price data

  • Build an arbitrage scanner, then learn why naive scanners lie to you

  • Upgrade from polling to a live WebSocket feed

  • Assemble everything into a Streamlit dashboard

The Two Polymarket APIs You Need to Understand

Polymarket exposes its data through two separate public APIs, and most tutorials blur them together. Keeping them straight will save you hours.

The Gamma API (https://gamma-api.polymarket.com) is the metadata and discovery layer. It knows about events, markets, slugs, volumes, current prices, and descriptions. When you want to answer “what World Cup markets exist and what are they trading at right now,” Gamma is your endpoint. It is a plain REST API that returns JSON, no authentication required.

The CLOB API (https://clob.polymarket.com) is the trading engine’s data interface. CLOB stands for central limit order book, the same matching architecture used by stock exchanges and crypto exchanges. This API gives you the actual order book for any outcome token: every resting bid and ask, with price and size. It also serves midpoints, spreads, and historical price series. When you want to answer “what would it actually cost me to buy $100,000 of Spain right now,” only the CLOB API can tell you.

The connecting tissue between the two is the token ID. Every market on Polymarket has two outcome tokens, YES and NO, each identified by a long numeric string. The Gamma API hands you these token IDs in a field called clobTokenIds, and you pass them to the CLOB API to get books and price history. That handoff is the spine of everything we build below.

One more concept before code. Polymarket prices live between $0.00 and $1.00. A YES share pays out $1.00 if the outcome happens and $0.00 if it does not. So a price of $0.1695 for Spain means the market collectively assigns Spain a 16.95% chance of lifting the trophy. Price equals probability, which is what makes prediction market data so clean to work with compared to bookmaker odds formats.

Project Setup

Create a project directory and install four packages:

That is the whole dependency list. requests handles the REST calls, pandas structures the data, plotly draws the charts, streamlit serves the dashboard, and websockets powers the real-time feed in step 6.

Step 1: Pulling All 48 World Cup Markets from the Gamma API

The World Cup Winner market lives at event ID 30615 on Polymarket. You can find any event’s ID by searching the Gamma events endpoint, but for a tutorial we can hardcode it:

A few details worth flagging. The outcomePrices and clobTokenIds fields arrive as JSON strings inside the JSON response, so you have to parse them a second time with json.loads. This trips up almost everyone on first contact with the Gamma API. The groupItemTitle field gives you the clean team name (“Spain”) instead of the full market question (“Will Spain win the 2026 FIFA World Cup?”), which matters once you are rendering 48 rows in a dashboard table.

Running this against the live API returns 48 active markets. Here are the top twelve by price, exactly as returned during this build:

One Gamma call, every World Cup market, sub-second response. Notice the volume column: even Colombia at 1.85 cents has pushed $40 million through its book. Liquidity at this depth is what separates the World Cup market from the average prediction market, and it is why the analysis in the rest of this tutorial produces numbers you can actually trade against.

Step 2: Implied Probability and the Overround

Prices map to probabilities, but the raw prices across a mutually exclusive market never sum to exactly 1.00. Only one team can win the World Cup, so in a mathematically fair market the 48 probabilities would total 100%. Sum the live prices and you get:

The live World Cup market carries a 4.30% overround. That excess is the cushion market makers collect for providing liquidity, structurally identical to the vig a sportsbook builds into its lines, except here it emerges from spread dynamics rather than being set by a bookmaker.

The fix is simple normalization: divide each price by the total. Spain’s raw implied probability of 16.95% deflates to a fair probability of 16.25%. France drops from 16.05% to 15.39%. Small differences per team, but they compound. If you are comparing Polymarket probabilities against your own model, or against Kalshi, or against bookmaker lines, you must compare de-vigged numbers to de-vigged numbers. Comparing a raw Polymarket price against a normalized model output will manufacture phantom edges that disappear the moment you trade them.

Your dashboard should display both columns. Raw price is what you transact at. Fair probability is what you reason with.

Step 3: Order Book Depth and the True Cost of Size

The Gamma API tells you the last price. It does not tell you what your order would actually fill at. For that you need the CLOB API’s book endpoint, keyed by the token ID you collected in step 1:

Spain’s live book at the time of this build:

Nearly half a million shares resting at the top bid and even more at the ask. The bid-ask spread is a single tick. This is institutional-grade depth.

But depth at the top of the book only protects orders that fit inside it. To know what a larger order costs, walk the book level by level and compute the volume-weighted fill price:

Running this against Spain’s live ask side:

Read that last line again. A $100,000 market buy fills at the top ask with zero slippage, because 568,000 shares at 0.170 absorbs it whole. Push to $250,000 and the average fill jumps to 24.11 cents, a 42% premium over the screen price, because the order chews through the entire first level and starts climbing a much thinner upper book.

This single function is the difference between a dashboard that displays prices and a dashboard with trading utility. Screen price is an advertisement. Executable price is reality. Your dashboard should compute executable prices at two or three reference sizes for every market you care about, and the gap between the $10k fill and the $250k fill tells you instantly how much real liquidity sits behind a quote.

Step 4: Charting Probability Shifts with Historical Prices

A snapshot tells you where the market is. A time series tells you where the money has been moving. The CLOB API serves historical prices through the prices-history endpoint:

The interval parameter accepts values like 1d, 1w, 1m, and max. The fidelity parameter sets resolution in minutes, so fidelity=360 returns six-hour candles. Pulling one month of history for the five most traded teams produces this picture, again from the live API:

There is a real story in those five lines. A month ago France was the tournament favorite at 17.7 cents with Spain trailing at 16.1. The two lines have fully crossed. Argentina has quietly gained 8% while England bled. None of this is visible on Polymarket’s front end, which shows you current prices and a single market’s chart at a time. A dashboard that overlays the contenders on one axis surfaces rotation between teams the moment it starts.

Plotting is a few lines of Plotly:

Multiply by 100 so the y-axis reads as percentages. The hovermode=”x unified” setting puts all five teams in one hover tooltip, which is what you want when scrubbing the chart for the exact day France and Spain crossed.

Step 5: The Arbitrage Scanner, and the Trap Inside It

Here is where the dashboard earns its keep for traders. A mutually exclusive multi-outcome market has two structural arbitrage conditions, and both reduce to simple sums.

The long arbitrage: if you can buy YES on all 48 teams for a combined cost under $1.00, you lock in profit, because exactly one of those positions must resolve to $1.00. Sum the best asks; if the total is below 1.00, the arb exists.

The short arbitrage runs the other way: if you can sell YES on all 48 teams for combined proceeds above $1.00, you collect more premium than the single winning contract will cost you at resolution. Sum the best bids; if the total exceeds 1.00, the arb exists.

Running the scanner on live World Cup data:

The scanner flags a live short arbitrage: 1.9 cents of riskless profit per set, on the most liquid prediction market ever to exist. Sell one full set of 48 YES contracts, collect $1.019, pay out $1.00 when one team wins, keep $0.019. Scale it to 100,000 sets and that is $1,900 of free money, repeatable.

Before you wire up a wallet, extend the scanner one level deeper. Top-of-book prices are not enough. You also need top-of-book sizes, because an arb you cannot fill on every leg simultaneously is not an arb. Pull the full order book for all 48 outcomes and check the depth behind each bid:

Live output:

The arbitrage evaporates. Curaçao, Jordan, New Zealand, Haiti, and Uzbekistan have no resting bids at all. Nobody is willing to pay even a tenth of a cent for the YES side of a 500-to-1 longshot, so five of the 48 legs cannot be sold at any price. The short arb requires selling all 48 legs. Executable capacity: zero sets. Riskless profit: zero dollars.

This is the most important lesson in the entire tutorial, and it is why the depth function from step 3 belongs at the heart of your scanner. A naive arbitrage scanner built on top-of-book prices alone will flag opportunities all day long, and every one of them will fail at execution on the thin legs. The market is not leaving $1,900 per hundred thousand sets on the table. It only looks that way from the price layer. Professional arb desks burn most of their engineering effort on exactly this problem, and your dashboard should display arb signals with their executable capacity attached or it will train you to chase ghosts.

Partial arbitrage across subsets is where the real hunting happens. The condition “sell every leg” can be relaxed: if the top 20 teams’ bids sum close to 1.00 on their own, shorting just those legs leaves you exposed only to a longshot winning, a risk you might price at a fraction of a cent. Add a subset scanner as an exercise. The scaffolding above already gives you everything you need.

Step 6: Going Real-Time with the Polymarket WebSocket

Polling the REST APIs every few seconds works, and for a personal dashboard it is honestly fine. But Polymarket also runs a public WebSocket feed that pushes order book changes to you the moment they happen, and upgrading to it removes both the polling lag and the rate-limit pressure.

The market channel lives at wss://ws-subscriptions-clob.polymarket.com/ws/market. You connect, send one subscription message listing the token IDs you care about, and the server streams events:

Two event types matter. On connection you receive a book event per token, a full snapshot of bids and asks identical in shape to the REST book endpoint. After that you receive price_change events carrying only the levels that moved. Verified live during this build:

The standard pattern is to hold the snapshot in a dict keyed by price level and apply each price_change as a patch. Your arbitrage scanner then re-runs on every patch instead of every poll cycle, which means you evaluate the arb condition within milliseconds of any book change across all 48 outcomes. If a real dislocation ever does appear in this market, it will live for seconds at most. WebSocket-driven scanning is the only architecture that gives you a chance at it.

One practical caution: the subscription message takes the token IDs under the key assets_ids (with the s in the middle), an awkward spelling that has cost many developers a confused half hour against a silent connection.

Step 7: Assembling the Streamlit Dashboard

Everything so far is a data layer in a single file, call it dashboard_core.py. Streamlit turns it into a served, auto-refreshing dashboard with under 50 lines:

Run it with streamlit run app.py and open localhost:8501. The @st.cache_data(ttl=30) decorator is doing quiet but important work: it caches the Gamma pull for 30 seconds so that every widget interaction does not re-hit the API, while still refreshing twice a minute. For faster updates, drop the TTL or swap the data layer onto the WebSocket feed from step 6 with a background thread writing into st.session_state.

The result is a single screen showing live prices and fair probabilities for all 48 teams, a 30-day probability shift chart for any set of contenders, the arb check with its warning to verify depth, and executable price ladders for any book you select. That last panel alone puts you ahead of anyone trading off the Polymarket front end.

Extending the Dashboard

The build above is a foundation, and several extensions are obvious next moves.

Cross-platform comparison is the highest-value addition. Kalshi runs its own World Cup markets under CFTC regulation, with its own REST API. Pull both platforms into one normalized table and you can scan for cross-venue divergence, which historically runs wider and lasts longer than anything within a single venue, because capital cannot move instantly between a crypto-settled orderbook and a regulated US exchange.

Alerting turns the dashboard from a screen you watch into a system that watches for you. Wrap the scanner in a loop that fires a Telegram or Discord webhook when any team moves more than two cents in an hour, when the overround compresses below 3%, or when executable depth at the top of any major book drops below a threshold you set. During the group stage, when 48 books reprice on every goal, alerts are the only realistic way to keep up.

Match-level markets multiply the surface area. Everything in this tutorial targets the tournament winner market, but Polymarket lists group winners, group runners-up, and individual fixtures. The code is identical; only the event ID changes. Group-stage markets are thinner and slower to reprice than the headline market, which makes them the more plausible home for genuine mispricings.

Rate limits deserve respect. The public endpoints tolerate the request volumes in this tutorial without complaint, and the 48-book depth scan completes in under six seconds with sequential requests. If you parallelize aggressively, back off on 429 responses and cache anything that has not changed. The WebSocket feed exists precisely so that high-frequency consumers stay off the REST endpoints.

What You Built

You now have a working real-time prediction market dashboard: live World Cup 2026 odds from the Polymarket Gamma API, fair probabilities with the 4.30% overround stripped out, order book depth and true executable prices from the CLOB API, 30-day probability shift charts that caught the France-to-Spain favorite rotation, an arbitrage scanner honest enough to tell you when its own signal is unfillable, and a WebSocket upgrade path for millisecond reaction times.

The deeper takeaway is about the data itself. The $1.96 billion World Cup market is the best free real-time probability feed in sports, and almost everyone consumes it through a web page built for retail clicking. A few hundred lines of Python against two public APIs gives you a strictly better view than the platform’s own interface, plus the execution math the interface will never show you. The tournament runs through July 2026. Plenty of time to point this dashboard at it.

#polymarket#kalshi#forecasting
Share:
Ezekiel Njuguna
Ezekiel Njuguna

Editor-in-Chief

Senior content writer at the intersection of AI, finance, and digital media. Produces data-driven analysis across prediction markets, cryptocurrency trading, and forecasting methodology. His work pulls live API data and stress-tests real workflows rather than summarizing press releases.

Newsletter

The Weekly Signal

Every Friday — the week's sharpest prediction market analysis, forecasting insights, and data-driven commentary. No noise.

Disclaimer: This content is for informational and educational purposes only. It does not constitute financial advice, investment recommendations, or trading guidance. Prediction market participation involves risk of loss. Always conduct your own research before making any financial decisions.

Read Next