Prediction Market Odds Scraper – Kalshi + Polymarket
Pricing
from $1.50 / 1,000 markets
Prediction Market Odds Scraper – Kalshi + Polymarket
Kalshi and Polymarket prediction markets in one call and one schema: YES probability, bid/ask, spread, volume, liquidity, close time, category and optional order books. Search, filter, sort. Clean JSON for traders, researchers and AI agents.
Pricing
from $1.50 / 1,000 markets
Rating
0.0
(0)
Developer
Rowfeed
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Get Kalshi and Polymarket prediction-market odds in one call and one schema: every market's YES probability, bid and ask, spread, lifetime and 24 h volume, liquidity, close time, category and, on request, the live order book, with a platform column so rows from both exchanges sit side by side.
Built for traders comparing venues, researchers building cross-platform datasets, AI agents that need one tool for "what are the odds on X" and dashboards that track both exchanges without maintaining two integrations.
Plain HTTPS calls to Kalshi's and Polymarket's public APIs with retries and a silent-failure check; one exchange having a bad day never stops the other.
What you get
- One row per market, same columns on both exchanges –
platform, id, title, page link,yes_prob(0–1), YES/NO bid and ask, spread,volume_usd,volume_24h_usd,liquidity_usd, open interest, ISO close time, status, category, both outcomes with prices, the parent event and the scrape timestamp. Compare a Fed-decision market on Kalshi against its Polymarket twin without translating field names. - Order books on demand – the top N price levels on the YES and the NO side as
[price, size]pairs from Kalshi's order book endpoint and Polymarket's CLOB, read at the same moment as the row. - Filters that work the same everywhere – a search term, a status (active, closed, all), a minimum volume, a sort order (24 h volume, volume, liquidity, close time) and a per-platform row cap, so a scheduled run costs the same every time.
Sample rows
Two rows from one run with includeOrderbook: true and orderbookDepth: 3, one per platform.
{"platform": "kalshi","market_id": "KXAAAGASD-26SEP10-4.2400","ticker_or_slug": "KXAAAGASD-26SEP10-4.2400","title": "Will average **gas prices** be above $4.2400?","url": "https://kalshi.com/markets/kxaaagasd","yes_prob": 0.99,"yes_bid": 0.98,"yes_ask": 1.0,"no_bid": 0.0,"no_ask": 0.02,"spread": 0.02,"volume_usd": 8568.64,"volume_24h_usd": 8568.64,"liquidity_usd": 0.0,"open_interest": 8094.64,"close_time": "2026-09-10T03:59:00Z","status": "active","category": "Economics","outcomes": [{ "name": "Yes", "price": 0.99 }, { "name": "No", "price": 0.01 }],"source_event": "KXAAAGASD-26SEP10","scraped_at": "2026-09-09T15:21:16+00:00","orderbook": { "yes": [[0.96, 18.91], [0.97, 872.34], [0.98, 2000.0]], "no": [] }}
{"platform": "polymarket","market_id": "2252244","ticker_or_slug": "will-there-be-no-change-in-fed-interest-rates-after-the-september-2026-meeting-615","title": "Will there be no change in Fed interest rates after the September 2026 meeting?","url": "https://polymarket.com/event/fed-decision-in-september-762/will-there-be-no-change-in-fed-interest-rates-after-the-september-2026-meeting-615","yes_prob": 0.465,"yes_bid": 0.46,"yes_ask": 0.47,"no_bid": 0.53,"no_ask": 0.54,"spread": 0.01,"volume_usd": 25074718.13,"volume_24h_usd": 690706.29,"liquidity_usd": 408917.26,"open_interest": null,"close_time": "2026-09-16T00:00:00Z","status": "active","category": "Politics","outcomes": [{ "name": "Yes", "price": 0.465 }, { "name": "No", "price": 0.535 }],"source_event": "fed-decision-in-september-762","scraped_at": "2026-09-09T15:21:16+00:00","orderbook": {"yes": [[0.44, 47928.09], [0.45, 28019.27], [0.46, 41567.22]],"no": [[0.51, 90932.08], [0.52, 100092.28], [0.53, 129408.82]]}}
How the columns map
| Unified column | Kalshi | Polymarket |
|---|---|---|
market_id, ticker_or_slug | market ticker | Gamma market id, market slug |
title | title | question |
url | kalshi.com/markets/<series> | polymarket.com/event/<event>/<market> |
yes_prob | last trade price in dollars (0 until the first trade; use bid/ask then) | price of the first outcome (the YES side, or the first named side on sports markets) |
yes_bid, yes_ask | yes_bid_dollars, yes_ask_dollars | bestBid, bestAsk |
no_bid, no_ask | no_bid_dollars, no_ask_dollars | 1 - bestAsk, 1 - bestBid |
spread | yes_ask - yes_bid | spread |
volume_usd, volume_24h_usd | contracts traded (each settles at $1) | USD |
liquidity_usd | liquidity_dollars | liquidityNum |
open_interest | open contracts | null |
close_time | close_time | endDate |
status | active / closed / resolved (settled) | active / closed / resolved (an outcome priced 1) |
category | series category (Sports, Politics, Economics, Climate and Weather…) | top-level event tag (Politics, Sports, Crypto, Geopolitics…) |
outcomes | Yes / No from the last price | both outcome names and prices |
source_event | event ticker | event slug |
orderbook.yes / .no | YES bids / NO bids, best level last | YES bids / NO bids (mirrored from the CLOB asks), best level last |
Rows carry the unified columns only. If you need every raw field of one exchange (rules text, sub-titles, strike values, token ids, tags), use the single-platform Kalshi Markets Scraper or Polymarket Markets Scraper.
Filters
| Input | Default | What it does |
|---|---|---|
platforms | ["kalshi", "polymarket"] | Which exchanges to scrape. Each is scraped independently with the same settings. |
searchTerm | "" | Keep only markets whose title contains this text (case-insensitive). On Kalshi the ticker is searched too, so NFL finds the KXNFLGAME markets. |
status | active | active (trading now), closed (Kalshi closed + settled, Polymarket closed) or all. |
minVolume | 0 | Skip markets whose lifetime volume_usd is below this number. |
sortBy | volume_24h | volume_24h, volume, liquidity (highest first), close_time (soonest first) or none. |
maxMarketsPerPlatform | 100 | Rows kept per platform after filtering and sorting. |
includeOrderbook | false | Fetch the live YES/NO order book for every row. |
orderbookDepth | 10 | Price levels per side (1–100). |
Kalshi's API lists markets in no useful order, so a Kalshi run without a search term ranks a pool of up to 3,000 open markets by sortBy; with a search term it walks the whole exchange (up to 50,000 markets, about 15 seconds) so rare terms are found. Polymarket is sorted server-side and cut at maxMarketsPerPlatform.
Pricing
Pay per event, no subscription: $1.50 per 1,000 markets and $2 per 1,000 order books. A default run (100 markets per platform, no order books) costs $0.30; the same run with order books costs $0.70. Set a maximum charge on the run and the Actor stops cleanly when it is reached, charging only for rows that were actually saved.
Use it from your tools
- API and SDKs – call it via the Apify API or the official Python/JavaScript clients: one call to start the run, one to fetch the merged dataset as JSON or CSV.
- Schedules – run it hourly or daily inside Apify and push new odds to Google Sheets, a webhook or your own storage automatically.
- n8n, Make and Zapier – trigger runs and pipe cross-platform odds into a workflow through Apify's integration for each.
- AI agents and MCP – this Actor is eligible for agentic use via Apify's MCP server and supports pay-per-event pricing, so an agent can call it mid-task and pay only per market it actually reads.
- Webhooks – fire on run finished to kick off the next step in a pipeline as soon as fresh odds land.
Details
- Sources: Kalshi's public trade API v2 (
api.elections.kalshi.com) and Polymarket's public Gamma and CLOB APIs (gamma-api.polymarket.com,clob.polymarket.com). No authentication, no proxies, no browser, no personal data (Polymarket wallet addresses are never output). - Freshness:
scraped_atis the UTC timestamp of the run. Kalshi prices are read live. Polymarket Gamma prices come from a CDN that caches for up to 5 minutes; order books are read live from the CLOB, so turn them on when you need the exact current bid and ask. - Reliability: 429 and 5xx responses are retried with exponential backoff (5 tries) and a 200 without the expected data counts as a failure. Each platform runs on its own: if one fails, the run pushes an error row (
platform,error,errorMessage) and continues with the other. A run fails only when it produced no rows and hit errors; a filter with no matching markets is a successful, empty run. - Run stats: the
STATSrecord in the run's key-value store holds market, order-book, request and error counts per platform and per category (network,rate_limit,blocked,not_found,other). - Speed: a default run finishes in about 10 seconds (five API calls). Order books add roughly a quarter of a second per market.
- Output: one dataset row per market. The Overview table shows platform, title, YES probability, 24 h volume, close time and link. Export as JSON, CSV or Excel, fetch through the Apify API, or schedule runs and pipe them into Google Sheets, Make, Zapier or your own code.