# Kalshi & Polymarket Odds Scraper (No Login, No API Key) (`locaihost/prediction-markets`) Actor

Scrape Kalshi and Polymarket odds by keyword, topic or link: implied probability, 24-hour volume, liquidity, open interest, bid and ask, close time and result, plus price history and order book. The same question is matched across both venues with the gap. No login or API key. $1 per 1,000 markets.

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

## Pricing

from $0.55 / 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

## Kalshi & Polymarket Odds Scraper (No Login, No API Key)

Get market data from Kalshi and Polymarket in one table: the question, implied probability, volume, liquidity, open interest, best bid and ask, close time and result, with the same question matched across both venues, one row per market. No login, no API key, no wallet.

- **Compare the two venues:** see where Kalshi and Polymarket disagree on the same question, with the gap in points.
- **Track a topic over time:** schedule an hourly run that returns only the markets that moved, with the previous probability beside the new one.
- **Build a dataset for research:** pull every open market on a topic, or past results, with daily or hourly price history.
- **Feed dashboards and newsletters:** current probabilities for elections, Fed decisions, crypto prices or sports, refreshed on a schedule.
- **Watch new listings:** get only the markets on a topic that weren't there last time.

### Quick start

Paste this into the **JSON** tab of the input and click **Start**:

```json
{"searchTerms": ["fed decision"], "platforms": ["kalshi", "polymarket"], "maxItemsPerQuery": 10}
```

You get 20 rows (the 10 most traded Fed decision markets on each venue), usually in about 10 seconds, and the next meeting's options usually come back matched across venues ("Hike 0bps" on Kalshi next to "no change" on Polymarket).

An hourly watch that only returns markets that moved by 2 points or more:

```json
{"searchTerms": ["presidential nominee 2028"], "maxItemsPerQuery": 0, "onlyChanged": true, "minChangePoints": 2}
```

Every open market on a topic, with 30 days of daily prices:

```json
{"categories": ["Crypto"], "minVolume24h": 1000, "priceHistory": "day", "historyDays": 30}
```

### What data can I get?

Kalshi and Polymarket rows share the same columns:

