# Kalshi Markets Scraper - Odds, Volume & Weather Forecasts (`dami_studio/kalshi-markets-scraper`) Actor

Kalshi prediction markets as rows: yes and no prices, last trade, volume, open interest, close time and result. The daily high and low temperature brackets in 24 US cities also get the forecast for their station and day, and whether it lands in the bracket. No API key or login.

- **URL**: https://apify.com/dami\_studio/kalshi-markets-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Business, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.92 / 1,000 market returneds

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 Markets Scraper

Kalshi's markets as rows, read from Kalshi's own public API: the yes and no prices, the last trade, volume, open interest, when trading closes and how the market settled.

The daily temperature markets get extra columns. Each bracket comes with the forecast for the weather station that market settles on, so you can see at a glance whether the forecast sits inside "73° or below" or three degrees above it.

There's no Kalshi account, API key or login involved.

### Temperature markets

Every day Kalshi asks how hot and how cold it will get in 24 US cities. Each question is split into six brackets, such as "73° or below" or "74° to 75°", and the bracket that holds the recorded temperature pays out.

Pick the cities and you get every bracket for the days Kalshi has open, usually today and tomorrow. Each bracket carries:

- `forecastTempF`: Open-Meteo's forecast high or low for that station and day.
- `forecastInBracket`: whether the forecast, rounded to a whole degree the way temperatures are recorded, falls inside the bracket.
- `forecastDistanceF`: how many degrees it would have to move to get inside, and 0 when it already is.

The forecast is for the station named in the market's rules, not the middle of town: Central Park for New York City, Midway for Chicago, the main airport for most of the others. `stationCode` and `stationName` tell you which. Once a market has settled, `settledTempF` holds the temperature it settled on.

A forecast is a model's guess and it moves during the day. It isn't Kalshi's data, and it isn't what the markets settle on. Today and the next 15 days get one; days already over don't.

The cities: Atlanta, Austin, Boston, Chicago, Dallas, Denver, Houston, Las Vegas, Los Angeles, Louisville, Miami, Minneapolis, New Orleans, New York City, Newark, Oklahoma City, Philadelphia, Phoenix, San Antonio, San Diego, San Francisco, Seattle, Trenton and Washington DC.

### Everything else on Kalshi

Every other market works the same way, one row each. Choose them by category, such as Economics or Sports, by Kalshi's tags, by series, by event or by market ticker. Or set only a status and take whatever Kalshi lists.

Then narrow the list with close dates, a keyword, or a floor on volume, 24-hour volume or open interest. Each market's orderbook and its latest trades can come along too.

### What it doesn't do

- **Trade.** It can't see an account, and it doesn't place or cancel orders.
- **Price history.** A row is the market as it stood when the run read it, and `fetchedAt` says when. Kalshi's API can answer from a copy up to 15 seconds old.
- **Combo markets, unless you ask.** Kalshi generates markets that bundle several outcomes into one contract, in very large numbers. They stay out unless you set Combo markets to include them, and they come without an event title, series or category, because Kalshi's list of events leaves combos out.
- **Old settled markets through a category.** Kalshi keeps recent settled markets in its live list and moves older ones to an archive after a few months. Searches by series, event, market ticker or city look in both. A category search only sees the live list.
- **More than 50,000 markets in one run.** Kalshi's open list alone is well over 100,000 markets, so split a big job by category or status. With recent trades on, a run stops at 2,000 markets.

### Input

There are two kinds of setting. Targets say which markets you want: cities, categories, tags, series, events and market tickers. They add up. Filters then narrow those down: status, close dates, keyword, volume, 24-hour volume and open interest.

Leave the status empty and cities, categories and series give you open markets, while event and market tickers come back whatever their status. A run with nothing set returns one sample row and charges nothing.

Brackets for three cities, with forecasts:

```json
{
  "status": "open",
  "weatherCities": ["New York City", "Chicago", "Miami"],
  "maxMarkets": 100
}
```

Every settled New York high from one summer. The older days come from Kalshi's archive:

```json
{
  "status": "settled",
  "seriesTickers": ["KXHIGHNY"],
  "closeFrom": "2026-06-01",
  "closeTo": "2026-08-31",
  "maxMarkets": 2000
}
```

Busy economics markets with their orderbooks:

```json
{
  "status": "open",
  "categories": ["Economics"],
  "minVolume": 1000,
  "includeOrderbook": true,
  "orderbookDepth": 5
}
```

Close dates are whole days in UTC. Tickers are Kalshi's own; capitals don't matter.

