# Polymarket & Kalshi Scraper - Odds, Markets & Arbitrage (`scrapesage/prediction-markets-scraper`) Actor

Scrape Polymarket & Kalshi prediction markets: live odds & implied probability, 24h/weekly volume, liquidity, order flow (trades), top holders, wallet P\&L, price history, and cross-platform arbitrage. Keyless, no browser. Monitor mode tracks odds moves and new markets. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/scrapesage/prediction-markets-scraper.md
- **Developed by:** [Scrape Sage](https://apify.com/scrapesage) (community)
- **Categories:** Developer tools, Automation, AI
- **Stats:** 5 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 market scrapeds

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/platform/actors/running/actors-in-store#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

## Polymarket & Kalshi Scraper — Live Odds, Markets, Order Flow & Arbitrage

Extract **complete prediction-market data from [Polymarket](https://polymarket.com) and [Kalshi](https://kalshi.com)** in one actor — live **odds and implied probability** for every outcome, **24h/weekly/monthly volume**, liquidity, **order flow (trades)**, **top holders (smart money)**, **wallet P\&L**, full **price-history time-series**, and **cross-platform arbitrage** that flags the same question priced differently on each venue.

No login, no API key, no browser — fast, reliable extraction straight from each platform's public data API. A **monitor mode** tracks odds moves and new markets so you can pull *only* what changed between runs.

### Why this prediction-markets scraper?

Most scrapers cover a single platform and a handful of fields. This actor reads Polymarket's Gamma, CLOB and Data APIs **and** Kalshi's public market API, ships the **richest record in the category** (60+ fields per market), and is the only one that **matches Polymarket against Kalshi to surface arbitrage**.

| Data | Typical scrapers | This actor |
|---|---|---|
| Polymarket markets & events | ✅ | ✅ |
| **Kalshi markets** (same schema) | ❌ | ✅ |
| Live odds + **implied probability** per outcome | partial | ✅ |
| 24h / 7d / 30d / total volume + liquidity | partial | ✅ |
| Best bid / ask / spread + 1d/1w/1m price change | ❌ | ✅ |
| **Price-history time-series** (chart data) | ❌ | ✅ |
| **Trades / order flow** (by market or wallet) | ❌ | ✅ |
| **Top holders** (whale / smart-money positions) | ❌ | ✅ |
| **Wallet profiles** (positions, value, realized/unrealized P\&L) | ❌ | ✅ |
| **Cross-platform arbitrage** (Polymarket ⇄ Kalshi) | ❌ | ✅ |
| **Monitor mode** — only new / changed odds | ❌ | ✅ |
| Keyless, no browser | — | ✅ |

### Use cases

- **Quant & trading research** — pull live odds, spreads and history across both venues to backtest signals, build dashboards, or feed a model.
- **Odds & price monitoring** — schedule the actor and use monitor mode to get alerted only when a market is new, its odds move, its volume spikes, or it resolves.
- **Arbitrage detection** — find the same question priced differently on Polymarket vs Kalshi, with the spread and a theoretical risk-free return.
- **Smart-money tracking** — surface the largest holders in a market and profile any wallet's positions and P\&L.
- **News, politics & forecasting** — prediction markets are real-time, money-weighted forecasts for elections, the economy, crypto, sports and tech. Power newsletters, research and AI agents with structured forecast data.
- **AI agents** — clean, LLM-ready JSON for any agent that needs "what does the market think will happen?"

### How to use

1. [Sign up for Apify](https://console.apify.com/sign-up) — the free plan is enough to try this actor.
2. Open the **Polymarket & Kalshi Scraper**, pick a **mode** (Markets by default), and optionally add a `query` (e.g. `election`, `bitcoin`, `fed rate`) or category `tagSlugs` (e.g. `politics`, `crypto`, `sports`).
3. Click **Start** and watch results stream into the dataset table.
4. **Export** as JSON, CSV, Excel, XML or RSS — or pull results programmatically via the [Apify API](https://docs.apify.com/api/v2).

### Input

```json
{
    "mode": "markets",
    "query": "election",
    "tagSlugs": ["politics"],
    "status": "active",
    "sortBy": "volume24hr",
    "maxItems": 100,
    "includePriceHistory": false,
    "monitorMode": false
}
```

Common fields:

- **mode** *(default `markets`)* — `markets`, `events`, `kalshi`, `priceHistory`, `trades`, `holders`, `wallet`, or `arbitrage`.
- **query** — keyword search across Polymarket markets/events. Empty = the top markets by volume.
- **tagSlugs** — Polymarket category slugs (`politics`, `crypto`, `sports`, `economy`, `elections`, `geopolitics`, `tech`, `pop-culture`…).
- **startUrls** — Polymarket event/market URLs, bare slugs, Kalshi URLs or tickers — each fetched directly.
- **status** *(default `active`)* — `active`, `closed`, or `all`.
- **sortBy** *(default `volume24hr`)* — `volume24hr`, `volume`, `liquidity`, `volume1wk`, `competitive`, `startDate`, `endDate`.
- **conditionIds / marketSlugs / eventSlugs** — target exact Polymarket markets/events (used by Trades, Holders, Price-history).
- **walletAddresses** — `0x…` wallets for Wallet mode (P\&L) or Trades-by-wallet.
- **kalshiTickers / kalshiSeriesTickers** — target exact Kalshi markets or whole series.
- **includePriceHistory / includeTopHolders / includeRecentTrades** — enrich each market in Markets mode (bundled into the record at no extra charge).
- **monitorMode** *(default false)* — emit only new / changed records between runs (see below).
- **maxItems** *(default 100, 0 = no cap)*, **minVolume24h**, **minLiquidity**, **maxConcurrency**, **proxyConfiguration**.

### Output

Every row carries a `platform` (`polymarket` / `kalshi`) and a `type` (`market`, `event`, `priceHistory`, `trade`, `holder`, `wallet`, `arbitrage`). Use the dataset **views** (Markets / Events / Trades / Holders / Wallets / Price history / Arbitrage) for clean, dense tables.

A market record (`type: "market"`):

```json
{
    "platform": "polymarket",
    "type": "market",
    "question": "Will the Fed cut rates in July?",
    "slug": "fed-decision-in-july",
    "conditionId": "0xd86a816093fcd0a0e1ca440bc5ce199bd3c5a8d6139e044b076958164f8c5423",
    "category": "Economy",
    "outcomes": ["Yes", "No"],
    "yesPrice": 0.18,
    "impliedProbabilityPct": 18.0,
    "odds": [
        { "outcome": "Yes", "price": 0.18, "impliedProbabilityPct": 18.0, "clobTokenId": "5904…078" },
        { "outcome": "No", "price": 0.82, "impliedProbabilityPct": 82.0, "clobTokenId": "5985…551" }
    ],
    "lastTradePrice": 0.18, "bestBid": 0.18, "bestAsk": 0.19, "spread": 0.01,
    "oneDayPriceChange": -0.03,
    "volume24hr": 1924034.84, "volumeNum": 91275371.43, "liquidityNum": 2461957.42,
    "startDate": "2026-06-01T00:00:00.000Z", "endDate": "2026-07-31T00:00:00.000Z",
    "status": "active",
    "url": "https://polymarket.com/event/fed-decision-in-july",
    "scrapedAt": "2026-06-17T12:00:00.000Z"
}
```

A **Kalshi** market uses the same schema (prices are 0–1 probabilities; `volume24hr`/`openInterest` are in contracts). Other record types: **priceHistory** (`history` array of `{t, timestamp, p}` plus first/last/min/max/change), **trade** (wallet, side, outcome, size, price, USD value, time), **holder** (wallet, trader name, outcome, shares), **wallet** (portfolio value + positions with P\&L), **arbitrage** (matched question, `polymarketYes`, `kalshiYes`, `spread`, `guaranteedReturnPct`, best strategy).

#### What to expect (field coverage)

| Field group | Notes |
|---|---|
| Odds, prices, volume, liquidity, dates, status | Always present when the platform exposes them |
| `category` / `tags` | Always on Kalshi & Polymarket **events**; on Polymarket **markets** when the listing exposes it |
| `priceHistory` / `topHolders` / `recentTrades` | Only when you enable the matching enrichment toggle |
| `conditionId` | Polymarket only (Kalshi uses `ticker`) |

A blank field means the platform didn't expose that value for that record — nothing is dropped, so you always get the richest dataset available.

### Monitor mode & scheduling

**Monitor mode and Apify Schedules work together — they don't conflict.** Apify's [Schedules](https://docs.apify.com/platform/schedules) decide *when* the actor runs; monitor mode decides *what* each run emits.

- Turn on **monitorMode** and the actor remembers a fingerprint of every market in a named key-value store. On the next run it emits **only** markets that are new, whose odds moved (by at least `monitorMinOddsChange`), whose 24h volume spiked, or that changed status / resolved — each tagged with a `changeType`.
- Pair it with a [Schedule](https://docs.apify.com/platform/schedules) (e.g. every 15 minutes or hourly) and a [webhook](https://docs.apify.com/platform/integrations/webhooks) to push odds alerts into Slack, a CRM, or your own pipeline.
- Leave monitorMode off for a full snapshot every run.

### Automate & integrate

Run on autopilot and pull results into your own stack:

- **[Apify API](https://docs.apify.com/api/v2)** — start runs, fetch datasets, manage schedules over REST.
- **[apify-client for JavaScript](https://docs.apify.com/api/client/js/)** and **[Python](https://docs.apify.com/api/client/python/)** — official SDKs.
- **[Schedules](https://docs.apify.com/platform/schedules)** — run it on any cron to track odds over time.
- **[Webhooks](https://docs.apify.com/platform/integrations/webhooks)** — trigger downstream actions the moment a run finishes.

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'MY_APIFY_TOKEN' });

const run = await client.actor('scrapesage/prediction-markets-scraper').call({
    mode: 'markets',
    query: 'election',
    status: 'active',
    maxItems: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Got ${items.length} markets`);
```

Connect the dataset to 5,000+ apps — no code required:

- **[Make](https://docs.apify.com/platform/integrations/make)** — multi-step automation scenarios.
- **[Zapier](https://docs.apify.com/platform/integrations/zapier)** — push odds moves straight into your tools.
- **[Slack](https://docs.apify.com/platform/integrations/slack)** — get alerted when a monitored market moves or resolves.
- **[Google Drive / Sheets](https://docs.apify.com/platform/integrations/drive)** — auto-export every run to a spreadsheet.
- **[Airbyte](https://docs.apify.com/platform/integrations/airbyte)** — pipe results into your data warehouse.
- **[GitHub](https://docs.apify.com/platform/integrations/github)** — trigger runs from commits or releases.

### Use with AI assistants (MCP)

The output is clean, LLM-ready JSON. Call this actor from Claude, ChatGPT, or any agent framework through the **[Apify MCP server](https://docs.apify.com/platform/integrations/mcp)** — ask your assistant to "show me the top political markets on Polymarket and Kalshi with their odds" and let it run the scraper for you.

### Agent-ready: autonomous payments (x402 & Skyfire)

This actor is **agent-ready** — AI agents can discover it, run it, and **pay for it autonomously**, with no Apify account and no human in the loop. It uses [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event) pricing and [limited permissions](https://docs.apify.com/platform/actors/development/permissions), so it qualifies for Apify's agentic-payment standards:

- **[x402](https://docs.apify.com/platform/integrations/x402)** — an open, HTTP-native payment protocol. Agents pay per run in USDC on the Base network directly through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) — no account, no API key.
- **[Skyfire](https://docs.apify.com/platform/integrations/skyfire)** — agent-to-service payments for fully autonomous AI-agent workflows.

Building an AI agent, MCP tool, or autonomous data pipeline? This scraper is ready to plug in and pay as it goes.

### More scrapers from scrapesage

Build a complete **market-intelligence stack** — pair prediction-market odds with prices, filings, news and demand signals:

- **[CoinGecko Crypto Scraper](https://apify.com/scrapesage/coingecko-crypto-scraper)** — coins, prices, exchanges, NFTs and on-chain market data.
- **[Yahoo Finance Scraper](https://apify.com/scrapesage/yahoo-finance-scraper)** — stocks, ETFs, FX, crypto quotes, financials and analyst ratings.
- **[SEC EDGAR Scraper](https://apify.com/scrapesage/sec-edgar-scraper)** — company filings and XBRL financials.
- **[FEC Campaign Finance Scraper](https://apify.com/scrapesage/fec-campaign-finance-scraper)** — donors, candidates, committees and lobbying for election markets.
- **[Google News Scraper](https://apify.com/scrapesage/google-news-scraper)** — real-time news that moves the markets you track.
- **[Google Trends Scraper](https://apify.com/scrapesage/google-trends-scraper)** — search-demand signals for any topic, candidate or asset.

### Tips

- **Start in Markets mode** with a `query` or `tagSlugs` for a clean, fully-populated table that's perfect for export.
- **Both platforms in one run**: run Markets (Polymarket) and Kalshi modes, or use Arbitrage mode to compare them side-by-side.
- **Enrichment costs requests**: `includePriceHistory` adds one request per outcome token, `includeTopHolders` / `includeRecentTrades` one per market — they're bundled into the market record at no extra charge.
- **Odds alerts**: combine `monitorMode` with a [Schedule](https://docs.apify.com/platform/schedules) and lower `monitorMinOddsChange` for tighter alerting.
- **Arbitrage is conservative by design**: raise `arbMinSimilarity` for stricter question matching and `arbMinSpread` for bigger gaps only.

### FAQ

**Does it need a Polymarket or Kalshi API key?** No. It reads each platform's public market-data API — no key, login or browser required.

**What's the difference between markets and events?** A Polymarket *event* groups related *markets* (e.g. "2028 Election Winner" contains one market per candidate). Events mode returns the group with all nested markets; Markets mode returns the individual markets.

**How are odds expressed?** As a probability from 0 to 1 (`yesPrice`) plus `impliedProbabilityPct` (0–100). Kalshi's native cent prices are normalised the same way.

**Can I monitor a market for odds changes?** Yes — turn on `monitorMode` and run on a [Schedule](https://docs.apify.com/platform/schedules). Each run emits only new or changed markets, tagged with a `changeType` (`new`, `odds_up`, `odds_down`, `volume_spike`, `status_change`, `resolved`).

**Does monitor mode conflict with Apify's scheduler?** No — they complement each other. The Schedule controls *when* it runs; monitor mode controls *what* is emitted. State is kept in a named key-value store, independent of the scheduler.

**Is the arbitrage signal guaranteed profit?** No. It's a theoretical, pre-fee calculation based on matched questions and current prices. Always verify liquidity, fees and the exact resolution criteria on each platform before trading.

**A field is empty — why?** The platform didn't expose that value for that record (e.g. category on some Polymarket markets, or a brand-new market with no trades). Fields are blank only when the source omits them — never because the scraper skipped them.

**Is scraping this data legal?** This actor collects publicly available market data only. You're responsible for using the data in compliance with applicable laws and each platform's terms. Nothing here is financial advice.

### Need help?

Open an issue on the actor's **Issues** tab, or visit the [Apify help center](https://help.apify.com/). Feature requests are welcome — this actor is actively maintained.

# Actor input Schema

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

Choose the data to extract. `Markets` and `Events` come from Polymarket. `Kalshi markets` pulls Kalshi.com. `Price history`, `Trades`, `Holders` and `Wallet` are Polymarket deep-dives. `Arbitrage` matches the same question across Polymarket and Kalshi and flags price gaps.

## `query` (type: `string`):

Keyword to search Polymarket markets/events (e.g. `election`, `bitcoin`, `fed rate`, `super bowl`). Leave empty to list the top markets/events by volume.

## `tagSlugs` (type: `array`):

Filter Polymarket markets/events by category tag slug, e.g. `politics`, `crypto`, `sports`, `economy`, `elections`, `geopolitics`, `tech`, `pop-culture`. Multiple = OR.

## `startUrls` (type: `array`):

Auto-routed targets. Accepts Polymarket event/market URLs (`https://polymarket.com/event/<slug>`), bare Polymarket slugs, Kalshi market URLs, or Kalshi tickers. Each is fetched directly.

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

Which markets to include: `Active` (open, accepting orders), `Closed` (resolved/ended), or `All`.

## `sortBy` (type: `string`):

Order Polymarket results (highest first).

## `marketSlugs` (type: `array`):

Specific Polymarket market slugs to fetch directly (the last path segment of a market URL).

## `eventSlugs` (type: `array`):

Specific Polymarket event slugs to fetch directly.

## `conditionIds` (type: `array`):

Polymarket market `conditionId` values. Used by Trades, Holders and Price-history modes to target exact markets.

## `walletAddresses` (type: `array`):

Polymarket proxy wallet addresses (0x…) for Wallet mode (P\&L, positions, portfolio value) or Trades-by-wallet.

## `kalshiTickers` (type: `array`):

Specific Kalshi market tickers to fetch in Kalshi mode.

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

Kalshi series or event tickers (e.g. `KXPRES`, `KXBTCD`) to pull all their markets in Kalshi mode.

## `includePriceHistory` (type: `boolean`):

For Markets/Events: attach the time-series odds (price chart) for each outcome token. Adds one request per token.

## `priceHistoryInterval` (type: `string`):

Look-back window for price history.

## `priceHistoryFidelity` (type: `integer`):

Minutes between price points (lower = more granular, more data).

## `includeTopHolders` (type: `boolean`):

For Markets: attach the largest position holders (smart money) per outcome. Adds one request per market.

## `topHoldersLimit` (type: `integer`):

How many top holders to fetch when enriching markets.

## `includeRecentTrades` (type: `boolean`):

For Markets: attach the most recent trades (order flow) per market. Adds one request per market.

## `recentTradesLimit` (type: `integer`):

How many recent trades to fetch when enriching markets, or per target in Trades mode.

## `arbMinSpread` (type: `number`):

Minimum YES-probability gap between Polymarket and Kalshi to report (e.g. 0.03 = 3 cents).

## `arbMinSimilarity` (type: `number`):

How closely the two platforms' questions must match (0–1) before they are treated as the same market. Higher = stricter.

## `monitorMode` (type: `boolean`):

Remember results between runs and emit ONLY markets that are new, whose odds moved, whose volume spiked, or that changed status/resolved. Perfect with Apify Schedules for odds alerts. State is kept in a named key-value store and is independent of Apify's scheduler.

## `monitorMinOddsChange` (type: `number`):

Minimum absolute change in a market's YES probability (0–1) to count as an `odds_move` (e.g. 0.02 = 2 cents).

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

Skip markets/events with less than this 24-hour traded volume. 0 = no filter.

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

Skip markets/events with less than this liquidity. 0 = no filter.

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

Maximum primary records to return per run (markets, events, kalshi markets, trades, etc.). 0 = no cap.

## `maxConcurrency` (type: `integer`):

Maximum parallel API requests.

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

Proxy settings. The Polymarket and Kalshi APIs are public and lenient, so Apify datacenter proxy (the default) is plenty.

## Actor input object example

```json
{
  "mode": "markets",
  "status": "active",
  "sortBy": "volume24hr",
  "includePriceHistory": false,
  "priceHistoryInterval": "1w",
  "priceHistoryFidelity": 60,
  "includeTopHolders": false,
  "topHoldersLimit": 10,
  "includeRecentTrades": false,
  "recentTradesLimit": 20,
  "arbMinSpread": 0.03,
  "arbMinSimilarity": 0.55,
  "monitorMode": false,
  "monitorMinOddsChange": 0.02,
  "minVolume24h": 0,
  "minLiquidity": 0,
  "maxItems": 100,
  "maxConcurrency": 8,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All scraped records in the default dataset. Each row is tagged with a `platform` (polymarket / kalshi) and a `type` (market, event, priceHistory, trade, holder, wallet, arbitrage).

# 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 = {
    "query": ""
};

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

# Run the Actor and wait for it to finish
run = client.actor("scrapesage/prediction-markets-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "query": ""
}' |
apify call scrapesage/prediction-markets-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=scrapesage/prediction-markets-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/LYKhbgAAVUKseFRwW/builds/MCQqIBgEz8TNgADYp/openapi.json