| Group | Fields |
|---|---|
| The question | `platform`, `question`, `title`, `eventTitle`, `outcomeLabel`, `category`, `tags`, `rules`, `url` |
| Price | `probability`, `outcomes` (each outcome's price), `bid`, `ask`, `spread`, `bidSize`, `askSize`, `lastPrice`, `change24h` |
| Size | `volume24h`, `volume`, `volumeUnit` (contracts or usd), `liquidity` (Polymarket), `openInterest` |
| Time and result | `openTime`, `closeTime`, `status` (open, closed, resolved, upcoming), `resolution`, `resolvedAt` |
| Same question on both venues | `matchKey`, `matchConfidence`, `matchedWith` (the other venue's market and probability), `probabilityGap` |
| Extras | `history` (`[{t, p}]` with `priceHistory`), `orderBook` (best 5 levels with `includeOrderBook`), `previous` and `changeSinceLast` (with `onlyChanged`) |
| Ids | `marketId`, `eventId`, `seriesId`, and on Polymarket rows `slug`, `eventSlug`, `conditionId`, `tokenIds` (the order-book token per outcome) |
| Run | `sourceType` (search, category, top or link), `source`, `scrapedAt` |

One real row (run on 2026-10-18, shortened):

```json
{
  "platform": "kalshi",
  "question": "Will the Federal Reserve Hike rates by 0bps at their October 2026 meeting?",
  "probability": 0.865,
  "outcomes": [{"name": "Yes", "price": 0.865}, {"name": "No", "price": 0.135}],
  "eventTitle": "Fed decision in Oct 2026?",
  "outcomeLabel": "Fed maintains rate",
  "category": "Economics",
  "volume24h": 31504.63,
  "volume": 5664930.77,
  "volumeUnit": "contracts",
  "liquidity": null,
  "openInterest": 1810294.89,
  "bid": 0.86,
  "ask": 0.87,
  "spread": 0.01,
  "lastPrice": 0.87,
  "change24h": 0.01,
  "closeTime": "2026-10-28T17:59:00.000Z",
  "status": "open",
  "resolution": null,
  "matchKey": "m_1320560288f2",
  "matchConfidence": 1,
  "matchedWith": {
    "platform": "polymarket",
    "marketId": "2589812",
    "question": "Will there be no change in Fed interest rates after the October 2026 meeting?",
    "probability": 0.865
  },
  "probabilityGap": 0,
  "marketId": "KXFEDDECISION-26OCT-H0",
  "eventId": "KXFEDDECISION-26OCT",
  "seriesId": "KXFEDDECISION",
  "sourceType": "search",
  "source": "fed decision"
}
```

The dataset has five views (**Markets**, **Same question on both venues**, **Results**, **Moves since last run**, **Price history**) and exports to JSON, CSV, Excel or HTML. The run's `SUMMARY` record shows rows per venue, what each search found and anything skipped.

**How the numbers are read:**

- **Implied probability uses one rule for both venues:** the bid/ask midpoint while the spread is 10 points or less, otherwise the last trade. Resolved markets read 1 or 0.
- **Matching is strict on purpose.** Two markets share a `matchKey` only when they have the same subject, the same numbers, the same option and close dates within 3 days of each other. A wrong pair is worse than none, so near misses stay unmatched. Head-to-head games are lined up team by team.
- **Market-level data only.** Everything comes from each venue's public market-data endpoints, read logged out. No trader names, wallets, positions or comments are collected.

### How much does it cost?

You pay per market returned. There is no charge for Apify platform usage on top.

| Row | Free and Starter | Scale | Business |
|---|---|---|---|
| Market | $1 per 1,000 | $0.75 per 1,000 | $0.55 per 1,000 |

Plus $0.00005 per run start. **Apify's free $5 monthly credit covers about 5,000 markets.** Free-plan runs stop at 1,000 markets each; any paid Apify plan removes the cap. Price history and order books are included at no extra charge.

**What's free:** runs that find nothing, input mistakes, links that can't be found, markets skipped by `onlyNew` or `onlyChanged`, the same market found by two searches (charged once per run), markets your filters leave out, and markets found but not delivered before the run's time limit. To cap a run's spend, set **Maximum cost per run** in the run options, or use `maxResults`.

### Limits, stated up front

- **Units differ by venue.** Kalshi reports volume and open interest in contracts (each pays $1 if right), Polymarket in US dollars. `volumeUnit` says which.
- **Kalshi publishes no liquidity figure**, so `liquidity` is empty on Kalshi rows and `minLiquidity` only filters Polymarket.
- **Kalshi has no keyword search of its own.** The Actor searches Kalshi's series names, tags and categories, then keeps the markets whose wording contains every word. Short, specific words work best ("fed decision", "bitcoin", "nominee").
- **Matching covers what this run read.** Run both venues with the same search terms, or a big pull, to get matches. A pull of about 59,000 open markets matched 120 questions.
- **"Upcoming" markets exist on Kalshi only.** Resolved Kalshi markets older than its live window come from Kalshi's archive when you search, pick a category or give a series.
- **Price history:** hourly up to 31 days, daily up to 365.
- **Big pulls:** `maxItemsPerQuery: 0` with no search returns every open market on both venues, well over 50,000 rows. Keep the default 2 GB memory and set the run's maximum cost high enough. Kalshi lists many strike and parlay-style markets with no trading; use `minVolume24h` to keep only active ones. If the time limit is reached, the run stops cleanly and keeps what it found.
- **Probabilities are market prices, not forecasts.** Thin markets can show stale or wide prices; check `bid`, `ask` and `volume24h`. Nothing here is investment or betting advice.

### Only new since last run, and schedules

Two switches for scheduled runs, remembered per saved task (or per set of inputs):

- `onlyNew` returns only markets this setup has never returned, for example new listings on a topic.
- `onlyChanged` returns only markets whose probability moved by at least `minChangePoints`, whose status or result changed, or that are new to the setup. Each row then carries `previous` (the last probability and when) and `changeSinceLast`.

Skipped markets cost nothing. Set up a schedule under **Schedules** in Apify Console; hourly or daily works well with `onlyChanged`.

### Integrations: API, n8n, Make and AI agents

**API.** Run it and get the rows back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/locaihost~prediction-markets/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchTerms": ["fed decision"], "maxItemsPerQuery": 10}'
```

Apify's API clients for Python and JavaScript work the same way.

**n8n, Make, Zapier, Google Sheets, Slack, webhooks.** Apify's built-in integrations send each run's dataset wherever you need it, for example a Slack message whenever an `onlyChanged` run returns rows.

**AI agents (MCP).** Add this Actor to Claude, Cursor or any MCP client with `https://mcp.apify.com/?tools=locaihost/prediction-markets`, then ask something like *"What do Kalshi and Polymarket give for each option at the next Fed meeting, and where do they differ?"*

### FAQ

#### How much does it cost to scrape Kalshi and Polymarket?

$1 per 1,000 markets on the Free and Starter plans, $0.75 on Scale and $0.55 on Business, with price history and order books included. Apify's free $5 monthly credit covers about 5,000 markets.

#### Can I use it through the API or from Python?

Yes. Use the `run-sync-get-dataset-items` call above, or Apify's Python and JavaScript clients. Every run's data is also available as JSON, CSV or Excel from its dataset.

#### Can I use it from an AI agent?

Yes. Through the Apify MCP server (`https://mcp.apify.com/?tools=locaihost/prediction-markets`) any MCP client can call it with search terms, categories or links and read the rows back.

#### Is it legal to scrape Kalshi and Polymarket?

The Actor reads public market data that both venues serve to logged-out visitors, and only market-level fields: no trader names, wallets, positions or comments. Both venues' terms restrict redistribution of their data, so check them before you republish anything. You are responsible for how you use the data and for the laws that apply to you. If you are a venue and want something changed, open an issue and we will act on it promptly.

#### What can I put in "Market or event links / IDs"?

Links copied from kalshi.com or polymarket.com (a market, an event or a Kalshi series page), Kalshi tickers such as `KXFEDDECISION-26OCT`, Polymarket slugs, condition ids (0x...) or market ids. Links always return their markets whatever the filters, a series link lists every market in the series, and a link that can't be found is named in the status message and costs nothing.

#### Why are some fields empty?

`liquidity` is Polymarket-only, the order-book ids (`slug`, `conditionId`, `tokenIds`) exist only on Polymarket rows, `resolution` stays empty until a market settles, and `probability` is empty when a market has neither a two-sided quote nor a trade. Match fields are empty when the other venue has no market on the same question in this run.

### More from locaihost data

- [Google Trends Scraper](https://apify.com/locaihost/google-trends): search interest over time for the same topics people are trading on.
- [SEC EDGAR Scraper](https://apify.com/locaihost/sec-edgar): company financials, filings and insider trades.
- [YouTube Transcript Scraper](https://apify.com/locaihost/youtube-transcripts): transcripts of press conferences, speeches and debates behind the markets.

### Did it help?

If this saved you time, a quick rating on the Store helps other people find it.

### Support

Something not working, a missing field or a market that reads wrong? Open an issue on the **Issues** tab: we answer issues within 24 hours.

# Changelog

This Actor's version history is a separate document: https://apify.com/locaihost/prediction-markets/changelog.md

# Actor input Schema

## `searchTerms` (type: `array`):

Words to search for on each venue, e.g. "fed decision", "bitcoin", "election", "Ballon d'Or". Every word must appear in a market's wording. Leave empty (with no categories or links) to get each venue's most traded markets.

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

Which venues to read. Leave both on to get the same question matched across Kalshi and Polymarket. (Links below always go to the venue they belong to.)

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

Topics in either venue's words, e.g. Politics, Elections, Sports, Crypto, Economics, Finance, Tech, Weather, Culture, World. With search terms, they narrow the results; on their own, they list the topic's markets, most traded first.

## `markets` (type: `array`):

Links copied from kalshi.com or polymarket.com (a market, an event or a Kalshi series page), or bare ids: Kalshi tickers (KXFEDDECISION-26OCT, KXFEDDECISION-26OCT-H0), Polymarket slugs, condition ids (0x...) or market ids. Links always return their markets, whatever the filters below. A link that can't be found is listed in the status message and costs nothing.

## `status` (type: `array`):

Which markets to return. Open = trading now. Closed = trading ended, no result yet. Resolved = has a result (Kalshi's older results come from its archive when you search, pick a category or a series). Upcoming = listed, not trading yet (Kalshi only).

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

Skip markets that traded less than this in the last 24 hours (contracts on Kalshi, US dollars on Polymarket). 0 = no minimum.

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

Skip markets with less total volume than this (contracts on Kalshi, US dollars on Polymarket). 0 = no minimum.

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

Skip Polymarket markets with less liquidity than this. Kalshi publishes no liquidity figure, so Kalshi rows are not affected. 0 = no minimum.

## `maxItemsPerQuery` (type: `integer`):

How many markets to return for each search term, category or series, per venue, most traded first. 0 = all of them (every open market on both venues is well over 50,000 rows).

## `maxResults` (type: `integer`):

Stop after this many markets in total. 0 = no limit.

## `priceHistory` (type: `string`):

Add each market's past prices to its row as history\[] (time and probability). Hourly covers up to 31 days, daily up to 365.

## `historyDays` (type: `integer`):

How many days of price history to read.

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

Add the best five bids and asks (price and size, in Yes terms) to each row as orderBook. Every row already has the best bid and ask.

## `onlyNew` (type: `boolean`):

Return only markets this setup has never returned before, e.g. to catch newly listed markets on a topic. Remembered per saved task (or per set of inputs).

## `onlyChanged` (type: `boolean`):

Return (and pay for) only markets whose probability moved by at least the threshold below, whose status or result changed, or that are new to this setup. Each row then also has previous (last probability and when) and changeSinceLast. Ideal for an hourly or daily schedule.

## `minChangePoints` (type: `integer`):

For "Only markets that moved": the smallest move that counts, in percentage points (1 = from 42% to 43%).

## Actor input object example

```json
{
  "searchTerms": [
    "fed decision",
    "bitcoin",
    "presidential nominee 2028"
  ],
  "platforms": [
    "kalshi",
    "polymarket"
  ],
  "categories": [
    "Politics",
    "Crypto"
  ],
  "markets": [
    "https://kalshi.com/markets/kxfeddecision/fed-meeting/kxfeddecision-26oct",
    "https://polymarket.com/event/fed-decision-in-october"
  ],
  "status": [
    "open"
  ],
  "minVolume24h": 0,
  "minVolume": 0,
  "minLiquidity": 0,
  "maxItemsPerQuery": 10,
  "maxResults": 0,
  "priceHistory": "none",
  "historyDays": 7,
  "includeOrderBook": false,
  "onlyNew": false,
  "onlyChanged": false,
  "minChangePoints": 1
}
```

# Actor output Schema

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

One row per market: probability, volume, liquidity, close time, status and link.

## `matches` (type: `string`):

Markets matched across Kalshi and Polymarket, with the other venue's probability and the gap.

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

Rows per venue, what each search found, anything skipped and the run's cost.

# 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 = {
    "searchTerms": [
        "fed decision"
    ],
    "platforms": [
        "kalshi",
        "polymarket"
    ],
    "maxItemsPerQuery": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("locaihost/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 = {
    "searchTerms": ["fed decision"],
    "platforms": [
        "kalshi",
        "polymarket",
    ],
    "maxItemsPerQuery": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("locaihost/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 '{
  "searchTerms": [
    "fed decision"
  ],
  "platforms": [
    "kalshi",
    "polymarket"
  ],
  "maxItemsPerQuery": 10
}' |
apify call locaihost/prediction-markets --silent --output-dataset

```

## MCP server setup

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