# Polymarket Market Monitor + Whale & Arbitrage Signals (`memo23/polymarket-market-monitor`) Actor

Turn Polymarket into a trading-signal feed: watchlist any market by slug, track price and volume changes between runs, whale flow, top holders, price history, orderbook depth, and Kalshi arbitrage spreads. Category, keyword and volume filters. JSON or CSV. First 5 results per run free

- **URL**: https://apify.com/memo23/polymarket-market-monitor.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** AI, Agents, Automation
- **Stats:** 2 total users, 1 monthly users, 77.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 polymarket market signals

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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 Market Monitor — Prices, Whale Trades & Arbitrage Signals

**Turn Polymarket into a structured trading-signal feed.** Track prediction markets by category or keyword — live prices, 24h/1wk/1mo price moves, volume, liquidity, resolution dates — plus signal layers no plain scraper gives you: **price & volume deltas versus your previous run**, **whale trade flow**, **live orderbook depth**, and **experimental Kalshi cross-market arbitrage matching**. One row per market (or per event group), JSON or CSV out. First 5 results of every run are free so you can validate the output shape.

#### How it works

![How Polymarket Market Monitor works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-polymarket.png)

#### ✨ Why use this monitor?

Watching hundreds of prediction markets by hand doesn't scale, and a plain market scraper only tells you where prices *are* — not what changed, who's moving size, or whether the same question is priced differently elsewhere.

- 📌 **Watchlist mode.** Pass `marketSlugs` / `eventSlugs` straight from polymarket.com URLs to track exactly the markets you care about — watchlist items are always included, bypassing the volume/keyword filters, and combine freely with category discovery.
- 📈 **Cross-run change detection.** The actor remembers every market it saw and reports `priceChangeSinceLastRun`, `volume24hChangeSinceLastRun`, and `volumeTradedSinceLastRun` on the next run — schedule it hourly and you have a change feed, not a snapshot.
- 🕰️ **Price history (opt-in).** Each market's full YES-price time series from the CLOB — daily candles over the market's lifetime, or 6h/1h candles for the last month. Backtest or chart without waiting for scheduled runs to accumulate.
- 🏦 **Top holders (opt-in).** The largest position holders on each side of the market — wallet, display name, shares, and estimated USD value. Whale *positions* to complement the whale *flow* feed.
- 🐋 **Whale trade flow (opt-in).** Large-trade count, buy/sell/net USD flow, and the top 5 biggest recent trades per market — trader name, side, outcome, USD value — joined from Polymarket's public trade feed in a single extra API sweep.
- 📚 **Live orderbook depth (opt-in).** Best bid/ask, spread, bid/ask depth in USD (top 10 levels), and book imbalance from the CLOB — see whether a price can actually absorb your size.
- ⚖️ **Kalshi arbitrage matching (opt-in, experimental).** Each Polymarket question is fuzzy-matched against ~70k open Kalshi markets; when a twin is found you get its ticker, yes bid/ask, the price spread in points, and an `arbSignal` flag. Matching is deliberately conservative — a missed match beats a false signal.
- 🚨 **Odds-outlier flags.** Every row carries heuristic signals: `isBigMover` (10+ point move in 24h), `isLongshotRally` (+5 points on a ≤20¢ market), `isNearResolution` (resolves within 48h with active volume), `isThinBook` (high volume on thin liquidity).
- 🎛️ **Trader-grade filters.** Minimum 24h volume, minimum liquidity, minimum lifetime volume, minimum price move, minimum minutes until resolution — keep only markets that matter to your strategy.
- ⚡ **Pure JSON APIs.** No HTML parsing, no login, no proxies needed — data comes straight from Polymarket's public Gamma, CLOB, and Data APIs plus Kalshi's public API. Fast and stable.

#### 🎯 Use cases

| Team | What they build |
|------|-----------------|
| **Prediction-market traders** | Hourly change feeds with whale flow and thin-book warnings before entering positions |
| **Arbitrage hunters** | Polymarket-vs-Kalshi spread screens on matched markets |
| **Quant / data teams** | Historical price+volume time series by scheduling runs and appending datasets |
| **Journalists / researchers** | Odds trackers for elections, geopolitics, Fed decisions, sports |
| **Crypto analysts** | BTC/ETH strike-market dashboards with orderbook depth |
| **Alert builders** | Pipe `arbSignal` / `isBigMover` rows into Slack, Telegram or email via Apify integrations |