### Output

One row per market. Prices are in dollars: `0.37` is 37 cents, which the market reads as a 37% chance of yes. Volume and open interest count contracts, and Kalshi lets people trade parts of a contract, so they can have decimals.

A real row, the New York high for 14 September 2026, as Kalshi listed it on the 13th:

| Field | Example | |
|---|---|---|
| `ticker` | `KXHIGHNY-26SEP14-T74` | the market |
| `eventTicker` | `KXHIGHNY-26SEP14` | the day's question |
| `seriesTicker` | `KXHIGHNY` | the question as it repeats every day |
| `eventTitle` | `Highest temperature in New York City on Sep 14, 2026?` | |
| `yesSubTitle` | `73° or below` | what has to happen for yes |
| `category` | `Climate and Weather` | Kalshi's category for the event. A series can sit in more than one, so a market found through Economics may say Financials here |
| `statusGroup` | `open` | open, closed, settled, unopened or paused; `status` has Kalshi's own word |
| `yesBid`, `yesAsk` | `0.36`, `0.37` | the best prices to sell and to buy yes |
| `noBid`, `noAsk` | `0.63`, `0.64` | the same for no |
| `lastPrice` | `0.37` | the last trade |
| `volume`, `volume24h` | `231.78`, `121` | contracts traded since the market opened, and in the last 24 hours |
| `openInterest` | `231.78` | contracts still held |
| `closeTime` | `2026-09-15T05:00:00Z` | when trading stops |
| `result` | `null` | `yes` or `no` once settled |
| `url` | `https://kalshi.com/markets/kxhighny` | the series on kalshi.com |

Every row also has `title`, `noSubTitle`, `eventSubTitle`, `marketType`, `strikeType`, `floorStrike`, `capStrike`, the sizes at the best bid and ask, the prices a day earlier (`previousYesBid`, `previousYesAsk`, `previousPrice`), `openTime`, `expectedExpirationTime`, `latestExpirationTime`, `settlementTime`, `settlementValue`, `expirationValue` (the figure the market settled on), `canCloseEarly`, `isCombo`, `rulesPrimary` (the market's rule in Kalshi's words), `archived` and `fetchedAt`.

Temperature brackets add:

| Field | Example | |
|---|---|---|
| `city` | `New York City` | |
| `stationCode`, `stationName` | `CLINYC`, `New York City, Central Park` | where the temperature is recorded |
| `weatherDate` | `2026-09-14` | the day the bracket is about |
| `temperatureKind` | `high` | `high` or `low` |
| `bracketLowF`, `bracketHighF` | `null`, `73` | the bracket in whole degrees, both ends included; `null` means open-ended |
| `forecastTempF` | `72.5` | Open-Meteo's forecast for that station and day |
| `forecastInBracket` | `true` | 72.5 rounds to 73, which is inside |
| `forecastDistanceF` | `0` | degrees between the forecast and the bracket |
| `settledTempF` | `null` | the recorded temperature, once settled; empty on the odd archived bracket Kalshi sends without it |

They also carry `forecastSource` and `forecastFetchedAt`.

With the orderbook on, `orderbook` holds `yesBids` and `noBids`, best price first, each like `{ "price": 0.36, "contracts": 30 }`. A yes bid at 0.36 is the same thing as a no offer at 0.64, which is why Kalshi only lists bids.

With recent trades on, `recentTrades` lists the latest trades, newest first: the time, the yes and no price, how many contracts, and which side the taker took.

The dataset has two views: Markets, and Temperature brackets, which puts the forecast beside each bracket.

Each run also leaves `RUN_REPORT` in its key-value store: what each search listed and returned, how many markets your filters set aside and why, how many brackets got a forecast, and why the run stopped.

### What you pay

Each market in your dataset is one charge, and the forecast, orderbook and trades come with it. Nothing else is charged: not the sample row, not markets your filters set aside, not a search Kalshi didn't answer, and not a market you already got from another of your searches. If you set a maximum charge for the run, it stops when that's reached, and every row you get has been paid for. The price is on the Pricing tab.

### Where the data comes from

Market data comes from Kalshi's public trade API. Kalshi sets its own terms for how its market data may be used, so read them before you republish or resell what you collect.

