# Prediction Markets Scraper – Kalshi + Polymarket Odds & Prices (`gratified_ashram/prediction-markets-scraper`) Actor

Kalshi and Polymarket prediction markets in one normalized table: question, yes/no price, bid/ask, volume, liquidity, close time, result. Politics, sports, crypto, economics and Kalshi weather markets (KXHIGH/KXLOW daily temperature). Public APIs, no login. Pay only for records delivered.

- **URL**: https://apify.com/gratified\_ashram/prediction-markets-scraper.md
- **Developed by:** [Tit Slobodjanac](https://apify.com/gratified_ashram) (community)
- **Categories:** Developer tools, News, Sports
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 market records

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

## Prediction Markets Scraper — Kalshi + Polymarket in one table

Pull **live odds and settled results from Kalshi and Polymarket** into one normalized dataset: question, yes/no price, best bid and ask, spread, volume, 24-hour volume, liquidity, open interest, open/close time, result and a link to the market. Filter by keyword, category, Kalshi series or Polymarket tag. Optional order-book depth.

**No Kalshi account, no Polymarket wallet, no API key.** Data comes straight from both exchanges' **public JSON APIs** (Kalshi trade API v2, Polymarket Gamma + CLOB). No login, no cookies, no browser, no proxies — which is why it is fast and why runs do not fail.

### Why this one

- **It works every run.** No headless browser and no scraping of HTML that changes. The only failure mode is an exchange API outage, and then the run fails loudly instead of returning an empty dataset.
- **One schema for both exchanges.** A Kalshi contract and a Polymarket market come back with the same field names, so you can join, compare and spot price gaps without mapping two formats.
- **Real markets, not parlay noise.** Kalshi lists thousands of auto-generated multi-leg combinations (`KXMVE…`). They are excluded by default; flip `excludeMultiLeg` if you want them.
- **Pay only for records you receive.** $1 per 1,000 market records. Nothing for a run that returns nothing.

### What people use it for

- **Arbitrage and cross-exchange comparison** — same event, two prices, one table.
- **Trading research and backtests** — settled markets with results and close times, pulled daily on a schedule.
- **Dashboards and newsletters** — top markets by 24-hour volume in politics, sports, crypto, economics, commodities, weather.
- **Weather markets** — every Kalshi daily high/low (`KXHIGH*`, `KXLOW*`) and hourly (`KXTEMP*`) temperature bracket for 50+ cities; pair with the [Kalshi Weather Index](https://apify.com/gratified_ashram/kalshi-weather-index) actor for the settlement series itself.
- **Alerts** — schedule hourly, compare `yesPrice` with the previous run, push a Slack/Discord message through an Apify integration when a market moves.
- **AI agents** — ask "what does the market think about X?" and get numbers, not vibes.

### Input

```json
{
  "platforms": ["kalshi", "polymarket"],
  "status": "open",
  "keywords": ["fed", "bitcoin"],
  "categories": ["economics", "crypto"],
  "minVolume": 1000,
  "maxItems": 500,
  "includeOrderbook": false
}
```

| Field | What it does |
|---|---|
| `platforms` | `kalshi`, `polymarket` or both (default both). |
| `status` | `open` (live prices), `settled` (results) or `both`. |
| `keywords` | Keep markets whose question, event title or ticker contains any keyword. |
| `categories` | Keep markets whose category/tag contains any word: politics, sports, crypto, economics, weather, entertainment, science, companies, world… |
| `minVolume`, `minLiquidity` | Drop thin or toy markets. |
| `maxItems` | Cost cap. Default 500. |
| `includeOrderbook` | Attach top 10 levels per market (+$1 per 1,000, one extra call per market). |
| `lookbackDays` | For settled Kalshi markets: how far back by close time (default 7). |
| `excludeMultiLeg` | Hide Kalshi parlay combinations (default on). |
| `kalshiSeriesTickers` | Exact tickers (`KXBTC`, `KXFED`, `KXNBA`) or prefixes with `*`: `KXHIGH*` = every daily-high temperature city, `KXLOW*` = every daily-low city (pair with `categories: ["weather"]` to skip the Lowe's earnings series `KXLOW`). |
| `polymarketTagIds` | Raw tag IDs from `gamma-api.polymarket.com/tags` when you need a precise tag. |
| `language` | `en`, `es` or `pt`: Kalshi market titles and rules in Spanish or Portuguese. |
| `archiveDatasetName` | Also append every record to a named dataset in your account. Schedule the run and the dataset becomes a price and settlement history that outlives Kalshi's ~68-day API window. No extra charge. |

A `categories` filter on Kalshi now scans exactly the series in that category (weather → 367 series, commodities → 81), so small categories are never missed. Very large categories (sports, ~3,600 series) fall back to the generic scan; add `kalshiSeriesTickers` such as `KXNBA*` to narrow.

### Output

One row per market:

```json
{
  "platform": "polymarket",
  "id": "4000248",
  "ticker": "lol-hle1-t1-2026-09-02",
  "question": "LoL: Hanwha Life Esports vs T1 (BO5) - LCK Playoffs",
  "eventTitle": "LoL: Hanwha Life Esports vs T1 (BO5) - LCK Playoffs",
  "category": "Esports",
  "status": "open",
  "outcomes": ["Hanwha Life Esports", "T1"],
  "outcomePrices": [0.565, 0.435],
  "yesPrice": 0.565,
  "noPrice": 0.435,
  "yesBid": 0.56,
  "yesAsk": 0.57,
  "lastPrice": 0.56,
  "spread": 0.01,
  "volume": 2009194.56,
  "volume24h": 1926235.0,
  "liquidity": 79729.05,
  "openInterest": 4529841.49,
  "priceChange1h": 0.22,
  "priceChange24h": -0.08,
  "openTime": "2026-08-30T12:20:38Z",
  "closeTime": "2026-09-02T14:00:00Z",
  "result": null,
  "url": "https://polymarket.com/event/lol-hle1-t1-2026-09-02/lol-hle1-t1-2026-09-02",
  "fetchedAt": "2026-09-02T11:50:00.000Z"
}
```

Kalshi rows carry the same fields plus `noBid` / `noAsk`, `eventId` (event ticker) and `seriesId` (series ticker). Prices are in dollars per contract (0–1). `result` is `yes`/`no` on Kalshi and the winning outcome name on Polymarket. With `includeOrderbook` an `orderbook` object is added: `{ yesBids: [{price,size}…], noBids | yesAsks: […] }`.

### Run it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/gratified_ashram~prediction-markets-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"platforms":["kalshi","polymarket"],"categories":["politics"],"maxItems":200}'
```

Works the same from the Apify JavaScript/Python clients, Make, Zapier, n8n, or on a schedule in the Console.

### FAQ

**Do I need a Kalshi or Polymarket account?** No. Both expose public market-data APIs; nothing here trades or logs in.

**How fresh are the prices?** As fresh as the exchange API at the moment of the run — typically seconds. Schedule the run as often as you like.

**Can I get historical price series?** Kalshi's API only serves roughly the last 68 days of settlements and no price history; Polymarket serves resolved markets at coarse granularity. Set `archiveDatasetName` and schedule the run (hourly for prices, daily for settlements): every run appends to one dataset in your account, and after 68 days you hold data the API no longer has. Runs by the maintainer have been archiving Kalshi weather, politics and sports since September 2026; open an issue if you need a slice of that.

**Why is Kalshi's category sometimes empty?** Categories come from the series list; a brand-new series may not be in it yet.

### Pricing

**$1.00 per 1,000 market records**, plus $1.00 per 1,000 order books when you ask for depth. Platform usage is included. A run that returns no records costs nothing.

***

**Found it useful?** A short review on the Actor page helps others find it. Missing a field or an exchange? Open an issue on the Issues tab.

# Actor input Schema

## `platforms` (type: `array`):

Which exchanges to pull from. Both by default.

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

Open = currently tradeable markets with live prices. Settled = resolved markets with results (Kalshi: within the lookback window; Polymarket: most recently ended first). Both = open then settled.

## `keywords` (type: `array`):

Keep only markets whose question, event title or ticker contains any of these words (case-insensitive). Empty = keep everything.

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

Keep only markets whose category or tag contains any of these words, e.g. politics, sports, crypto, economics, weather, entertainment, science. Matches Kalshi categories and Polymarket tags.

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

Drop markets with less lifetime volume than this. Useful to skip toy markets.

## `minLiquidity` (type: `integer`):

Drop markets with thinner books than this.

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

Hard cap on records pushed to the dataset per run. Controls cost: 1,000 records = $1.

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

Adds the top 10 bid/ask levels per market (one extra API call per market, slower, +$1 per 1,000). Kalshi: yes and no bids. Polymarket: yes-token bids and asks.

## `lookbackDays` (type: `integer`):

For status = settled/both: how many days back of Kalshi settlements to pull (by close time). 1–365.

## `excludeMultiLeg` (type: `boolean`):

Kalshi lists thousands of auto-generated parlay combinations (KXMVE…). They are excluded by default because they drown out real markets.

## `kalshiSeriesTickers` (type: `array`):

Restrict Kalshi to specific series. Exact tickers (KXBTC, KXFED, KXNBA) or a prefix with a trailing \* that expands to every matching series: KXHIGH\* = all daily-high temperature cities, KXLOW\* = all daily-low cities (add category "weather" to exclude the Lowe's earnings series KXLOW). Empty = all series.

## `polymarketTagIds` (type: `array`):

Restrict Polymarket to tag IDs from https://gamma-api.polymarket.com/tags (e.g. 2 = politics, 100639 = crypto). Empty = all markets, sorted by 24h volume. Prefer the Categories filter above unless you need a precise tag.

## `language` (type: `string`):

Kalshi serves market titles and rules in Spanish or Portuguese as well as English. Polymarket is English only.

## `archiveDatasetName` (type: `string`):

Also append every record to a named dataset in your account (e.g. kalshi-weather-history). Run on a schedule and the dataset becomes a price and settlement history that outlives Kalshi's ~68-day API window. No extra charge; the dataset is yours.

## `archiveOnly` (type: `boolean`):

With an archive dataset set: write only to the archive, not to this run's dataset. Halves storage writes on scheduled runs. Records are still charged.

## Actor input object example

```json
{
  "platforms": [
    "kalshi",
    "polymarket"
  ],
  "status": "open",
  "keywords": [],
  "categories": [],
  "minVolume": 0,
  "minLiquidity": 0,
  "maxItems": 500,
  "includeOrderbook": false,
  "lookbackDays": 7,
  "excludeMultiLeg": true,
  "kalshiSeriesTickers": [],
  "polymarketTagIds": [],
  "language": "en",
  "archiveOnly": false
}
```

# Actor output Schema

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

One row per prediction market with normalized price, volume, liquidity, close time and result fields.

## `summary` (type: `string`):

Counts of records pushed, scanned, per platform, and any platform errors.

# 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 = {
    "platforms": [
        "kalshi",
        "polymarket"
    ],
    "keywords": [],
    "categories": [],
    "kalshiSeriesTickers": [],
    "polymarketTagIds": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("gratified_ashram/prediction-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 = {
    "platforms": [
        "kalshi",
        "polymarket",
    ],
    "keywords": [],
    "categories": [],
    "kalshiSeriesTickers": [],
    "polymarketTagIds": [],
}

# Run the Actor and wait for it to finish
run = client.actor("gratified_ashram/prediction-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 '{
  "platforms": [
    "kalshi",
    "polymarket"
  ],
  "keywords": [],
  "categories": [],
  "kalshiSeriesTickers": [],
  "polymarketTagIds": []
}' |
apify call gratified_ashram/prediction-markets-scraper --silent --output-dataset

```

## MCP server setup

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