#### 📥 Supported inputs

No URLs needed — pick what to track with filters:

| Input | Behaviour |
|---|---|
| `marketSlugs` | **Watchlist**: exact markets by URL slug (the last path segment of a polymarket.com market URL). Always included, filters bypassed |
| `eventSlugs` | **Watchlist**: event groups from `polymarket.com/event/<slug>`. In `markets` mode every market inside the event is tracked; in `events` mode each slug is one row |
| `categories` | Top-level category shortcuts: `sports`, `politics`, `crypto`, `technology`, `science`, `business`, `finance`, `elections`, `entertainment`, `economy`, `world` |
| `tagIds` | Raw Polymarket Gamma tag IDs for anything outside the shortcuts (browse at `gamma-api.polymarket.com/tags`) |
| `searchQueries` | Keyword filter on the market question/description, e.g. `["bitcoin", "fed"]` |
| `itemType` | `markets` = one row per question · `events` = one row per event group (e.g. "World Cup Winner") with a nested markets summary |
| `status` | `active` (default), `closed` (resolved), or `all` |

Watchlist slugs and category/keyword discovery combine in one run (watchlist rows come first). Leave everything empty to track the whole exchange sorted by your `sortBy` choice.

#### 🔄 How it works

1. **Pull markets** (or event groups) from Polymarket's public Gamma API for each selected category/tag, sorted by 24h volume, liquidity, end date, or recency.
2. **Apply your filters** — volume, liquidity, price move, minutes-until-resolution, keywords.
3. **Diff against the previous run** — price/volume deltas are computed from a persistent snapshot (stored in a named key-value store, so it survives between runs and works on schedules).
4. **Join the signal layers you enabled** — whale trades (one API sweep for all markets), orderbook depth (one CLOB call per market, fetched in parallel), Kalshi twin matching (one index build per run).
5. **Flag outliers and push one row per market/event** to the dataset. JSON and CSV export automatically.

#### ⚙️ Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `marketSlugs` | array | `[]` | Watchlist of exact market slugs — always included, filters bypassed |
| `eventSlugs` | array | `[]` | Watchlist of event slugs — expanded to their markets in `markets` mode |
| `categories` | array | `["politics"]` | Category shortcuts (see Supported inputs) |
| `searchQueries` | array | `[]` | Case-insensitive keyword filter on question + description |
| `tagIds` | array | `[]` | Raw Gamma tag IDs, combined with categories |
| `itemType` | string | `markets` | `markets` or `events` |
| `status` | string | `active` | `active` / `closed` / `all` |
| `sortBy` | string | `volume24hr` | `volume24hr` / `liquidity` / `endDate` / `startDate` / `newest` |
| `minVolume24h` | integer | `0` | Drop markets under this 24h USD volume |
| `minLiquidity` | integer | `0` | Drop markets under this resting liquidity |
| `minTotalVolume` | integer | `0` | Drop markets under this lifetime volume |
| `minPriceChangePct` | integer | `0` | Keep only markets whose 1wk/1mo price moved ≥ N points |
| `minutesUntilEnd` | integer | `0` | Drop markets resolving sooner than N minutes from now |
| `includeWhaleTrades` | boolean | `false` | Join whale flow + top 5 whale trades per market |
| `whaleMinUsd` | integer | `10000` | Minimum single-trade cash value to count as a whale |
| `includeOrderbook` | boolean | `false` | Fetch live CLOB book per market (best bid/ask, depth, imbalance) |
| `includePriceHistory` | boolean | `false` | Attach the YES-price time series (up to 400 points, newest last) |
| `priceHistoryInterval` | string | `daily` | `daily` (full lifetime) / `6h` / `1h` (last ~month) |
| `includeTopHolders` | boolean | `false` | Attach largest position holders per outcome side |
| `topHoldersCount` | integer | `10` | Holders fetched per outcome side |
| `kalshiArb` | boolean | `false` | Fuzzy-match against open Kalshi markets and compute arb spreads |
| `kalshiArbMinSpreadPct` | integer | `5` | Points of spread needed to flag `arbSignal: true` |
| `dedupe` | boolean | `false` | Skip rows already pushed on previous runs. Leave off for monitoring — deltas are computed either way |
| `maxItemsPerSource` | integer | `300` | Per-category fetch cap before filtering |
| `maxItemsTotal` | integer | `100` | Hard cap on dataset rows per run (controls cost) |

