# Kalshi & Polymarket Scraper - Odds, Results & Price History (`artsiom_k/prediction-markets-scraper`) Actor

Prediction market data from Kalshi and Polymarket in one row shape: live probabilities, bid/ask, volume and open interest, settled results, and price history candles. Sports (NFL, NBA, MLB, NHL, college, soccer, UFC, tennis, F1, golf, esports), politics, economics, crypto, weather and more.

- **URL**: https://apify.com/artsiom_k/prediction-markets-scraper.md
- **Developed by:** [Artsiom Kunitsyn](https://apify.com/artsiom_k) (community)
- **Categories:** Other, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 results

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

## Kalshi & Polymarket Scraper - Odds, Results & Price History

Prediction market data from [Kalshi](https://kalshi.com) and [Polymarket](https://polymarket.com), the two biggest
prediction markets, in **one row shape**:

- **Open markets**: the current probability, best bid and ask, last trade, volume, 24-hour volume, open interest and
  liquidity.
- **Results**: settled markets with the winning outcome, settlement price and settle time. Kalshi results go back to
  the start of each series (NFL games: September 2025), and Polymarket sports back to 2023.
- **Price history**: hourly, daily or minute data per market. Kalshi gives candles (open/high/low/close trade price,
  bid/ask, volume, open interest); Polymarket gives the price per interval.

**Sports** are covered in depth: NFL, college football, NBA, WNBA, college basketball, MLB, NHL, the Premier League,
Champions League, La Liga, Bundesliga, Serie A, Ligue 1, MLS, Liga MX, UFC, boxing, ATP/WTA tennis, F1, NASCAR, PGA
golf, cricket and esports. That includes moneylines, spreads, totals, player and period props, and futures. **Every
other category** works too: politics, elections, economics (Fed, inflation, jobs), finance, crypto, weather, culture,
tech and world events.

Prediction market prices are real-money probabilities. Use them next to sportsbook lines, to measure closing-line
value, to find differences between Kalshi and Polymarket, or to track elections, Fed decisions and the weather.

### What you get

One row per market. On Kalshi a market is one yes/no contract (e.g. "Philadelphia wins"), so a game has a row per
team; on Polymarket a game moneyline is one market with both teams as outcomes.

| Field | Example |
|---|---|
| `platform`, `event_title`, `market_title` | `polymarket`, `Seahawks vs. Broncos`, `Seahawks vs. Broncos` |
| `category`, `league`, `competition` | `sports`, `nfl`, `NFL 2026` |
| `market_type`, `market_type_raw`, `line` | `spread`, `spreads`, `-3.5` |
| `outcome`, `outcomes`, `outcome_prices` | `Seahawks`, `["Seahawks", "Broncos"]`, `[0.565, 0.435]` |
| `price`, `best_bid`, `best_ask`, `last_price` | `0.565`, `0.56`, `0.57`, `0.56` |
| `volume`, `volume_24h`, `open_interest`, `liquidity` | `1437982.78`, `52110.4`, `744.3`, `20345.1` |
| `status`, `result`, `winning_outcome`, `settlement_price` | `settled`, `no`, `Bears`, `0` |
| `event_time`, `open_time`, `close_time`, `settled_at` | `2026-10-04T17:00:00Z`, ... |
| `teams`, `score` (Polymarket games) | `["New York Jets", "Chicago Bears"]`, `12-23` |
| `url`, `rules` | the event page and the resolution rules |

- `price` is the probability (0 to 1) of `outcome`. For an open Kalshi market it is the bid/ask midpoint, and for a
  Polymarket market the price the site displays.
- `result` is `yes` or `no` for `outcome`. `winning_outcome` names the winning entry of `outcomes`.
- `market_type` is `moneyline` (full-game winner), `spread`, `total`, `props` (player props, period winners, both
  teams to score and other game markets) or `futures` (season, awards, tournaments). It is empty outside sports.
  `spread` and `total` include half, quarter and team lines; `market_type_raw` tells them apart (e.g.
  `first_half_spreads`, `team_totals`, `1st Half Spread`).
- `volume` is in $1 contracts on Kalshi and in USD on Polymarket.

#### Price history rows

`entityType: "priceHistory"` returns one row per interval per market: `ts`, `price`, and on Kalshi `open`, `high`,
`low`, `mean`, `best_bid`, `best_ask`, `volume` and `open_interest`, plus the market fields (event, outcome, league,
status, result). `price_source` tells whether a Kalshi interval had a trade (`trade`) or only a quote (`quote_mid`).

### How to use it

- **Current odds for upcoming games** (the default): just run it. Sports from both sites, 50 rows.
- **This week's NFL moneylines and spreads on both sites**: leagues `NFL`, market types `Moneyline` and `Spread`,
  clear **Max items**.
- **Yesterday's results**: `entityType: "results"`, set **From date** and **To date** to yesterday.
- **A whole season of results**: `entityType: "results"`, leagues `NBA`, market types `Moneyline`, From date
  `2025-10-01`, To date `2026-06-30`.
- **Closing-line analysis**: `entityType: "priceHistory"`, leagues `NFL`, market types `Moneyline`,
  `historyLastHours: 24`, a date range.
- **One game or market**: paste the Kalshi or Polymarket URL into **Event IDs or URLs**.
- **Politics, Fed or weather markets**: set **Categories** (and clear the default `Sports`), optionally with
  **Search** (e.g. `Fed`, `New York`).
- **A daily feed of newly settled markets**: `entityType: "results"`, `mode: "incremental"`, scheduled daily. Each run
  returns only what earlier incremental runs with the same filters have not.

### Input

| Field | What it does |
|---|---|
| `platforms` | `kalshi`, `polymarket` or both (default). With both, `maxItems` is split between them. |
| `entityType` | `markets` (open), `results` (settled) or `priceHistory`. |
| `categories` | Sports (default), politics, elections, economics, finance, crypto, weather, culture, tech, world. Empty = all. |
| `leagues` | 27 leagues plus "all" entries per sport (soccer, basketball, hockey, baseball, tennis, golf, MMA, cricket, esports). |
| `marketTypes` | Sports only: moneyline, spread, total, props, futures. |
| `search` | Every word must appear in the event, market or outcome text. |
| `dateFrom`, `dateTo` | Results: settle date (default the last 7 days). Open markets: event start date. |
| `minVolume` | Skip markets with less traded volume. |
| `eventIds` | Kalshi event tickers/URLs and Polymarket event slugs/URLs; every market of each event. |
| `marketStatus` | Price history of `settled` (default) or `open` markets. |
| `historyInterval`, `historyLastHours` | `minute`, `hour` (default) or `day`; optionally only the last N hours. |
| `mode` | `full` or `incremental` (results only). |
| `maxItems` | Row cap, 50 by default. Clear it for everything. |

### Good to know

- **No login, no proxy.** Both sites have public APIs; the actor reads them at about 10 requests per second each.
- **Kalshi results older than about two months** come from Kalshi's archive, which is read series by series. Setting
  `leagues` and `marketTypes` keeps that fast (a whole NBA season of moneylines on both sites: about 3 minutes);
  all sports without leagues reads about 4,000 series.
- **A Polymarket NFL game has about 300 markets** (spreads and totals for every quarter and half, team totals, props).
  `marketTypes: ["moneyline"]` keeps one market per game; spreads and totals bring every alternate and period line.
- **Price history size**: one market's hourly history over two weeks is about 300 rows. Use `historyLastHours` or
  `day` to keep it small.
- Polymarket's minute data is fetched in 3-day windows. Over a whole market life, `interval: minute` without
  `historyLastHours` makes many requests.
- Polymarket trade-level data is not collected: it carries trader wallet addresses and usernames.

### FAQ

**Why does a Kalshi game have two rows?** Kalshi lists each team as its own yes/no contract ("Philadelphia wins",
"Dallas wins"). Polymarket lists one market with both teams.

**How do I compare Kalshi and Polymarket on the same game?** Run both platforms with the same league and market type,
then match on teams and `event_time`.

**What is `open_interest`?** The number of Kalshi contracts still held. Polymarket reports it per event, not per
market, so it is empty there.

**Can I get trades?** Kalshi candles include per-interval volume. Individual trades are not collected.

### Related sports data scrapers

- [Action Network Scraper](https://apify.com/artsiom_k/actionnetwork-scraper) — US sportsbook odds, public betting splits, line movement, props, injuries and futures.
- [Smarkets Scraper](https://apify.com/artsiom_k/smarkets-scraper) — betting exchange back/lay odds, results and traded-price history.
- [Sports Odds History Scraper](https://apify.com/artsiom_k/sports-odds-history-scraper) — opening and closing lines per sportsbook since 2021 and ATS results since 2006.
- [PGA Tour Scraper](https://apify.com/artsiom_k/pgatour-scraper) — golf results, scorecards, odds, tee times and stats.
- [TennisExplorer Scraper](https://apify.com/artsiom_k/tennisexplorer-scraper) — tennis results back to the 1990s, bookmaker odds per match, match statistics and point-by-point.
- [SofaScore Scraper](https://apify.com/artsiom_k/sofascore-scraper) — results, team statistics, lineups with player ratings, incidents and odds for football, basketball, hockey, tennis and 17 more sports.
- [Flashscore Scraper](https://apify.com/artsiom_k/flashscore-scraper) — results, statistics, lineups, incidents and opening/closing odds from ~20 bookmakers for 17 sports.

# Actor input Schema

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

Which sites to read. With both, maxItems is shared: Kalshi gets half (rounded up), Polymarket the rest.

## `entityType` (type: `string`):

"markets": open markets with the current probability, bid/ask, last trade, volume and open interest. "results": settled markets with the winning outcome (default window: the last 7 days; set a From date for older). "priceHistory": the price over time for each matching market (see Price history of and History interval).

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

Market categories. Leave empty for every category. Ignored when leagues are set.

## `leagues` (type: `array`):

Only these leagues (games, props and futures). The "(all ...)" entries cover every league of that sport. Empty = every market in the chosen categories.

## `marketTypes` (type: `array`):

Only these sports market types. Non-sports markets are not affected. Empty = all.

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

Only markets whose event, market or outcome text contains every word, e.g. "Chiefs" or "bitcoin".

## `dateFrom` (type: `string`):

Results and settled price history: settled on or after this date (default: 7 days ago). Open markets: events starting on or after this date. Kalshi history starts with each series (NFL games: September 2025); Polymarket sports go back to 2023.

## `dateTo` (type: `string`):

Upper bound for the same date as From date (inclusive).

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

Skip markets that traded less than this (Kalshi: $1 contracts; Polymarket: USD). Drops empty markets.

## `eventIds` (type: `array`):

Scrape just these events instead of a listing: Kalshi event tickers (KXNFLGAME-26OCT26DALPHI) or kalshi.com market URLs, Polymarket event slugs (nfl-sea-den-2026-10-16) or polymarket.com event URLs. Every market of each event is returned, whatever its status.

## `marketStatus` (type: `string`):

Price history only: read the history of settled or of open markets.

## `historyInterval` (type: `string`):

Price history only. Kalshi returns candles (open/high/low/close, bid/ask, volume, open interest); Polymarket returns one price per interval.

## `historyLastHours` (type: `integer`):

Price history only: keep just the last N hours before the market closed (or before now, for open markets). Empty = the whole market life.

## `mode` (type: `string`):

Results only. "incremental" remembers what earlier incremental runs with the same filters returned and skips it, so a daily schedule gets only newly settled markets.

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

Stop after this many rows. Clear it for everything (a whole listing can be hundreds of thousands of rows).

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

Not needed: both APIs are public. Available in case one starts limiting a shared IP.

## Actor input object example

```json
{
  "platforms": [
    "kalshi",
    "polymarket"
  ],
  "entityType": "markets",
  "categories": [
    "sports"
  ],
  "marketStatus": "settled",
  "historyInterval": "hour",
  "mode": "full",
  "maxItems": 50
}
```

# Actor output Schema

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

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

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

```

## MCP server setup

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