Forecasts come from [Open-Meteo](https://open-meteo.com), whose data is licensed under CC BY 4.0. Credit Open-Meteo if you publish them.

Station names and coordinates come from the US National Weather Service.

This actor isn't made by, endorsed by or connected to Kalshi.

### Questions

**How fresh are the prices?** As fresh as Kalshi's API when the run reads them; `fetchedAt` is on every row. The API can hand out a copy up to 15 seconds old.

**Why doesn't the forecast match the recorded temperature?** It's a forecast. It's also Open-Meteo's value for the grid square around the station, while the market settles on the station's own reading.

**How long does a run take?** A few seconds for a handful of cities, and about half a minute for all 24 with their forecasts.

**Why do some volumes have decimals?** Kalshi lets people trade fractions of a contract.

**Does it cover Polymarket?** No, only Kalshi.

# Actor input Schema

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

Leave it empty and the run returns open markets for the cities, categories or series you pick, and market or event tickers whatever their status. With nothing at all set, you get one sample row.

## `weatherCities` (type: `array`):

Kalshi's daily highest and lowest temperature markets in these cities, six brackets a day. Each bracket gets the forecast for the station the market settles on.

## `weatherKind` (type: `string`):

Which of the two temperature markets to fetch for each city.

## `addForecast` (type: `boolean`):

Next to each temperature bracket: the forecast high or low for that station and day from Open-Meteo, whether it falls inside the bracket, and by how many degrees it misses. Today and the next 15 days get a forecast; past days don't.

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

Kalshi's own categories. Every market in them comes back, subject to the status and filters.

## `tags` (type: `array`):

Kalshi's sub-categories, written the way Kalshi shows them, for example Daily temperature or Inflation. With categories set too, a series has to carry both.

## `seriesTickers` (type: `array`):

A series is the question Kalshi asks again and again, such as KXHIGHNY (highest temperature in New York) or KXFED. Every market in it comes back.

## `eventTickers` (type: `array`):

One occurrence of a series, such as KXHIGHNY-26SEP14. All of its markets come back.

## `marketTickers` (type: `array`):

Single markets, such as KXHIGHNY-26SEP14-B81.5.

## `keyword` (type: `string`):

Only markets whose title, bracket or event mentions this. Capitals don't matter.

## `closeFrom` (type: `string`):

Only markets whose trading closes on or after this day, UTC. For settled markets this reaches back past Kalshi's live window into its archive.

## `closeTo` (type: `string`):

Only markets whose trading closes on or before this day, UTC.

## `minVolume` (type: `integer`):

Only markets where at least this many contracts have traded since the market opened.

## `minVolume24h` (type: `integer`):

Only markets where at least this many contracts traded in the last 24 hours.

## `minOpenInterest` (type: `integer`):

Only markets with at least this many contracts still held.

## `combos` (type: `string`):

Kalshi generates combo markets, several outcomes bundled into one contract, in very large numbers. They're left out unless you ask. Market tickers you list come back either way.

## `includeOrderbook` (type: `boolean`):

The resting bids on the yes and no side of each market, best price first.

## `orderbookDepth` (type: `integer`):

How many price levels per side.

## `includeTrades` (type: `boolean`):

The latest trades of each market, newest first. This asks Kalshi once per market, so a run with trades stops at 2,000 markets.

## `tradesPerMarket` (type: `integer`):

How many of the latest trades per market.

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

The most markets returned in one run. Each market returned is one charge.

## Actor input object example

```json
{
  "status": "open",
  "weatherCities": [
    "New York City",
    "Chicago",
    "Miami"
  ],
  "weatherKind": "both",
  "addForecast": true,
  "combos": "exclude",
  "includeOrderbook": false,
  "orderbookDepth": 10,
  "includeTrades": false,
  "tradesPerMarket": 20,
  "maxMarkets": 100
}
```

# Actor output Schema

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

One row per Kalshi market: prices, volume, open interest, close time, status and result. Temperature brackets also carry the city, the day, the bracket in degrees and the forecast for that station.

## `report` (type: `string`):

What each search returned, rows skipped by your filters, forecast and orderbook counts, and why the run stopped.

# 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 = {
    "status": "open",
    "weatherCities": [
        "New York City",
        "Chicago",
        "Miami"
    ],
    "maxMarkets": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/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 = {
    "status": "open",
    "weatherCities": [
        "New York City",
        "Chicago",
        "Miami",
    ],
    "maxMarkets": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/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 '{
  "status": "open",
  "weatherCities": [
    "New York City",
    "Chicago",
    "Miami"
  ],
  "maxMarkets": 100
}' |
apify call dami_studio/kalshi-markets-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/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/vwSeSd0gMDgEjH4HJ/builds/MYqepGoEICmlYgJ9s/openapi.json