#### 📊 Output overview

Each tracked market is one **single dataset row** of `type: "market"` (or `type: "event"` in events mode). All enabled signal layers — cross-run deltas, whale flow, orderbook, Kalshi match — are merged into the same row, so the dataset row count equals the market count exactly. You're charged per result **after the first 5 free rows each run**.

#### 📦 Output sample

```json
{
  "type": "market",
  "id": "531217",
  "question": "Will the price of Bitcoin be above $66,000 on July 11?",
  "slug": "will-the-price-of-bitcoin-be-above-66000-on-july-11",
  "url": "https://polymarket.com/event/bitcoin-price-on-july-11",
  "conditionId": "0x66b0824d3e2fe1c...",
  "eventTitle": "Bitcoin price on July 11?",
  "outcomes": ["Yes", "No"],
  "outcomePrices": [0.0145, 0.9855],
  "yesPrice": 0.0145,
  "lastTradePrice": 0.014,
  "bestBid": 0.014,
  "bestAsk": 0.015,
  "spread": 0.001,
  "volume24h": 311480.51,
  "volume1wk": 1102873.22,
  "totalVolume": 4817263.9,
  "liquidity": 54921.34,
  "startDate": "2026-07-04T20:01:44Z",
  "endDate": "2026-07-11T21:00:00Z",
  "minutesUntilEnd": 1362,
  "oneDayPriceChange": -0.011,
  "oneWeekPriceChange": -0.045,
  "oneMonthPriceChange": null,
  "priceChangeSinceLastRun": -0.002,
  "volume24hChangeSinceLastRun": 18211.4,
  "volumeTradedSinceLastRun": 21830.7,
  "lastSeenAt": "2026-07-10T21:24:21.931Z",
  "isBigMover": false,
  "isLongshotRally": false,
  "isNearResolution": true,
  "isThinBook": false,
  "signals": ["resolves within 48h with active volume"],
  "whaleTradeCount": 3,
  "whaleBuyUsd": 42100.5,
  "whaleSellUsd": 5250.47,
  "whaleNetFlowUsd": 36850.03,
  "topWhaleTrades": [
    {
      "side": "BUY",
      "outcome": "No",
      "usdValue": 18067.0,
      "shares": 50000,
      "price": 0.3613,
      "trader": "0x8bd3...f69a",
      "tradedAt": "2026-07-10T18:14:50.000Z"
    }
  ],
  "bookBestBid": 0.014,
  "bookBestAsk": 0.015,
  "bookSpread": 0.001,
  "bidDepthUsd": 8211.19,
  "askDepthUsd": 12081.53,
  "bookImbalance": -0.191,
  "priceHistory": [
    { "t": "2026-07-04T00:00:08.000Z", "p": 0.031 },
    { "t": "2026-07-05T00:00:08.000Z", "p": 0.024 }
  ],
  "topHolders": [
    { "outcome": "No", "wallet": "0xa5ef...2966", "name": "athelstan", "shares": 505624, "usdValue": 498293.4 }
  ],
  "kalshiMatch": {
    "kalshiTicker": "KXBTCD-26JUL1117-T66000",
    "kalshiTitle": "BTC price on Jul 11, 2026 at 5pm EDT? — $66,000 or above",
    "kalshiYesBid": 0.01,
    "kalshiYesAsk": 0.01,
    "kalshiYesMid": 0.01,
    "matchScore": 0.67,
    "arbSpreadPct": 0.45,
    "arbSignal": false
  },
  "arbSpreadPct": 0.45,
  "arbSignal": false,
  "active": true,
  "closed": false,
  "scrapedAt": "2026-07-10T22:30:11.412Z"
}
````

#### 🗂 Key output fields

| Group | Fields |
|---|---|
| **Identity** | `id`, `question`, `slug`, `url`, `conditionId`, `eventId`, `eventSlug`, `eventTitle` |
| **Prices** | `outcomes[]`, `outcomePrices[]`, `yesPrice`, `lastTradePrice`, `bestBid`, `bestAsk`, `spread` |
| **Volume & liquidity** | `volume24h`, `volume1wk`, `volume1mo`, `totalVolume`, `liquidity` |
| **Price moves** | `oneDayPriceChange`, `oneWeekPriceChange`, `oneMonthPriceChange` (from the API, as decimals: 0.05 = 5 points) |
| **Cross-run deltas** | `priceChangeSinceLastRun`, `volume24hChangeSinceLastRun`, `volumeTradedSinceLastRun`, `lastSeenAt` — `null` on the first run a market is seen |
| **Outlier flags** | `isBigMover`, `isLongshotRally`, `isNearResolution`, `isThinBook`, `signals[]` (human-readable reasons) |
| **Whale flow** *(when `includeWhaleTrades: true`)* | `whaleTradeCount`, `whaleBuyUsd`, `whaleSellUsd`, `whaleNetFlowUsd`, `topWhaleTrades[]` |
| **Orderbook** *(when `includeOrderbook: true`)* | `bookBestBid`, `bookBestAsk`, `bookSpread`, `bidDepthUsd`, `askDepthUsd`, `bookImbalance` (−1…1, positive = bid-heavy) |
| **Price history** *(when `includePriceHistory: true`)* | `priceHistory[]` — `{t, p}` points, ISO timestamp + YES price, newest last, up to 400 points |
| **Top holders** *(when `includeTopHolders: true`)* | `topHolders[]` — `{outcome, wallet, name, shares, usdValue}` sorted by position value |
| **Kalshi arb** *(when `kalshiArb: true`)* | `kalshiMatch{}` (ticker, title, yes bid/ask/mid, match score), `arbSpreadPct` (Polymarket yes − Kalshi mid, in points), `arbSignal` |
| **Event rows** *(itemType `events`)* | `title`, `tags[]`, `marketCount`, `leadingOutcome`, `leadingOutcomePrice`, `markets[]` (nested per-outcome summary), `openInterest`, `commentCount` |

#### ❓ FAQ

**How do the cross-run deltas work?**
The actor stores a snapshot of every market it saw (price, 24h volume, lifetime volume) in a named key-value store called `polymarket-monitor-state`. On the next run it diffs current values against that snapshot. Deltas are `null` the first time a market is seen. Snapshots older than 30 days are pruned automatically.

**How reliable is the Kalshi matching?**
It's fuzzy title matching with a conservative threshold, and it's marked experimental for a reason. In testing it correctly pairs exact twins (e.g. Polymarket "Bitcoin above $66,000 on July 11" → Kalshi "BTC price on Jul 11 — $66,000 or above") and rejects near-misses (a "Fed +25bps" question will NOT match a "Fed funds rate above X%" market). But resolution criteria, timezones and fee structures differ between platforms — **always verify both markets' rules before trading a flagged spread.** `matchScore` is included so you can set your own bar.

**Does a big `arbSpreadPct` mean free money?**
No. Spreads can reflect different resolution sources, different cut-off times, fees, or stale quotes on the thinner platform. Treat `arbSignal` as a screening tool, not a trade instruction. Nothing in this actor's output is financial advice.

**Where do I find a market's slug for the watchlist?**
It's the last path segment of the market's polymarket.com URL. For event pages (`polymarket.com/event/<slug>`) use `eventSlugs`. Unresolvable slugs are reported in the run log and skipped — the run doesn't fail.

**What's the difference between whale trades and top holders?**
`topWhaleTrades` is *flow* — who traded size recently. `topHolders` is *positions* — who is currently sitting on the largest stake on each side. A market can have zero recent whale trades but a $1M standing position.

**Why don't I see whale trades on my markets?**
The whale feed covers recent large trades exchange-wide. Quiet markets often have none above your `whaleMinUsd` threshold — that's real signal (no size moving), not missing data.

**How do I build a price history?**
Schedule the actor (e.g. hourly) with `dedupe: false`. Each run appends a fresh snapshot per market, and the delta fields tell you what changed between runs.

**Does it need a proxy or login?**
No. All four data sources (Polymarket Gamma, CLOB, Data API, Kalshi) are public JSON APIs. The proxy input exists for completeness but is rarely needed.

**How is the run priced?**
Pay-per-event: you're charged per dataset row, and the **first 5 rows of every run are free** so you can validate output on your exact input before scaling `maxItemsTotal` up.

#### 💬 Support

- For issues or feature requests, please use the **Issues** tab on the actor's Apify Console page.
- Author's website: <https://muhamed-didovic.github.io/>
- Email: <muhamed.didovic@gmail.com>

#### 🛠 Additional services

- Custom output shape, additional signal layers, or one-off datasets: <muhamed.didovic@gmail.com>
- Need a similar monitor for other prediction or betting markets (Kalshi-first, sports odds, etc.)? Drop an email.
- For API access (no Apify fee, just a usage fee for the API): <muhamed.didovic@gmail.com>

#### 🔎 Explore more scrapers

If this Polymarket Market Monitor was useful, see other scrapers and actors at [memo23's Apify profile](https://apify.com/memo23) — covering finance, social media, job boards, real estate, and more.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Polymarket, Kalshi, or any of their subsidiaries or affiliates. All trademarks mentioned are the property of their respective owners.

The actor accesses only publicly available JSON APIs (Polymarket's Gamma, CLOB and Data APIs; Kalshi's public trade API) — no authenticated endpoints, no order placement, no wallet access, no content behind a login. Output is market data, not financial advice; users are responsible for their own trading decisions and for ensuring their use complies with each platform's Terms of Service and applicable law in their jurisdiction.

***

### SEO Keywords

polymarket scraper, polymarket api, polymarket market monitor, polymarket price tracker, prediction market scraper, prediction market data, polymarket odds api, polymarket whale tracker, polymarket whale trades, polymarket kalshi arbitrage, kalshi polymarket spread, prediction market arbitrage finder, polymarket orderbook data, polymarket volume tracker, polymarket price alerts, polymarket monitoring tool, scrape polymarket, polymarket dataset, election odds scraper, crypto prediction market data, polymarket gamma api, prediction market signals

# Actor input Schema

## `searchQueries` (type: `array`):

Only keep markets whose question or description contains any of these keywords. Case insensitive. Leave empty to keep everything the API returned.

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

Top-level Polymarket categories. Pick one or more of: sports, politics, crypto, technology, science, business, finance, elections, entertainment, economy, world. Leave empty to track all categories.

## `tagIds` (type: `array`):

Raw Polymarket Gamma tag IDs for tags outside the category shortcuts — add one ID per entry, e.g. 144 (Elections) or 180 (Israel). Find a tag's ID by opening gamma-api.polymarket.com/tags/slug/<tag-name> in your browser. Combined with the category shortcuts above.

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

Track specific markets by their URL slug — the last path segment of a polymarket.com market URL, e.g. 'will-bitcoin-reach-80000-in-july'. Watchlist markets are always included, bypassing the keyword/volume/liquidity filters below. Combined with any categories or keywords you also set. Used when itemType is 'markets'.

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

Track specific event groups by their URL slug — from polymarket.com/event/<slug>, e.g. 'world-cup-winner'. In 'events' mode each slug becomes one row; in 'markets' mode every market inside the event is tracked. Watchlist events bypass the filters below.

## `itemType` (type: `string`):

'markets' returns one row per individual market (question + outcomes + prices). 'events' returns one row per event group (a basket of related markets, e.g. 'World Cup Winner') with a nested markets summary.

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

'active' (default) returns open markets. 'closed' returns resolved markets. 'all' returns both.

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

Sort markets before filtering and capping. 'volume24hr' ranks by last-24h traded volume, 'liquidity' by resting orderbook depth, 'endDate' by closest to resolution, 'startDate' / 'newest' by recency.

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

Drop markets with less than this much traded volume in the last 24 hours. Useful when you only want liquid, actively traded markets. 0 disables.

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

Drop markets with less than this much resting liquidity on the orderbook. Filters thin books. 0 disables.

## `minTotalVolume` (type: `integer`):

Drop markets with less than this much lifetime traded volume. Filters toy markets. 0 disables.

## `minPriceChangePct` (type: `integer`):

Only keep markets whose 1-week or 1-month price has moved by at least this many percentage points (absolute value). Example: 10 keeps only markets that moved 10+ points. 0 disables.

## `minutesUntilEnd` (type: `integer`):

Drop markets ending sooner than this many minutes from now, e.g. to exclude markets too close to resolution for your strategy. 0 keeps everything.

## `includeWhaleTrades` (type: `boolean`):

Enrich each row with large-trade flow: whale trade count, whale buy/sell/net USD flow, and the top 5 largest recent trades (side, outcome, USD value, trader). One extra API sweep per run, not per market.

## `whaleMinUsd` (type: `integer`):

Minimum cash value of a single trade to count as a whale trade.

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

Fetch the live CLOB orderbook for each market's YES outcome: best bid/ask, spread, bid/ask depth in USD (top 10 levels), and book imbalance. Adds one request per market.

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

Attach the market's YES-price time series from the CLOB (up to 400 points, newest last). Adds one request per market. Only for itemType 'markets'.

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

'daily' = one point per day over the market's full lifetime. '6h' / '1h' = finer candles covering roughly the last month.

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

Attach the largest position holders on each side of the market — wallet, display name, shares, and estimated USD value at current prices. Adds one request per market. Only for itemType 'markets'.

## `topHoldersCount` (type: `integer`):

How many holders to fetch per outcome side.

## `kalshiArb` (type: `boolean`):

Fuzzy-match each Polymarket question against open Kalshi markets and report the Kalshi yes bid/ask, the price spread in points, and an arbSignal flag when the spread exceeds the threshold. Matching is conservative (a missed match beats a false signal) and resolution criteria can differ between platforms — always verify before trading.

## `kalshiArbMinSpreadPct` (type: `integer`):

Flag arbSignal=true when the absolute Polymarket-vs-Kalshi price spread is at least this many percentage points.

## `dedupe` (type: `boolean`):

Skip market IDs already pushed on previous runs (stored in the key-value store under SEEN\_IDS). Leave off to snapshot every run — recommended for monitoring, since price/volume deltas versus the prior run are computed either way.

## `maxItemsPerSource` (type: `integer`):

Per-tag cap on items fetched from the API before filtering. The Gamma API returns up to 100 per page; the actor paginates.

## `maxItemsTotal` (type: `integer`):

Hard cap on rows pushed to the dataset per run. Controls total cost — you are charged per result after the first 5 free rows.

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

Apify proxy settings. The Polymarket and Kalshi APIs are public and do not aggressively rate-limit by IP, so a proxy is rarely needed.

## Actor input object example

```json
{
  "searchQueries": [],
  "categories": [
    "politics"
  ],
  "tagIds": [],
  "marketSlugs": [],
  "eventSlugs": [],
  "itemType": "markets",
  "status": "active",
  "sortBy": "volume24hr",
  "minVolume24h": 0,
  "minLiquidity": 0,
  "minTotalVolume": 0,
  "minPriceChangePct": 0,
  "minutesUntilEnd": 0,
  "includeWhaleTrades": false,
  "whaleMinUsd": 10000,
  "includeOrderbook": false,
  "includePriceHistory": false,
  "priceHistoryInterval": "daily",
  "includeTopHolders": false,
  "topHoldersCount": 10,
  "kalshiArb": false,
  "kalshiArbMinSpreadPct": 5,
  "dedupe": false,
  "maxItemsPerSource": 300,
  "maxItemsTotal": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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 = {
    "searchQueries": [],
    "categories": [
        "politics"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/polymarket-market-monitor").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 = {
    "searchQueries": [],
    "categories": ["politics"],
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/polymarket-market-monitor").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 '{
  "searchQueries": [],
  "categories": [
    "politics"
  ]
}' |
apify call memo23/polymarket-market-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=memo23/polymarket-market-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Polymarket Market Monitor + Whale & Arbitrage Signals",
        "description": "Turn Polymarket into a trading-signal feed: watchlist any market by slug, track price and volume changes between runs, whale flow, top holders, price history, orderbook depth, and Kalshi arbitrage spreads. Category, keyword and volume filters. JSON or CSV. First 5 results per run free",
        "version": "0.0",
        "x-build-id": "n5Twqsz6EH6LmvOPo"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~polymarket-market-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-polymarket-market-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~polymarket-market-monitor/runs": {
            "post": {
                "operationId": "runs-sync-memo23-polymarket-market-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~polymarket-market-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-polymarket-market-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchQueries": {
                        "title": "Keyword search (question or description)",
                        "type": "array",
                        "description": "Only keep markets whose question or description contains any of these keywords. Case insensitive. Leave empty to keep everything the API returned.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "categories": {
                        "title": "Category shortcuts",
                        "type": "array",
                        "description": "Top-level Polymarket categories. Pick one or more of: sports, politics, crypto, technology, science, business, finance, elections, entertainment, economy, world. Leave empty to track all categories.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "tagIds": {
                        "title": "Tag IDs (advanced)",
                        "type": "array",
                        "description": "Raw Polymarket Gamma tag IDs for tags outside the category shortcuts — add one ID per entry, e.g. 144 (Elections) or 180 (Israel). Find a tag's ID by opening gamma-api.polymarket.com/tags/slug/<tag-name> in your browser. Combined with the category shortcuts above.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "marketSlugs": {
                        "title": "Watchlist: market slugs",
                        "type": "array",
                        "description": "Track specific markets by their URL slug — the last path segment of a polymarket.com market URL, e.g. 'will-bitcoin-reach-80000-in-july'. Watchlist markets are always included, bypassing the keyword/volume/liquidity filters below. Combined with any categories or keywords you also set. Used when itemType is 'markets'.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "eventSlugs": {
                        "title": "Watchlist: event slugs",
                        "type": "array",
                        "description": "Track specific event groups by their URL slug — from polymarket.com/event/<slug>, e.g. 'world-cup-winner'. In 'events' mode each slug becomes one row; in 'markets' mode every market inside the event is tracked. Watchlist events bypass the filters below.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "itemType": {
                        "title": "Item type",
                        "enum": [
                            "markets",
                            "events"
                        ],
                        "type": "string",
                        "description": "'markets' returns one row per individual market (question + outcomes + prices). 'events' returns one row per event group (a basket of related markets, e.g. 'World Cup Winner') with a nested markets summary.",
                        "default": "markets"
                    },
                    "status": {
                        "title": "Status",
                        "enum": [
                            "active",
                            "closed",
                            "all"
                        ],
                        "type": "string",
                        "description": "'active' (default) returns open markets. 'closed' returns resolved markets. 'all' returns both.",
                        "default": "active"
                    },
                    "sortBy": {
                        "title": "Sort",
                        "enum": [
                            "volume24hr",
                            "liquidity",
                            "endDate",
                            "startDate",
                            "newest"
                        ],
                        "type": "string",
                        "description": "Sort markets before filtering and capping. 'volume24hr' ranks by last-24h traded volume, 'liquidity' by resting orderbook depth, 'endDate' by closest to resolution, 'startDate' / 'newest' by recency.",
                        "default": "volume24hr"
                    },
                    "minVolume24h": {
                        "title": "Minimum 24h volume (USD)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop markets with less than this much traded volume in the last 24 hours. Useful when you only want liquid, actively traded markets. 0 disables.",
                        "default": 0
                    },
                    "minLiquidity": {
                        "title": "Minimum liquidity (USD)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop markets with less than this much resting liquidity on the orderbook. Filters thin books. 0 disables.",
                        "default": 0
                    },
                    "minTotalVolume": {
                        "title": "Minimum lifetime volume (USD)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop markets with less than this much lifetime traded volume. Filters toy markets. 0 disables.",
                        "default": 0
                    },
                    "minPriceChangePct": {
                        "title": "Minimum price move (percentage points)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only keep markets whose 1-week or 1-month price has moved by at least this many percentage points (absolute value). Example: 10 keeps only markets that moved 10+ points. 0 disables.",
                        "default": 0
                    },
                    "minutesUntilEnd": {
                        "title": "Minimum minutes until resolution",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Drop markets ending sooner than this many minutes from now, e.g. to exclude markets too close to resolution for your strategy. 0 keeps everything.",
                        "default": 0
                    },
                    "includeWhaleTrades": {
                        "title": "Include whale trades",
                        "type": "boolean",
                        "description": "Enrich each row with large-trade flow: whale trade count, whale buy/sell/net USD flow, and the top 5 largest recent trades (side, outcome, USD value, trader). One extra API sweep per run, not per market.",
                        "default": false
                    },
                    "whaleMinUsd": {
                        "title": "Whale trade threshold (USD)",
                        "minimum": 500,
                        "type": "integer",
                        "description": "Minimum cash value of a single trade to count as a whale trade.",
                        "default": 10000
                    },
                    "includeOrderbook": {
                        "title": "Include orderbook depth",
                        "type": "boolean",
                        "description": "Fetch the live CLOB orderbook for each market's YES outcome: best bid/ask, spread, bid/ask depth in USD (top 10 levels), and book imbalance. Adds one request per market.",
                        "default": false
                    },
                    "includePriceHistory": {
                        "title": "Include price history",
                        "type": "boolean",
                        "description": "Attach the market's YES-price time series from the CLOB (up to 400 points, newest last). Adds one request per market. Only for itemType 'markets'.",
                        "default": false
                    },
                    "priceHistoryInterval": {
                        "title": "Price history granularity",
                        "enum": [
                            "daily",
                            "6h",
                            "1h"
                        ],
                        "type": "string",
                        "description": "'daily' = one point per day over the market's full lifetime. '6h' / '1h' = finer candles covering roughly the last month.",
                        "default": "daily"
                    },
                    "includeTopHolders": {
                        "title": "Include top holders",
                        "type": "boolean",
                        "description": "Attach the largest position holders on each side of the market — wallet, display name, shares, and estimated USD value at current prices. Adds one request per market. Only for itemType 'markets'.",
                        "default": false
                    },
                    "topHoldersCount": {
                        "title": "Top holders per side",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "How many holders to fetch per outcome side.",
                        "default": 10
                    },
                    "kalshiArb": {
                        "title": "Kalshi arbitrage matching (experimental)",
                        "type": "boolean",
                        "description": "Fuzzy-match each Polymarket question against open Kalshi markets and report the Kalshi yes bid/ask, the price spread in points, and an arbSignal flag when the spread exceeds the threshold. Matching is conservative (a missed match beats a false signal) and resolution criteria can differ between platforms — always verify before trading.",
                        "default": false
                    },
                    "kalshiArbMinSpreadPct": {
                        "title": "Arb signal threshold (percentage points)",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Flag arbSignal=true when the absolute Polymarket-vs-Kalshi price spread is at least this many percentage points.",
                        "default": 5
                    },
                    "dedupe": {
                        "title": "Deduplicate across runs",
                        "type": "boolean",
                        "description": "Skip market IDs already pushed on previous runs (stored in the key-value store under SEEN_IDS). Leave off to snapshot every run — recommended for monitoring, since price/volume deltas versus the prior run are computed either way.",
                        "default": false
                    },
                    "maxItemsPerSource": {
                        "title": "Max items fetched per category/tag",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Per-tag cap on items fetched from the API before filtering. The Gamma API returns up to 100 per page; the actor paginates.",
                        "default": 300
                    },
                    "maxItemsTotal": {
                        "title": "Maximum results per run",
                        "minimum": 1,
                        "maximum": 20000,
                        "type": "integer",
                        "description": "Hard cap on rows pushed to the dataset per run. Controls total cost — you are charged per result after the first 5 free rows.",
                        "default": 100
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify proxy settings. The Polymarket and Kalshi APIs are public and do not aggressively rate-limit by IP, so a proxy is rarely needed.",
                        "default": {
                            "useApifyProxy": false
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
