# Kalshi Prediction Markets Scraper: prices, volume, order book (`thatmike1/kalshi-markets-scraper`) Actor

Scrape live and settled Kalshi prediction markets from the public trading API: yes/no prices, top of the order book, volume, open interest, close and settlement times, and the result.

- **URL**: https://apify.com/thatmike1/kalshi-markets-scraper.md
- **Developed by:** [Michal Pšenčík](https://apify.com/thatmike1) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.005 / actor start

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Kalshi Prediction Markets Scraper (prices, order book, settlements)

### What does Kalshi Prediction Markets Scraper do?

This Actor reads **[Kalshi](https://kalshi.com)** prediction markets straight from the exchange's
**public trading API** ([docs.kalshi.com](https://docs.kalshi.com)). For every market it returns the ticker, the
question, the Kalshi category, the **yes and no bid/ask in dollars**, the **top of the order book with sizes on
both sides**, traded volume, 24-hour volume, open interest, the open and close times, the expiration times, and the
**result once the market settles**.

Filter by category (weather, sports, economics, politics and more), by a single series such as `KXHIGHNY`, and by
status (open, settled, or everything). Because it runs on the Apify platform you get a REST API for the results,
scheduled runs, run monitoring, and integrations with Google Sheets, Zapier, Make, Slack and the rest.

Try it from the **Input** tab: leave everything at its default and hit Start to get 100 markets that are trading
right now.

### Why use Kalshi Prediction Markets Scraper?

- **No API key, no account.** Kalshi's read endpoints are open, and this Actor uses only those. You never hand over
  a trading credential to run it.
- **Both sides of the book.** Most Kalshi datasets stop at the last traded price. This one carries the best bid and
  best ask with resting size on the yes side and the no side, which is what tells you whether a quoted price is
  real or a one-lot.
- **Settlement history.** Set **Market status** to `Settled` and every item carries `result` (`yes`, `no`, or
  `scalar`) alongside the final volume and open interest, so you can backtest a model against outcomes.
- **The event context, not just the ticker.** Kalshi's own `/markets` feed publishes no category and no readable
  event title. This Actor sweeps events instead, so every market arrives with its category, its event title and its
  series ticker attached.
- **Cross-market research.** One run pulls weather, sports, economics, politics, crypto and company markets in the
  same schema, ready for a spreadsheet, a dashboard or a Polymarket comparison.

### How to use Kalshi Prediction Markets Scraper

1. Click **Try for free** (or open the Actor in Apify Console).
2. On the **Input** tab, pick a **Category**. The default returns every category.
3. Optionally type a **Series ticker** such as `KXHIGHNY` to pin the run to one recurring question.
4. Pick a **Market status**. `Open` is the default and returns markets that are trading now.
5. Set **Maximum results**. The default is 100 markets. `0` means no limit, and Kalshi lists over 100,000 markets.
6. Click **Start**. A default run takes about 15 seconds.
7. Open the **Output** tab (or **Storage → Dataset**) and export as JSON, CSV, Excel or HTML, or pull it through the
   [Apify API](https://docs.apify.com/api/v2).

To keep the data fresh, use **Schedules** in Apify Console to run the Actor every few minutes against a single
series, or once a day for a full category sweep.

### Input

All fields are optional; the defaults return 100 open markets across every category.

| Field              | Type    | Default | Description                                                                                                                                    |
| ------------------ | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `category`         | string  | `all`   | One of `all`, `weather`, `sports`, `economics`, `politics`, `crypto`, `companies`, `entertainment`, `world`.                                   |
| `seriesTicker`     | string  | empty   | Restrict the run to one Kalshi series, e.g. `KXHIGHNY`. Applied on top of the category filter.                                                 |
| `status`           | string  | `open`  | One of `open`, `settled`, `all`. `all` returns open markets first, then settled, closed, and not-yet-open ones.                                |
| `maxItems`         | integer | `100`   | Stop after this many markets. `0` means no limit.                                                                                              |
| `includeOrderBook` | boolean | `true`  | Fetch the best bid and ask with sizes on both sides. Costs one extra API request per open market. Turn it off for a price-and-volume-only run. |

`economics` covers Kalshi's Economics, Financials and Commodities categories. `politics` covers Politics and
Elections. The `category` field in the output always carries Kalshi's own category name.

Example input:

```json
{
    "category": "weather",
    "status": "open",
    "maxItems": 100,
    "includeOrderBook": true
}
```

### Output

Each market is one dataset item. Download the dataset in various formats such as JSON, HTML, CSV, or Excel.

An open market, from a run with `seriesTicker: KXHIGHNY`:

```json
{
    "ticker": "KXHIGHNY-26SEP03-T83",
    "eventTicker": "KXHIGHNY-26SEP03",
    "seriesTicker": "KXHIGHNY",
    "title": "Will the maximum temperature be <83° on Sep 3, 2026?",
    "eventTitle": "Highest temperature in New York City on Sep 3, 2026?",
    "subtitle": "82° or below",
    "category": "Climate and Weather",
    "status": "open",
    "rawStatus": "active",
    "marketType": "binary",
    "strikeType": "less",
    "yesBid": 0.6,
    "yesAsk": 0.62,
    "noBid": 0.38,
    "noAsk": 0.4,
    "lastPrice": 0.62,
    "previousPrice": 0.33,
    "orderBook": {
        "yesBid": { "price": 0.6, "size": 1 },
        "yesAsk": { "price": 0.62, "size": 111.75 },
        "noBid": { "price": 0.38, "size": 111.75 },
        "noAsk": { "price": 0.4, "size": 1 }
    },
    "volume": 21066.03,
    "volume24h": 19396.48,
    "openInterest": 11701.29,
    "liquidity": 0,
    "openTime": "2026-09-02T14:00:00Z",
    "closeTime": "2026-09-04T05:00:00Z",
    "expectedExpirationTime": "2026-09-04T19:00:00Z",
    "expirationTime": "2026-09-10T14:00:00Z",
    "result": null,
    "rules": "If the maximum temperature recorded at New York City (CLINYC) for Sep 3, 2026, is less than 83° fahrenheit according to The Weather Company, then the market resolves to Yes.",
    "seriesUrl": "https://kalshi.com/markets/kxhighny",
    "apiUrl": "https://api.elections.kalshi.com/trade-api/v2/markets/KXHIGHNY-26SEP03-T83",
    "scrapedAt": "2026-09-03T16:59:04.369Z"
}
```

A settled market carries its `result`. Settled markets have no resting orders, so `orderBook` is `null` and the
bid/ask fields fall back to Kalshi's 0 and 1 placeholders:

```json
{
    "ticker": "KXHURRICANENAMES-26DEC01EPAC-FAU",
    "eventTicker": "KXHURRICANENAMES-26DEC01EPAC",
    "seriesTicker": "KXHURRICANENAMES",
    "title": "Will Fausto be categorized as a hurricane in the Eastern Pacific in 2026?",
    "eventTitle": "What named storms will be hurricanes in the Eastern Pacific this year?",
    "subtitle": "Fausto",
    "category": "Climate and Weather",
    "status": "settled",
    "rawStatus": "finalized",
    "marketType": "binary",
    "strikeType": "custom",
    "yesBid": 0,
    "yesAsk": 1,
    "noBid": 0,
    "noAsk": 1,
    "lastPrice": 0.99,
    "previousPrice": 0.99,
    "orderBook": null,
    "volume": 1001.29,
    "volume24h": 0,
    "openInterest": 780.54,
    "liquidity": 0,
    "openTime": "2026-05-15T22:00:00Z",
    "closeTime": "2026-07-29T14:46:04Z",
    "expectedExpirationTime": "2026-12-01T15:00:00Z",
    "expirationTime": "2026-12-08T15:00:00Z",
    "result": "yes",
    "rules": "If a storm named Fausto is a storm categorized as a hurricane in the Eastern Pacific between May 15, 2026 and December 01, 2026, then the market resolves to Yes.",
    "seriesUrl": "https://kalshi.com/markets/kxhurricanenames",
    "apiUrl": "https://api.elections.kalshi.com/trade-api/v2/markets/KXHURRICANENAMES-26DEC01EPAC-FAU",
    "scrapedAt": "2026-09-03T16:58:59.592Z"
}
```

With `includeOrderBook: false` the shape is identical and `orderBook` is `null`, which halves the run time:

```json
{
    "ticker": "KXWCCAREERGOALS-KMBAPPE-30",
    "eventTicker": "KXWCCAREERGOALS-KMBAPPE",
    "seriesTicker": "KXWCCAREERGOALS",
    "title": "Will Kylian Mbappe score at least 30 goals in the World Cup in his career?",
    "eventTitle": "Kylian Mbappe Total FIFA World Cup Career Goals",
    "subtitle": "30+ Goals Scored",
    "category": "Sports",
    "status": "open",
    "rawStatus": "active",
    "marketType": "binary",
    "strikeType": "structured",
    "yesBid": 0.8,
    "yesAsk": 0.83,
    "noBid": 0.17,
    "noAsk": 0.2,
    "lastPrice": 0.8,
    "previousPrice": 0.8,
    "orderBook": null,
    "volume": 687.03,
    "volume24h": 3,
    "openInterest": 231.36,
    "liquidity": 0,
    "openTime": "2026-07-20T23:52:00Z",
    "closeTime": "2043-07-28T14:00:00Z",
    "expectedExpirationTime": "2043-07-21T14:00:00Z",
    "expirationTime": "2043-07-28T14:00:00Z",
    "result": null,
    "rules": "If Kylian Mbappe scores at least 30 goals in FIFA World Cup Tournament games during his career, then the market resolves to Yes.",
    "seriesUrl": "https://kalshi.com/markets/kxwccareergoals",
    "apiUrl": "https://api.elections.kalshi.com/trade-api/v2/markets/KXWCCAREERGOALS-KMBAPPE-30",
    "scrapedAt": "2026-09-03T16:59:09.103Z"
}
```

#### Data fields

All prices are in **dollars per contract**, where a contract settles at $1.00. `0.62` is 62 cents, or a 62%
implied probability.

| Field                    | Type           | Description                                                                                                  |
| ------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------ |
| `ticker`                 | string         | Kalshi's market ticker. Stable across runs, so use it as your primary key.                                   |
| `eventTicker`            | string         | The event this market belongs to. One event usually holds several strike markets.                            |
| `seriesTicker`           | string | null | The recurring series, e.g. `KXHIGHNY`. Use it as the `seriesTicker` input to pin a run.                      |
| `title`                  | string | null | The market's own question, including its strike.                                                             |
| `eventTitle`             | string | null | The event's question, without the strike.                                                                    |
| `subtitle`               | string | null | What a Yes contract means, e.g. `82° or below`.                                                              |
| `category`               | string | null | Kalshi's category, e.g. `Climate and Weather`, `Sports`, `Elections`.                                        |
| `status`                 | string         | `unopened`, `open`, `closed`, `determined`, `settled`, `inactive`, or `other`.                               |
| `rawStatus`              | string         | Kalshi's own status string, e.g. `active`, `finalized`.                                                      |
| `marketType`             | string | null | Usually `binary`.                                                                                            |
| `strikeType`             | string | null | `greater`, `less`, `between`, `custom`, `structured`. Empty on plain yes/no markets.                         |
| `yesBid`, `yesAsk`       | number | null | Best bid and ask for a Yes contract, in dollars.                                                             |
| `noBid`, `noAsk`         | number | null | Best bid and ask for a No contract, in dollars.                                                              |
| `lastPrice`              | number | null | Last traded price.                                                                                           |
| `previousPrice`          | number | null | Kalshi's previous reference price.                                                                           |
| `orderBook`              | object | null | `yesBid`, `yesAsk`, `noBid`, `noAsk`, each with `price` and `size`. `null` for markets that are not trading. |
| `volume`                 | number | null | Contracts traded over the market's life.                                                                     |
| `volume24h`              | number | null | Contracts traded in the last 24 hours.                                                                       |
| `openInterest`           | number | null | Contracts currently outstanding.                                                                             |
| `liquidity`              | number | null | Kalshi's liquidity figure in dollars.                                                                        |
| `openTime`               | string | null | When the market opened, ISO 8601 in UTC.                                                                     |
| `closeTime`              | string | null | Last trading time.                                                                                           |
| `expectedExpirationTime` | string | null | When Kalshi expects to settle.                                                                               |
| `expirationTime`         | string | null | The latest possible settlement time.                                                                         |
| `result`                 | string | null | `yes`, `no` or `scalar` once settled. `null` while the market is still live.                                 |
| `rules`                  | string | null | Kalshi's primary settlement rule, in full.                                                                   |
| `seriesUrl`              | string | null | Link to the series page on kalshi.com.                                                                       |
| `apiUrl`                 | string         | Link to this market on Kalshi's public API.                                                                  |
| `scrapedAt`              | string         | When this run read the API, ISO 8601 in UTC.                                                                 |

### How much does it cost to scrape Kalshi markets?

This Actor uses **pay per event** pricing: **$0.002 per market** returned, plus **$0.005 per run start**. Platform
usage is included, so those two numbers are the whole bill.

The default run returns 100 markets and costs **$0.205**. A single weather series such as `KXHIGHNY` holds about a
dozen open markets, so one run against it costs **$0.029** and a five-minute schedule is a little over $8 a day.
The Apify free plan comes with $5 of monthly platform credit, which is enough to try the Actor and run it for a
while.

To cap spending on a single run, set `maxItems`, or set a maximum cost in the run options.

### Tips and advanced options

- **Pin a series for live tracking.** `seriesTicker` plus a small `maxItems` is the cheapest way to watch one
  question. `KXHIGHNY` is the New York high temperature, `KXNFLGAME` is NFL games, `KXHURRICANENAMES` is the
  hurricane season.
- **Backtest against settlements.** `status: settled` with a category gives you resolved markets with their final
  `result`, `volume` and `openInterest`. Order books are not fetched for them, so those runs are fast.
- **Read the book, not just the price.** A market can show `yesAsk: 0.62` with one contract behind it. `orderBook`
  carries the resting size, so you can drop quotes that are too thin to trade against.
- **Deduplicate across runs.** `ticker` is stable, so upsert on it. A market pulled while open and again after it
  settled has the same ticker and a filled `result` the second time.
- **`status: all` sweeps in a useful order.** Open markets first, then settled, closed, and finally the very large
  pool of markets that have not opened yet, so a capped run fills with tradeable markets first.
- **Combination markets are excluded.** Kalshi auto-generates tens of thousands of `KXMVECROSSCATEGORY` parlay
  markets that carry no readable question. This Actor reads events rather than the raw market feed, so those never
  appear in your dataset.

### FAQ, disclaimers and support

**Does this Actor need a Kalshi API key?**
No. Kalshi's market data endpoints are public and were verified working without any credential. A key is only
needed for account and trading endpoints, which this Actor never touches.

**Does it use a proxy?**
No. Kalshi's API answers plain requests, so no proxy is configured and there is no proxy cost. The Actor paces
itself at roughly nine requests a second so it stays inside the exchange's rate limits.

**Is scraping Kalshi legal?**
This Actor reads Kalshi's own documented public API and collects market facts, not personal data. You are
responsible for how you use the output, including Kalshi's Developer Agreement and terms. Nothing here is trading
or investment advice.

**Why do prices sometimes read 0 and 1 on settled markets?**
That is what Kalshi's API returns once a market stops trading. `orderBook` is `null` for those, and `lastPrice`
holds the last real trade.

**Why did I get fewer markets than I asked for?**
Check `maxItems`, `category`, `seriesTicker` and `status`. A narrow series may simply not have that many markets
open. The run log prints the filters it resolved.

**Does it cover Polymarket too?**
No. This Actor is Kalshi only.

**Found a bug, or need something else?**
Open an issue on the **Issues** tab of this Actor and it will be picked up. Trade history, candlesticks and
WebSocket-level updates are all reachable from the same API, so mention it in the issue if you need them.

# Actor input Schema

## `category` (type: `string`):

Only return markets in this Kalshi category. 'Economics' also covers Financials and Commodities; 'Politics' also covers Elections.

## `seriesTicker` (type: `string`):

Restrict the run to one Kalshi series, for example KXHIGHNY (New York high temperature) or KXNFLGAME (NFL games). Leave empty to sweep every series. Applied on top of the category filter.

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

'Open' returns markets that are trading right now. 'Settled' returns markets that have paid out, with their result. 'All' returns both plus closed and not-yet-open markets, open ones first.

## `maxItems` (type: `integer`):

Stop after this many markets. Set to 0 for no limit. Kalshi lists over 100,000 markets, so leaving this at 0 with no filter is a long run.

## `includeOrderBook` (type: `boolean`):

Fetch the best bid and ask with sizes on both the yes and no side. Costs one extra API request per market and adds a few seconds per hundred markets. Turn it off for a faster price-and-volume-only run.

## Actor input object example

```json
{
  "category": "all",
  "seriesTicker": "KXHIGHNY",
  "status": "open",
  "maxItems": 100,
  "includeOrderBook": true
}
```

# Actor output Schema

## `markets` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("thatmike1/kalshi-markets-scraper").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("thatmike1/kalshi-markets-scraper").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 '{}' |
apify call thatmike1/kalshi-markets-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/pcSFAM26r9jTl8NEY/builds/GxgUgtCCoUaNXmEER/openapi.json
