# Prediction Markets Scraper: Kalshi & Polymarket Odds (`datagleaner/prediction-markets`) Actor

Prediction markets scraper and API for Kalshi and Polymarket: one normalized table of odds (Yes/No probability), bid/ask, 24h volume, liquidity, close time and rules. Filter by keyword or category, open or closed. $1 per 1,000 markets. Public data, no login or API key.

- **URL**: https://apify.com/datagleaner/prediction-markets.md
- **Developed by:** [Data Gleaner](https://apify.com/datagleaner) (community)
- **Categories:** Automation, News, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 markets

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Prediction Markets Scraper: Kalshi and Polymarket odds, volume and rules in one table

**One normalized dataset of prediction-market prices from Kalshi and Polymarket.** Each row is one market with the Yes and No probability, best bid and ask, last trade, 24-hour and total volume, liquidity, close time, resolution rules and a link to the market page. Filter by keyword or category, read open or settled markets, and sort by 24-hour volume. JSON, CSV or Excel. No login, no API key, no browser. **$1.00 per 1,000 markets ($0.001 each).**

#### Why this one

- **Two venues, one schema.** Kalshi (US-regulated exchange) and Polymarket speak different dialects: Kalshi sends prices as dollar strings and volume in contracts, Polymarket sends outcomes and prices as JSON strings and volume in USD. Every row comes out with the same field names, numeric probabilities from 0 to 1, ISO 8601 times and a stated `volumeUnit`, so you can put the two side by side in a spreadsheet, a dashboard or an LLM prompt.
- **The official public market-data APIs.** It reads Kalshi's public market-data API and Polymarket's public Gamma API over plain HTTP. No trading account, no key, no scraping around a block. Requests are paced politely (0.25 s by default) to stay well inside both venues' published rate limits.
- **Works from Apify's servers without a proxy.** Both APIs answered from Apify datacenter IPs in testing. A proxy field is there if you want one.
- **Cheap to schedule.** Pull the top 100 markets by 24-hour volume every hour for about $0.10 a run, or the full order book of open markets once a day.
- **Built for pipelines and AI agents.** Flat rows, stable camelCase fields, numbers as numbers, a run summary in the status message (rows per venue, failures, anything that stopped the run early).

#### Minimal input

```json
{"venues": ["kalshi", "polymarket"], "search": "bitcoin", "maxMarkets": 50}
```

An empty input runs a built-in example: the top 5 markets by 24-hour volume across both venues.

#### Sample output rows

A Kalshi market and a Polymarket market from a platform run on 2026-10-21 (rules text and tags shortened here):

```json
{
  "venue": "kalshi",
  "marketId": "CONTROLH-2026-R",
  "ticker": "CONTROLH-2026-R",
  "eventId": "CONTROLH-2026",
  "eventTicker": "CONTROLH-2026",
  "eventTitle": "Which party will win the U.S. House?",
  "question": "Will Republicans win the House in 2026?",
  "outcomeLabel": "Republican Party",
  "outcomes": ["Yes", "No"],
  "yesPrice": 0.0905,
  "noPrice": 0.9095,
  "yesBid": 0.09,
  "yesAsk": 0.091,
  "noBid": 0.909,
  "noAsk": 0.91,
  "lastPrice": 0.091,
  "volume24h": 1274457.26,
  "volumeUnit": "contracts",
  "totalVolume": 42666645.13,
  "liquidity": null,
  "openInterest": 31330400.78,
  "closeTime": "2027-02-01T15:00:00Z",
  "status": "open",
  "result": null,
  "category": "Elections",
  "tags": ["Elections", "CONTROLH"],
  "rules": "If the Republican Party has won control of the House in 2026, then the market resolves to Yes. ...",
  "resolutionSource": "Library of Congress",
  "url": "https://kalshi.com/markets/controlh",
  "scrapedAt": "2026-10-21T15:53:21Z",
  "input": {"venue": "kalshi", "search": null, "categories": null, "status": "open", "sortBy": "volume24h", "minVolume24h": null}
}
```

```json
{
  "venue": "polymarket",
  "marketId": "2589811",
  "ticker": "will-the-fed-decrease-interest-rates-by-25-bps-after-the-october-2026-meeting-20260617190324030",
  "eventId": "606422",
  "eventTicker": "fed-decision-in-october-20260617190323537",
  "eventTitle": "Fed Decision in October?",
  "question": "Will the Fed decrease interest rates by 25 bps after the October 2026 meeting?",
  "outcomeLabel": "25 bps decrease",
  "outcomes": ["Yes", "No"],
  "yesPrice": 0.0035,
  "noPrice": 0.9965,
  "yesBid": 0.003,
  "yesAsk": 0.004,
  "noBid": null,
  "noAsk": null,
  "lastPrice": 0.003,
  "volume24h": 858432.985999,
  "volumeUnit": "USD",
  "totalVolume": 9540985.758944,
  "liquidity": 1129077.11034,
  "openInterest": null,
  "closeTime": "2026-10-29T03:59:00Z",
  "status": "open",
  "result": null,
  "category": "Economy",
  "tags": ["Fed", "fomc", "Economy", "Fed Rates", "Macro Indicators"],
  "rules": "The FED interest rates are defined in this market by the upper bound of the target federal funds range. ...",
  "resolutionSource": "https://www.federalreserve.gov/monetarypolicy/fomccalendars.htm",
  "url": "https://polymarket.com/event/fed-decision-in-october-20260617190323537",
  "conditionId": "0x9cf563d7b55aa9aa876d5d7e55126347eee473f0ae56d799e325fdef2bf25297",
  "scrapedAt": "2026-10-21T15:53:22Z",
  "input": {"venue": "polymarket", "search": null, "categories": null, "status": "open", "sortBy": "volume24h", "minVolume24h": null}
}
```

#### Price

**$1.00 per 1,000 markets** ($0.001 per market row), final. Volume discounts apply automatically by Apify plan: Free and Bronze $0.001, Silver $0.00085, Gold $0.0007 per market.

| Run | Markets | Cost at $0.001 |
|---|---|---|
| Top 100 markets by 24h volume, hourly for a day | 24 runs x 100 | $2.40 |
| Every open market about "bitcoin", once | about 1,000 | about $1.00 |
| 1,000 markets, once | 1,000 | $1.00 |

Each returned market is one billed row, so `maxMarkets` is also your cost cap. Set a maximum charge per run in Apify and the run stops when it is reached.

### What does Prediction Markets Scraper do?

- Reads every open market on **Kalshi** and **Polymarket**, or only the venue you choose.
- Returns one row per market with Yes and No probability, best bid and ask, last price, 24h volume, total volume, liquidity, open interest, close time, status, category and tags.
- Adds the **resolution rules** (shortened to 600 characters), the named resolution source where the venue gives one, and a link to the market page.
- Keeps multi-outcome events as one row per market, with `eventTitle`, `eventId` and `outcomeLabel` (candidate, bracket or team) to group them.
- Filters by keyword (`search`), by `categories` (politics, sports, crypto, economics, weather, tech or any Polymarket tag such as `bitcoin` or `nba`) and by minimum 24h volume.
- Reads open markets, or closed and settled ones (`status`), including the `result` of settled markets.
- Sorts by 24h volume, total volume, liquidity or closing soonest.

#### Use cases

- **Arbitrage and spread watch.** Schedule a run, join Kalshi and Polymarket rows on the same question and look for gaps between the two prices.
- **Research and forecasting.** Collect odds for elections, rate decisions, inflation prints or sports as a dataset, and track how probabilities move run over run.
- **News and trading signals.** Alert when the Yes probability of a market jumps, or when 24h volume spikes on a topic.
- **AI agents and LLM pipelines.** Give an agent flat, labelled probabilities with rules and sources instead of making it parse two different APIs.
- **Dashboards and newsletters.** Feed "most traded markets today" tables to a site, a Google Sheet or a Slack message.

### Input

| Field | Type | What it does |
|---|---|---|
| `venues` | list | `kalshi`, `polymarket` or both. Prefilled with both. |
| `search` | text | Optional. Keep markets whose event title, question or option contains every word (case-insensitive). |
| `categories` | list of text | Optional. `politics`, `sports`, `crypto`, `economics`, `weather`, `tech` or any Polymarket tag slug. Kalshi matches its own category names (Politics, Elections, Economics, Financials, Climate and Weather, Science and Technology, Sports, Crypto, and so on). |
| `status` | choice | `open` (default, trading now) or `closed` (ended or settled). |
| `minVolume24h` | number | Optional. Drop markets traded less than this in the last 24 hours (Kalshi contracts, Polymarket USD). |
| `sortBy` | choice | `volume24h` (default), `totalVolume`, `liquidity` or `closeTime` (soonest first). |
| `maxMarkets` | number | Default 1,000, prefilled 10. Maximum rows across all venues, and your cost cap. |
| `requestDelaySeconds` | number | Default 0.25. Pause between API requests. |
| `proxyConfiguration` | proxy | Optional. Default none. |

Example inputs:

```json
{"venues": ["polymarket", "kalshi"], "categories": ["politics"], "maxMarkets": 100}
{"venues": ["kalshi", "polymarket"], "search": "bitcoin", "sortBy": "volume24h", "maxMarkets": 50}
{"venues": ["polymarket"], "status": "closed", "categories": ["crypto"], "maxMarkets": 200}
```

### Output fields

| Field | Meaning |
|---|---|
| `venue` | `kalshi` or `polymarket` |
| `marketId`, `ticker` | Kalshi ticker, or Polymarket market id and slug |
| `eventId`, `eventTicker`, `eventTitle` | The event the market belongs to |
| `question`, `outcomeLabel` | The market question and its short label inside a multi-market event |
| `outcomes` | Outcome labels (Yes and No on Kalshi; Polymarket sometimes uses team names or Over and Under) |
| `yesPrice`, `noPrice` | Probability of the first and second outcome, 0 to 1 |
| `yesBid`, `yesAsk`, `noBid`, `noAsk`, `lastPrice` | Quotes, 0 to 1. The No quotes are Kalshi only |
| `volume24h`, `totalVolume`, `volumeUnit` | Volume, with its unit: `contracts` on Kalshi, `USD` on Polymarket |
| `liquidity` | USD, Polymarket only |
| `openInterest` | Contracts on Kalshi; on Polymarket only for single-market events |
| `closeTime`, `status`, `result` | ISO close time; `open`, `paused`, `closed` or `settled`; winning outcome of settled markets |
| `category`, `tags` | Category and tags |
| `rules`, `resolutionSource` | Resolution rules (600 characters at most) and named source |
| `url` | Market page on kalshi.com or polymarket.com |
| `conditionId` | Polymarket on-chain condition id |
| `scrapedAt`, `input` | When it was read and which input produced the row |

#### How the numbers are defined

- **Polymarket** `yesPrice` is the first outcome's price from the API (`outcomePrices`), which is the market's displayed probability. For markets that are not Yes/No, read `outcomes` for the labels.
- **Kalshi** `yesPrice` is the midpoint of the best Yes bid and ask when both sides are quoted, and the last traded price when the book is one-sided or empty. `noPrice` is `1 - yesPrice`.
- **Volume units differ.** A Kalshi contract pays 1 USD if it wins, so contract counts and USD are the same order of magnitude, but they are not the same thing. Rankings that mix both venues are approximate; sort one venue at a time if it matters.
- Prices are the venue's quote at `scrapedAt`. Run on a schedule and compare rows for changes over time.

### Limits

- Kalshi's API cannot sort by volume, so an open-market run reads all open Kalshi events first (about a minute in total) and then ranks them. Closed markets: Kalshi returns the most recent history first, so `status: closed` gives the newest settled markets, sorted among those; Polymarket closed markets are sorted by total volume.
- Polymarket search and category filters read events in descending order of volume; a very rare keyword in a low-volume market can sit beyond the 7,500 events read per tag.
- `search` matches words in titles, labels and tags, not meaning.
- Market lists change by the minute. Two runs a minute apart can differ.

### FAQ

**Do I need a Kalshi or Polymarket account or API key?** No. The Actor reads public market-data endpoints only.

**Why is `liquidity` empty on Kalshi?** Kalshi's public API does not give a liquidity number; use `yesBid`, `yesAsk` and `openInterest`.

**How do I match the same event on both venues?** Search the same keywords on both and join on the `question` or `eventTitle`. Titles are written differently on each venue, so a fuzzy match works better than an exact one.

**How fresh is the data?** Live: each run reads the venues' current quotes.

**Can it place trades?** No. It only reads public data.

### Responsible use

This Actor collects public market data that Kalshi and Polymarket publish through their own public APIs. It is provided for research and information, not financial advice, and it does not place or recommend trades. Prediction-market access and trading are regulated differently by country; check the rules that apply to you. Respect each venue's terms of use and rate limits, and keep your own volume modest.

# Actor input Schema

## `venues` (type: `array`):

Which prediction markets to read: Kalshi, Polymarket or both.

## `search` (type: `string`):

Keep markets whose event title, question or option contains every word, for example "bitcoin", "fed rate" or "world cup". Leave empty for all markets.

## `categories` (type: `array`):

Keep markets in these categories, for example politics, sports, crypto, economics, weather, tech. Polymarket matches its tag slugs (any tag works, such as bitcoin or nba); Kalshi matches its category names. Leave empty for all.

## `status` (type: `string`):

open: tradable markets now (default). closed: ended or settled markets; Polymarket is sorted by total volume, Kalshi returns the most recent history the API lists first.

## `minVolume24h` (type: `number`):

Drop markets traded less than this in the last 24 hours (Kalshi contracts, Polymarket USD). Leave empty or 0 for no minimum.

## `sortBy` (type: `string`):

Order of the rows, best first. closeTime puts the soonest-ending markets first. Kalshi counts contracts and Polymarket counts USD, so mixed-venue volume rankings are approximate.

## `maxMarkets` (type: `integer`):

Maximum number of markets returned across all venues. Each returned market is billed, so this is also your cost cap.

## `requestDelaySeconds` (type: `number`):

Pause between API requests, randomised up to 1.5x, to stay well inside the venues' published rate limits.

## `proxyConfiguration` (type: `object`):

Optional Apify Proxy. Default is no proxy; both APIs answered from Apify datacenter IPs without one.

## Actor input object example

```json
{
  "venues": [
    "kalshi",
    "polymarket"
  ],
  "status": "open",
  "sortBy": "volume24h",
  "maxMarkets": 10,
  "requestDelaySeconds": 0.25
}
```

# Actor output Schema

## `markets` (type: `string`):

No description

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "venues": [
        "kalshi",
        "polymarket"
    ],
    "maxMarkets": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagleaner/prediction-markets").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "venues": [
        "kalshi",
        "polymarket",
    ],
    "maxMarkets": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("datagleaner/prediction-markets").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "venues": [
    "kalshi",
    "polymarket"
  ],
  "maxMarkets": 10
}' |
apify call datagleaner/prediction-markets --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datagleaner/prediction-markets"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/FL7tHFJf0OkexILby/builds/zsUyNcRjrwBOlf53t/openapi.json
