Prediction Market Odds Scraper (Polymarket & Kalshi)
Pricing
from $1.00 / 1,000 market scrapeds
Prediction Market Odds Scraper (Polymarket & Kalshi)
Scrape Polymarket and Kalshi prediction market odds: 0-1 prices, implied probability, bid/ask, volume, liquidity and orderbook depth. No login. Pay per market.
Pricing
from $1.00 / 1,000 market scrapeds
Rating
0.0
(0)
Developer
Romas Jurevicius
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
10 days ago
Last modified
Share
Prediction Market Odds Scraper (Polymarket & Kalshi)
Prediction Market Odds turns the two largest prediction exchanges into one clean, machine-readable feed. It returns one JSON record per market - "Fed cut in December?", "Bitcoin above $110k on October 11?", "Who will be the next NATO Secretary General?", sports and esports matchups - with every price normalized to a 0-1 probability (0.0565 = 5.65%), the implied probability in percent, the best bid and ask, the last trade, lifetime and 24-hour volume, resting liquidity, open interest, the close date, the resolution rules and the exchange's own URL. Polymarket and Kalshi rows have the same shape, so a Kalshi contract at 6 cents and a Polymarket share at $0.06 compare directly. No account, API key or login is needed: both exchanges publish this data through official public endpoints.
Typical uses: feeding an AI trading agent that cross-references macro odds (rate decisions, CPI prints, elections) before placing trades, scanning for price disagreements between Polymarket and Kalshi on the same question, tracking a watchlist of markets every few minutes into a database, alerting a Telegram or Slack channel when a probability crosses a threshold, or backfilling a research dataset of resolved markets with their final prices.
Two sources are supported and can be combined in one run:
polymarket- the Gamma API (gamma-api.polymarket.com) for events, markets and tags, plus the CLOB API (clob.polymarket.com) for orderbooks. Prices are USDC per share, already 0-1.kalshi- the trade API v2 (api.elections.kalshi.com/trade-api/v2) for events, markets and orderbooks. Prices are published in dollars per $1 contract and arrive as 0-1 floats; legacy integer-cent fields are converted too.
How to scrape prediction market odds
- Open the Actor in Apify Console and click Try for free.
- Pick the Sources (default: both) and the Market status (default:
active, i.e. tradeable now;closedadds resolved and settled markets;allfor both). - Narrow the output with Search (
bitcoin,fed rate,nato), Polymarket tags (crypto,politics,fed) or Kalshi series tickers (KXBTCD,KXFED,KXCPI). Filtering happens before anything is charged. - Set Max markets per source (default 30) and turn on Include orderbook if you need depth beyond the top of book.
- Click Start. Results appear in the Output tab within seconds and can be downloaded as JSON, CSV or Excel, or read through the API.
How the fetching works
For Polymarket the Actor lists events with their nested markets from GET /events (100 per page - the API caps limit there - ordered by 24-hour volume for active markets and by end date for closed ones), optionally one request series per tag slug, and pages with offset until the cap or the end of the list. Each nested market carries its outcomes, quoted prices, best bid/ask, last trade, volume and liquidity, so no second request is needed per market. With Include orderbook on, the CLOB POST /books endpoint is called with batches of 20 token ids, and the best bid/ask are refreshed from the live book.
For Kalshi, active and closed markets come from GET /events?with_nested_markets=true (200 events per page, with category and settlement sources), paged with the API's cursor; settled markets come from GET /markets?status=settled (1,000 per page) because the events listing does not nest markets once an event has settled. Multivariate "parlay" combinations (mve_collection_ticker) are skipped: they carry no odds of their own. Each market's quote is read from yes_bid/yes_ask/no_bid/no_ask; the orderbook endpoint is called once per market when Include orderbook is on.
Requests are serialized with a 250 ms gap and retried on network errors, 429 and 5xx responses. Markets are pushed most-traded first, and every market id is remembered in the run state so a migrated or resurrected run never charges the same market twice.
Prediction Market Odds Scraper pricing
This Actor uses Apify's pay-per-event model. There is no subscription and no per-result platform fee on top:
- Actor start: a flat fee of $0.00005 per run.
- Market scraped: $0.001 per market pushed to your dataset ($1 per 1,000 markets).
- Orderbook fetched: $0.0005 per market whose orderbook was fetched (only with Include orderbook on, and only when the exchange returned a book).
Search, status, tag and series filters are free and applied before charging - a run for search: "fed" on both exchanges is typically 20-60 markets, well under $0.10. Status records for a source that was unavailable or returned nothing are free. You can cap spending with Maximum cost per run; when the cap is reached the Actor stops cleanly and keeps everything scraped so far.
Input example
{"sources": ["polymarket", "kalshi"],"status": "active","search": "bitcoin","tags": ["crypto"],"seriesTickers": ["KXBTCD"],"maxMarketsPerSource": 200,"includeOrderbook": false,"proxyConfiguration": { "useApifyProxy": true }}
Input fields
| Field | Type | Default | Description |
|---|---|---|---|
sources | array of polymarket / kalshi | both | Which exchanges to read. Each record carries its source. |
status | active / closed / all | active | active = tradeable now; closed = trading ended, including resolved/settled; all = both. |
search | string | none | Case-insensitive filter on question, event title, slug, ticker and event/series ticker. All words must appear. |
tags | array of strings | none | Polymarket only: event tag slugs such as crypto, politics, fed, bitcoin, sports. One request series per tag. |
seriesTickers | array of strings | none | Kalshi only: series such as KXBTCD, KXFED, KXCPI, KXNEXTNATOSECGEN. |
maxMarketsPerSource | integer | 30 | Stop a source once this many markets matched the filters (max 20,000). |
includeOrderbook | boolean | false | Fetch live books: top 10 levels per outcome, depth, resting dollars; refreshes best bid/ask. |
proxyConfiguration | object | Apify Proxy | Standard Apify proxy settings. |
Output example
One dataset item per market (Kalshi example, captured 2026-10-11):
{"source": "kalshi","marketId": "KXNEWPOPE-70-LANT","eventId": "KXNEWPOPE-70","eventTitle": "Who will the next Pope be?","question": "Who will the next Pope be? (Luis Antonio Tagle)","slug": null,"ticker": "KXNEWPOPE-70-LANT","seriesTicker": "KXNEWPOPE","url": "https://kalshi.com/markets/kxnewpope/who-will-the-next-pope-be/kxnewpope-70","outcomes": [{ "name": "Yes", "price": 0.0565, "impliedProbabilityPct": 5.65, "bestBid": 0.041, "bestAsk": 0.072, "tokenId": null },{ "name": "No", "price": 0.9435, "impliedProbabilityPct": 94.35, "bestBid": 0.928, "bestAsk": 0.959, "tokenId": null }],"isBinary": true,"yesPrice": 0.0565,"noPrice": 0.9435,"lastTradePrice": 0.04,"spread": 0.031,"volumeUsd": 21292.58,"volume24hUsd": 1376.83,"volumeContracts": 21292.58,"volume24hContracts": 1376.83,"liquidityUsd": null,"openInterest": 4703.57,"status": "active","sourceStatus": "active","resolvedOutcome": null,"createdAt": "2025-07-18T08:05:49.322Z","endDate": "2070-01-01T15:00:00.000Z","resolutionSource": "The New York Times; the Associated Press; Reuters; Axios; Politico; ...","description": "If Luis Antonio Tagle becomes the first person elected Pope before Jan 1, 2070, then the market resolves to Yes.","category": "Elections","tags": [],"orderbookFetched": false,"scrapedAt": "2026-10-11T05:49:05.178Z"}
A Polymarket record has the same keys: marketId is the Gamma market id, eventId the Gamma event id, slug the URL slug, ticker/seriesTicker are null, each outcome carries its CLOB tokenId, tags holds the event's tag slugs (["bitcoin", "crypto", "weekly"]) and category is null.
Field notes:
- Prices are 0-1 everywhere.
outcomes[].priceis the exchange's quoted price: Polymarket'soutcomePrices, or on Kalshi the midpoint of the Yes book with 0 / 1 standing in for an empty side (the same convention Polymarket uses).impliedProbabilityPctisprice x 100.bestBid/bestAskarenullwhen that side of the book is empty - the Actor never invents a quote. yesPrice/noPriceare filled only for Yes/No questions. Polymarket matchups with team names as outcomes (["MOUZ", "Spirit"]) keep themnull; readoutcomesinstead.isBinaryistruefor any two-outcome market.statusis normalized:active(tradeable),closed(trading ended, not yet resolved),resolved(settled;resolvedOutcomenames the winner and the winning outcome's price is1),upcoming(listed, not yet open).sourceStatuskeeps the exchange's own label (finalized,determined,closed/resolved, ...).- Volume. Polymarket reports USDC traded. Kalshi reports contract counts;
volumeUsd/volume24hUsdare those counts times the $1 notional per contract (the raw counts stay involumeContracts/volume24hContracts). Treat Kalshi's figure as notional, not dollars that changed hands. liquidityUsdis Polymarket's resting liquidity figure. Kalshi does not publish one in the listing, so it isnullunless Include orderbook is on, in which case it is the dollars resting on both sides of the fetched book (Yes bids payp, No bids pay1 - p).openInterestis Kalshi's open contracts; Polymarket publishes open interest only per event, so it isnullthere.- With Include orderbook on, each outcome gets
orderbook: { bids, asks, bidDepth, askDepth, restingUsd }with up to 10 levels per side, best first, prices in 0-1 and sizes in shares (Polymarket) or contracts (Kalshi). On Kalshi the asks of Yes are the mirrored No bids (1 - price) and vice versa, which is exactly how the exchange matches orders.orderbookFetchedtells you whether the book came back; only those markets are charged the orderbook event. urlis the market page. Kalshi pages have the formkalshi.com/markets/{series}/{slug}/{event}; the middle segment is cosmetic and the Actor builds it from the event title.resolutionSourceis Polymarket's resolution source text, or Kalshi's settlement sources joined with;.descriptionholds Polymarket's resolution text or Kalshi's primary rules.
A source that could not be read produces a single free record with status: "unavailable" (or "empty") and a message containing the HTTP status and a body snippet, so your pipeline can tell "no markets" from "exchange down".
Integrations
- API: start runs and read results with the Apify API or the JavaScript and Python clients. Run the Actor synchronously with
run-sync-get-dataset-itemsto get a fresh odds snapshot in one call. - MCP / AI trading agents: the Actor is exposed through the Apify MCP server at
https://mcp.apify.com. Add it to Claude Desktop, Claude Code, Cursor, ChatGPT or any MCP-capable trading agent, enable this Actor as a tool, and the agent can call it with the same input - for example{"search": "fed", "status": "active"}before an FOMC decision, or{"seriesTickers": ["KXBTCD"], "includeOrderbook": true}to read the Bitcoin strike ladder with depth. Because prices are already probabilities, the agent can compare them with its own model or with the other exchange without any unit conversion. No custom MCP server is needed; the Actor's input schema becomes the tool schema. - n8n and Make: use the Apify node or module, pick this Actor, pass the input JSON above and map the dataset items into your workflow.
- Schedules and webhooks: run it every few minutes from Apify Schedules and let a webhook push the snapshot to Slack, Telegram, Google Sheets, Postgres or your trading system.
Sources and limitations
Polymarket (polymarket). Read from the public Gamma and CLOB APIs. Verified on 2026-10-11: GET /events?active=true&closed=false&limit=100 returned 100 events with 1,242 nested markets, tag_slug=crypto worked, POST /books returned full books, and limit values above 100 were silently capped at 100. Gamma's /markets endpoint does not carry tags, which is why the Actor lists through /events. Polymarket markets are always two-outcome (multi-choice questions are events with one market per choice), so isBinary is always true there. openInterest is not published per market. The quoted outcomePrices can lag the live book by a few seconds; turn on Include orderbook when you need the exact top of book.
Kalshi (kalshi). Read from the public trade API v2, which serves market data without authentication (trading endpoints need keys and are not used). Verified on 2026-10-11: /events?status=open&with_nested_markets=true&limit=200 returned 200 events with 1,821 markets, series_ticker=KXBTCD returned 318 open strike markets, /markets/{ticker}/orderbook returned orderbook_fp levels, and /events?status=settled returned events without nested markets (hence the /markets?status=settled path). The exchange lists markets in its own order, not by activity, so a small maxMarketsPerSource without filters returns whatever Kalshi lists first; use seriesTickers or search to target what you need. Settled markets fetched from /markets have no event metadata: category is null and eventTitle falls back to the market title. Multivariate parlay legs are excluded. Kalshi's public rate limit is generous for this volume; the Actor still spaces requests 250 ms apart.
Both exchanges publish live data that changes by the second; scrapedAt tells you when the record was taken. Prices on illiquid markets (wide spreads, zero 24-hour volume) are quotes, not fair values - check spread, volume24hUsd and liquidityUsd before acting on them.
Prediction Market Odds Scraper FAQ
How do I compare the same question across both exchanges?
Run with search set to the topic ("fed december", "bitcoin 100k") and both sources on. Prices are 0-1 on both, so the difference between yesPrice values is the raw edge before fees and slippage.
Why is yesPrice null on some Polymarket markets?
Those markets name their outcomes (["Texas", "Oklahoma"]) rather than Yes/No. The prices are in outcomes; yesPrice is only filled when the outcomes are literally Yes and No so it always means the same thing.
Can I get resolved markets with their final prices?
Yes - set status: "closed". Resolved markets carry status: "resolved", resolvedOutcome and a winning price of 1.
How much does a full snapshot cost?
At the default 30 markets per source, a run of both exchanges is 60 markets, i.e. $0.06, plus $0.03 if orderbooks are on. At 200 markets per source it is 400 markets, i.e. $0.40, plus $0.20 with orderbooks.
What happens if an exchange is down?
The run still succeeds with the other source, and a free unavailable record explains what failed (HTTP status and body snippet). Nothing is faked.
Related actors
Same author, same pay-per-event model and the same no-login approach. They combine well in one pipeline (for example calendar events plus prediction odds plus channel chatter around a release):
- Telegram Channel Scraper - posts, views, media and links from public Telegram channels, no login.
- Substack Scraper - posts, authors, likes, restacks and comments from public Substack publications, custom domains included.
- Economic Calendar Scraper - Forex Factory and Investing.com macro events with UTC times, impact, actual, forecast and previous values.
- Product Hunt Scraper - daily, weekly and monthly leaderboards, topic pages, search and product launches with votes, makers and website URLs.
Legal and compliance
This Actor only reads public, unauthenticated API endpoints that both exchanges document for market data, and it never places orders or touches account endpoints. Market prices are public facts, but each exchange's presentation and API are subject to its own terms: see Polymarket's terms of use and Kalshi's terms. You are responsible for using the data in line with those terms and applicable law, including any restrictions on redistribution and on trading from your jurisdiction. Keep request rates low (the Actor already serializes requests with a delay) and read Apify's article on the legality of web scraping if you are unsure. Nothing here is investment advice.
Support
Found a market that normalizes wrongly, a missing field, or need another exchange (Manifold, PredictIt, Metaculus)? Open an issue on the Actor's Issues tab in Apify Console or contact the author through the Actor page. Reports that include the input JSON and the market id or ticker are usually fixed within days.