Prediction Markets Data: Kalshi + Polymarket in One Schema
Pricing
from $1.60 / 1,000 market outcomes
Prediction Markets Data: Kalshi + Polymarket in One Schema
Pick Kalshi, Polymarket or both, optionally filter by keyword or category, and get one flat row per outcome: probability (0-1), bid/ask, 1h/24h/7d change, volume, liquidity, close time and URL. Optional 7-day price history and changed-since-last-run mode. Official public APIs.
Pricing
from $1.60 / 1,000 market outcomes
Rating
0.0
(0)
Developer
SUNGHWAN CHO
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Choose Kalshi, Polymarket or both (optionally a keyword, category, status or minimum volume), and get one flat row per market outcome with the implied probability (0–1), best bid/ask, 1h/24h/7d price change, volume, liquidity or open interest, close time and a link to the market.
- Both venues in the same English field names, numbers as numbers, missing values as
null. - Open markets come highest 24-hour volume first.
- Optional 7-day hourly price history per outcome.
- Optional "only what changed since my last run" mode for scheduled monitoring and alerts.
- Uses only the venues' official public, unauthenticated read APIs. No login, no browser, no proxy.
What you get
One row per outcome:
- A single yes/no question (e.g. "Will the Fed cut rates in December?") → one row,
outcome: "Yes". - A multi-outcome event (e.g. "Who will win the 2028 Democratic nomination?") → one row per candidate,
outcome: "Gavin Newsom", … - A two-sided Polymarket market (e.g. a game "Ravens vs. Falcons") → one row per side.
| Field | Meaning |
|---|---|
venue | polymarket or kalshi |
eventId, eventTitle | Event the market belongs to |
marketId, question | Kalshi market ticker / Polymarket condition id, and the market question |
outcome, outcomeId | What this row prices (candidate, team, range or Yes); Kalshi ticker / Polymarket CLOB token id |
probability | Implied probability 0–1 (see below) |
lastPrice, bestBid, bestAsk, spread | Prices on the 0–1 scale |
change1h, change24h, change7d | Price change on the 0–1 scale (0.05 = +5 points) |
volume24h, volumeTotal, volumeUnit | Volume; volumeUnit is USD (Polymarket) or contracts (Kalshi, each contract pays $1) |
liquidity | Polymarket order-book liquidity in USD (null on Kalshi) |
openInterest | Kalshi open interest in contracts (null on Polymarket) |
closeTime | Scheduled close, ISO 8601 |
status, resolvedOutcome | open, closed, resolved, upcoming; the winning outcome once resolved |
category, tags | Kalshi event category; Polymarket main category and all tags |
url | Market page |
previousProbability, probabilityChangeSinceLastRun, changeType | Filled in change mode only |
priceHistory | [{ "time", "price" }] hourly for 7 days, when requested |
scrapedAt, schemaVersion | Collection time and output version |
Example row:
{"venue": "kalshi","eventId": "KXNEXTNATOSECGEN-99","eventTitle": "Who will be the next Secretary General of NATO?","marketId": "KXNEXTNATOSECGEN-99-KKAL","question": "Will Kaja Kallas be the next Secretary General of NATO?","outcome": "Kaja Kallas","outcomeId": "KXNEXTNATOSECGEN-99-KKAL","probability": 0.21,"lastPrice": 0.21,"bestBid": 0.25,"bestAsk": 0.47,"spread": 0.22,"change1h": null,"change24h": 0.088,"change7d": null,"volume24h": 0,"volumeTotal": 1936.64,"volumeUnit": "contracts","liquidity": null,"openInterest": 1174.5,"closeTime": "2099-01-08T15:00:00.000Z","status": "open","resolvedOutcome": null,"category": "Elections","tags": ["Elections"],"url": "https://kalshi.com/markets/kxnextnatosecgen","previousProbability": null,"probabilityChangeSinceLastRun": null,"changeType": null,"priceHistory": null,"scrapedAt": "2026-10-12T03:48:47.026Z","schemaVersion": 1}
How probability is computed
- Polymarket: the outcome price Polymarket itself displays (
outcomePrices). - Kalshi: the midpoint of best bid and best ask when the spread is 10 cents or less, otherwise the last traded price (the same rule Polymarket uses for its display).
nullif the market never traded and has no two-sided book.
Where the changes come from
- Polymarket: the 1h/24h/7d changes Polymarket publishes for each market; missing ones are filled from price history when you turn it on.
- Kalshi:
change24h= last price − price 24 hours ago.change1handchange7dneed Include 7-day price history (then all three are computed from the hourly history, againstprobability).
Input
| Field | Default | Notes |
|---|---|---|
venues | both | polymarket, kalshi |
keywords | – | Any of these words in event title, question or outcome (case-insensitive) |
categories | – | Whole-word match on category/tags, e.g. Politics, Crypto, Economics, Weather |
status | open | open, closed (resolved first, most recent first), all (open first) |
maxItems | 100 | Rows per venue (1–10,000) |
minVolume24h | 0 | USD on Polymarket, contracts on Kalshi |
closingWithinDays | – | Only markets closing within N days |
includePriceHistory | false | Adds 7-day hourly priceHistory |
onlyChangedSinceLastRun | false | Change mode, see below |
minProbabilityChange | 0.01 | Smallest move that counts as a change (0–1 scale) |
historyStoreName | prediction-markets-history | Named key-value store that remembers the last returned probabilities |
Example — top 50 crypto markets on both venues:
{ "categories": ["Crypto"], "maxItems": 50 }
Example — every 15 minutes, alert on Fed / rates markets that moved 3+ points:
{"keywords": ["fed", "rate cut", "fomc"],"onlyChangedSinceLastRun": true,"minProbabilityChange": 0.03,"historyStoreName": "fed-watch"}
Change mode
With onlyChangedSinceLastRun, the Actor builds the same list as usual (filters + maxItems) and then returns only outcomes that are new, changed status, or moved at least minProbabilityChange since they were last returned. The comparison point only moves when a row is returned, so slow drifts are still reported once they add up. Use a different historyStoreName for each watchlist. Two runs with the same store at the same moment may report the same change twice.
Pricing
Pay per event: one market-outcome event per row saved to the dataset. Runs that save nothing (no matches, or nothing changed) cost no events; failed requests are never charged. If you set a Maximum cost per run, the Actor stops cleanly when it is reached and says so in the status message and in RUN_SUMMARY.
Run summary
The key-value store record RUN_SUMMARY (free) has per-venue status (completed, failed, budgetLimited), stopReason, markets scanned, rows matched/saved, rows unchanged (change mode) and request counts. If one venue fails, the other venue's rows are still saved; the run fails only if every venue failed.
Speed and limits
- Polymarket returns markets sorted by 24h volume, so the Actor stops as soon as it has enough rows. Up to 5,000 open markets are scanned per run when a filter is narrow.
- Kalshi does not sort by volume, so the Actor reads the whole open list (about 12,000 events / 120,000 markets, roughly 2–4 minutes at 256 MB) and sorts it. With
status: closed, resolved (settled) markets come first, then closed-but-unresolved ones, most recently closed first; up to 2,000 events of each are scanned and Kalshi markets that never traded are skipped. status: allreturns open markets first and fills the rest with closed ones.- Requests are paced (about 2–3 per second) and well under both venues' published rate limits.
- The Actor must run on the Apify platform. Polymarket blocks some countries; this Actor does not try to get around regional restrictions.
Notes and responsible use
- This Actor reads public market data through official, unauthenticated read endpoints. It does not log in, trade, or access any account or personal data.
- Kalshi's Developer Agreement and data terms and Polymarket's Terms of Use restrict how their data may be stored, redistributed and used commercially. You are responsible for making sure your use of the data complies with those terms. Not investment advice.
- Kalshi market URLs point to the series page.
- Cross-venue matching ("is this Kalshi market the same as that Polymarket market?") is deliberately not done: resolution rules and close times differ even when the questions look alike.