# Polymarket Scraper — Prediction Market Odds & Whale Tracker (`jy-labs/polymarket-whale-tracker`) Actor

Prediction market intelligence from Polymarket without maintaining a Gamma + Data + CLOB pipeline: market odds, deep dives, whale wallet profiles from $0.25, and scheduled large-trade checks. Built for researchers, analysts, quant teams and AI agents. Research use only.

- **URL**: https://apify.com/jy-labs/polymarket-whale-tracker.md
- **Developed by:** [jy-labs](https://apify.com/jy-labs) (community)
- **Categories:** AI, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 91 total users, 1 monthly users, 100.0% runs succeeded, 2 bookmarks
- **User rating**: No ratings yet

## Pricing

from $225.00 / 1,000 whale profiles

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

## Polymarket Scraper — Prediction Market Odds & Whale Tracker

Research public Polymarket markets, wallets, holders, trades, and orderbooks without maintaining separate Gamma + Data + CLOB APIs. This Actor calls public APIs directly; it is not a browser scraper.

Use it for:

- market researchers comparing active markets and public wallet exposure;
- operators running scheduled large-trade checks;
- data teams feeding structured Dataset items into dashboards or warehouses;
- AI-agent builders using Apify API or MCP workflows.

> Informational public-data research only. It does not provide financial advice, trading recommendations, guaranteed alpha, predictions, trade execution, streaming alerts, or push notifications.

### 5-minute quickstart: profile one Polymarket wallet

A single-wallet `whale_profile` is the cheapest first run that returns a complete research object: `$0.25` for one wallet. An `alert_check` run costs less at `$0.05`, but it reports only threshold-crossing trades on condition IDs you already have.

1. Copy a public wallet address from a Polymarket profile URL, or take one from a prior `bulk_scan`/`whale_discovery` run. It must be `0x` plus exactly 40 hexadecimal characters.
2. Open the Actor **Input** tab, switch to the JSON editor, paste the input below, and replace the all-zero address with yours. The all-zero address is a schema-valid placeholder, not a live target.
3. Start the run, then open the **Dataset**. You get one item per successfully processed wallet.

```json
{
  "mode": "whale_profile",
  "walletAddresses": ["0x0000000000000000000000000000000000000000"],
  "timeWindow": "30d",
  "enableMlAnalysis": false
}
```

Trimmed output item. Values are illustrative:

```json
{
  "wallet": "0x0000000000000000000000000000000000000000",
  "summary": {
    "winRate": 0.62,
    "totalPnl": 184203.44,
    "activePositionCount": 7
  }
}
```

The full item also carries `summary.roi`, `summary.resolvedTrades`, `summary.activePositionValue`, the `activePositions` array, `recentActivity` (up to 20 entries inside `timeWindow`), and `metadata`.

**Charge cap note.** Apify requires every run of this Actor to allow at least `$1.50` of total charge, so leave the run's maximum total charge at `$1.50` or higher. A run configured below that is rejected before it starts instead of ending as a silent empty success. The cap is a ceiling, not a fee: a one-wallet profile still charges `$0.25`.

### Choose your workflow

| Mode | Customer job | Required target | Dataset shape | PPE plan |
|---|---|---|---|---|
| `bulk_scan` | Scan the top N active markets by 24h trading volume, by category | None; use `category` and `maxMarkets` to narrow the scan | Non-ML: flat market rows; eligible statistical ML: one `{ markets, mlInsights }` object | One `$1.50` `bulk_scan` event only when eligible output exists |
| `market_analysis` | Deep-dive markets under one or more known event slugs | `eventSlugs` | One persisted Dataset item and one `$0.15` charge per successfully analyzed market | `$0.15` `market_analysis` per persisted market item |
| `alert_check` | Poll known condition IDs for trades above a threshold | `marketConditionIds` | One persisted condition summary per successfully checked unique condition ID, including zero-trade summaries | One `$0.05` `alert_check` event per check, whatever the number of checked condition IDs |
| `whale_profile` | Profile known public wallet addresses | `walletAddresses` | One profile item per successfully processed wallet | `$0.25` `whale_profile` per persisted wallet profile |
| `whale_discovery` | Discover candidate wallets across a bounded market set | None; use scan and qualification filters | One aggregate object containing `whales`, `hotMarkets`, and `metadata` | One `$1.50` `bulk_scan` event only when eligible output exists |

Target arrays are trimmed and de-duplicated before work starts. `market_analysis`, `alert_check`, and `whale_profile` reject an omitted required target field. Empty target arrays produce zero Dataset items and no mode-specific PPE charge. Malformed non-empty slugs, condition IDs, or wallet addresses are rejected before API work.

`market_analysis` resolves every supplied event slug to its current markets. One slug can therefore emit and charge for more than one selected market. Each `metadata.eventSlug` is copied from the Gamma response's `event.slug`, not inferred from market position or query order.

### Polymarket API without maintaining Gamma, Data, and CLOB pipelines

Polymarket exposes public market data across three separate services. This Actor calls all three, normalizes the responses, and writes structured Dataset items, so you do not build, host, or retry those pipelines yourself.

- **Gamma API** (`gamma-api.polymarket.com`) supplies active events, markets, tags, prices, volume, liquidity, and market metadata.
- **Data API** (`data-api.polymarket.com`) supplies public holders, trades, positions, closed positions, and wallet activity.
- **CLOB API** (`clob.polymarket.com`) supplies token orderbooks, used by `market_analysis` when `includeOrderbook` is enabled and the market has valid string token IDs, and the live price of each market selected by `bulk_scan` and `whale_discovery` and of each open market `market_analysis` analyzes (one `/book` request per market, plus `/last-trade-price` only when that book lacks a last trade; never for unselected candidates).

No Polymarket account, API key, or login is required, and no headless browser runs. Output goes to the default Dataset in the same shape whether you start the run from Console, the Apify API, a schedule, or an MCP client.

Targets are yours to supply: slugs from Polymarket event URLs, condition IDs from current market/API data or prior Actor output, and wallets from public profile URLs or your own dataset. The Actor's format checks are trust boundaries, not discovery shortcuts.

### Track Polymarket whale wallets and large trades

A whale here is a position size, not a reputation: `whaleThreshold` is the minimum estimated current USD value a wallet holds in one scanned market, summed over every outcome it holds there (shares × current outcome price), not the wallet's total portfolio value. A wallet counts once per market. The default is `$50,000`. Large individual trades use a separate `tradeAlertThreshold`, default `$10,000`.

#### Profile wallets you already know

Replace the all-zero wallet with a current `0x` + 40-hex-character public wallet address. One item and one `$0.25` charge per successfully processed wallet.

```json
{
  "mode": "whale_profile",
  "walletAddresses": ["0x0000000000000000000000000000000000000000"],
  "timeWindow": "30d",
  "enableMlAnalysis": false
}
```

`winRate`, `totalPnl`, `roi`, and `resolvedTrades` are computed from the wallet's closed positions: all of them, or the 2,000 most recent for a wallet with more. A wallet with no resolved history reports zeros there while its `activePositions` still populate. `timeWindow` filters `recentActivity` only; it never trims active positions or the closed-history summary.

#### Discover candidate wallets across markets

Use this when you do not have addresses yet. It scans a bounded market set, collects qualifying holders, and returns one aggregate object with `whales`, `hotMarkets`, and `metadata`. Wallets without resolved history are exempt from the `minWinRate`/`minPnl` filters and are assessed by active position size instead.

```json
{
  "mode": "whale_discovery",
  "category": "politics",
  "maxMarkets": 5,
  "whaleThreshold": 50000,
  "minWinRate": 0.5,
  "minPnl": 0,
  "maxWhales": 10,
  "enableMlAnalysis": false
}
```

`whale_discovery` bills through the `bulk_scan` event at `$1.50` per eligible scan, and it ignores `timeWindow`.

### Prediction market odds data for research

Market rows carry `currentPrice` as the current price of the market's first outcome, and `currentPriceOutcome` names that outcome (for example `Yes`, or a team name on a head-to-head market), alongside `volume24hr`, liquidity and spread on deep dives, and holder context. Each run is a snapshot of what the source returned during that run, not a settled exchange feed.

#### Scan active markets by category

This discovery input is intentionally bounded and returns no orderbook analysis (only each selected market's live price), because `includeOrderbook` affects `market_analysis` only.

```json
{
  "mode": "bulk_scan",
  "category": "politics",
  "maxMarkets": 5,
  "whaleThreshold": 50000,
  "includeTradeFlow": true,
  "enableMlAnalysis": false
}
```

A normal item can include `question`, `slug`, `eventSlug`, `conditionId`, `category`, `currentPrice`, `currentPriceOutcome`, `priceSource`, `priceFetchedAt`, `volume24hr`, `healthScore`, `topHolderCount`, `tradeFlow`, and `metadata`. The Actor requests and analyzes at most `topHoldersCount` holders per outcome of each market (`5`–`20`); `topHolderCount` counts distinct wallets whose position, summed over every outcome they hold, met `whaleThreshold`, not every returned holder. In `tradeFlow`, each `largeTrades` entry names the traded `outcome` and `outcomeIndex`, and `initiatedBy`, `buyerInitiated`, and `sellerInitiated` follow each public trade's taker side (BUY or SELL). Take an item's `eventSlug` into `market_analysis` or its `conditionId` into `alert_check`.

In `bulk_scan` and `market_analysis` (`market.currentPrice`), `currentPrice` is the live order-book price of the first outcome's token at fetch time, using Polymarket's display rule: the CLOB book midpoint, or the last trade price when the bid-ask spread is wider than `0.10`, one side of the book is empty, or the book is crossed. The other outcome is priced as its complement (`1 - currentPrice`). `priceSource` says what you got: `clob_midpoint`, `clob_last_trade`, or `gamma` when the CLOB request failed (5-second timeout, no rate-limit retry) or returned no usable price, or the market is closed or not accepting orders, in which case `currentPrice` is Gamma's `outcomePrices` value, which is cached and can trail the order book by minutes on fast-moving markets. `priceFetchedAt` is the ISO time the price response was received (for `gamma`, when the Gamma events response arrived). Holder values (`whaleThreshold`, `whaleBreakdown`) and `tradeFlow` buyer/seller references use the same prices; `whale_discovery` values holders the same way. `RUN_SUMMARY.priceFallbackCount` counts open markets priced from Gamma, and the run's status message ends with `(N priced from Gamma)` when it is above zero.

A valid run can still return zero items when the current source has no matching category/market data or every candidate fails closed. `whale_discovery` may instead persist one aggregate object with empty `whales`/`hotMarkets` while planning no mode-specific PPE charge. Zero eligible output does not plan the mode-specific PPE charge.

#### Deep-dive one event

Replace `replace-with-current-event-slug` with a current slug from a Polymarket event URL or prior Actor output. One event slug can resolve to several markets, and each successfully analyzed market is one item and one `$0.15` charge.

```json
{
  "mode": "market_analysis",
  "eventSlugs": ["replace-with-current-event-slug"],
  "topHoldersCount": 20,
  "includeOrderbook": true,
  "includeTradeFlow": true,
  "enableMlAnalysis": false
}
```

### Scheduled Polymarket whale alerts and webhooks

`alert_check` is scheduled polling, not streaming or push notifications. Point an Apify schedule at a fixed set of condition IDs and each run reports the large trades seen inside `timeWindow`.

Replace the all-zero condition ID with a current `0x` + 64-hex-character ID.

```json
{
  "mode": "alert_check",
  "marketConditionIds": ["0x0000000000000000000000000000000000000000000000000000000000000000"],
  "tradeAlertThreshold": 10000,
  "timeWindow": "24h"
}
```

Every successfully checked unique condition ID emits one item, including quiet ones, which report `newLargeTrades: 0` and `status: "no_alerts"`. Items with matches carry `newLargeTrades`, `totalVolume`, and up to 10 matching trades. The whole sweep is a single `$0.05` check charge, whatever the number of condition IDs.

The Actor itself sends no notifications. To get one, attach an Apify webhook or integration to the run so a finished check pushes the Dataset to your endpoint, Slack, or storage, or poll the Dataset from your own automation.

### Inputs and exact behavior

| Parameter | Type | Default | Exact behavior |
|---|---|---:|---|
| `mode` | string | `bulk_scan` | `bulk_scan`, `market_analysis`, `alert_check`, `whale_profile`, or `whale_discovery` |
| `eventSlugs` | string\[] | `[]` | `market_analysis` only. The field must be present. After trimming, each value must match `^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$`; duplicates are removed in first-seen order. An explicit `[]` means zero output/no charge. |
| `marketConditionIds` | string\[] | `[]` | `alert_check` only. The field must be present. Each trimmed value starts with lowercase `0x` followed by exactly 64 hexadecimal characters; hex letters may be upper- or lowercase. De-duplication is case-insensitive. A successfully checked unique condition emits one persisted Dataset item, even when no trade crosses the threshold. |
| `walletAddresses` | string\[] | `[]` | `whale_profile` only. The field must be present. Each trimmed value starts with lowercase `0x` followed by exactly 40 hexadecimal characters; hex letters may be upper- or lowercase. De-duplication is case-insensitive. Emits one Dataset item and one charge per successfully processed and persisted wallet profile. |
| `category` | string | `all` | `bulk_scan` and `whale_discovery`. Values: `all`, `politics`, `crypto`, `sports`, `pop-culture`, `business`, `science`. Matching uses current Gamma event tags after case, whitespace, and hyphen normalization; no aliases are promised. |
| `whaleThreshold` | integer | `50000` | `whaleThreshold` is consumed only by `bulk_scan` and `whale_discovery`. It is the minimum estimated current USD value a wallet holds in the scanned market, summed over its outcomes (shares × current outcome price), not total wallet portfolio value; range `$1,000`–`$10,000,000`. |
| `tradeAlertThreshold` | integer | `10000` | Minimum USD trade size used by `alert_check` and supported trade-flow paths; range `$1,000`–`$1,000,000`. |
| `timeWindow` | string | `24h` | `1h`, `6h`, `24h`, `7d`, or `30d`. `timeWindow` applies to `market_analysis` trade lookback, optional `bulk_scan` trade flow, `alert_check` polling, and `whale_profile.recentActivity`; `whale_discovery` ignores it. It does not limit active positions or all-time closed-history summaries. Future/invalid timestamps are skipped. |
| `includeOrderbook` | boolean | `true` | `market_analysis` only. Other modes ignore it. |
| `includeTradeFlow` | boolean | `true` | `includeTradeFlow` is consumed only by `market_analysis` and `bulk_scan`. It analyzes public trades over `timeWindow`/`tradeAlertThreshold` where valid trades exist; it does not add CLOB orderbooks. |
| `topHoldersCount` | integer | `20` | `5`–`20`. The Actor requests and analyzes at most this many holders per outcome of each market. |
| `maxMarkets` | integer | `5` | `1`–`50`. Caps selected markets in `bulk_scan` and `whale_discovery`; it is a market cap, not an event cap. Both modes take the top N markets by each market's own 24h trading volume, drawn from the highest-volume active events, and `bulk_scan` rows are emitted in that order. |
| `minWinRate` | number | `0.5` | `whale_discovery` qualification filter for wallets with resolved history; candidates without resolved history are exempt and assessed by active position size; range `0`–`1`. |
| `minPnl` | number | `0` | `whale_discovery` historical P\&L filter for wallets with resolved history; candidates without resolved history are exempt and assessed by active position size; range `0`–`10,000,000`. |
| `maxWhales` | integer | `10` | `whale_discovery` output limit; range `1`–`50`. |
| `enableMlAnalysis` | boolean | `false` | Enables best-effort local ML work supported by the selected mode. No external AI API key or AI-provider fee is required. Normal PPE charges still apply; platform usage is included. Enrichment can be absent when data/features are insufficient. |
| `mlFeatures` | object | all toggles `true` | ML support is mode-specific: `market_analysis` can use all toggles; `bulk_scan` uses `statisticalEnhancement`; `alert_check` uses `anomalyDetection` and optional report generation; `whale_profile` uses report generation; `whale_discovery` currently has no ML post-processing path. Enrichment is optional and data/time dependent. |

### Output and billing semantics

Results are written to the default Dataset. `RUN_SUMMARY` in the default key-value store records fetched/skipped counts, output cardinality, partial failures, Gamma price fallbacks (`priceFallbackCount`), zero-result reason, and planned/actual PPE counts.

- `bulk_scan`: non-ML output is a flat array of market rows. When `enableMlAnalysis` and `statisticalEnhancement` produce eligible enrichment, the runtime can emit one `{ markets, mlInsights }` object instead. Neither shape emits `whaleSentimentScore`.
- `market_analysis`: flat market items. Output/PPE cardinality is the successfully analyzed and persisted market count, not the input slug count. `whaleBreakdown.holders` has one entry per distinct top-holder wallet (no `whaleThreshold` filter) and `totalWhales` counts them; `totalPositionValue` sums the wallet's outcomes, and `outcomeHoldings` lists each one as `outcomeIndex`, `side` (`YES` for the first outcome, `NO` otherwise), `shares`, and USD `value`. `smartMoneyConsensus` splits top-holder capital between the first outcome and the others, summed per holding; `concentrationHHI` is computed over each wallet's share of total top-holder value.
- `alert_check`: one item per successfully checked unique condition ID, including `newLargeTrades: 0` when the check ran successfully but found none.
- `whale_profile`: one item per successfully processed wallet.
- `whale_discovery`: one aggregate object with `whales`, `hotMarkets`, and `metadata`.

Since 1.0.9, holders on every outcome are included, so `smartMoneyConsensus`, `concentrationHHI`, and whale counts can differ from earlier runs for the same market. Earlier versions saw only the first outcome's holders, which biased consensus toward YES. Since 1.0.10, holders are counted per wallet, with value summed over outcomes, so `topHolderCount`, `totalWhales`, `totalPositionValue` and tier, `concentrationHHI`, `whale_discovery` tiers, and `hotMarkets` `whaleCount` can differ from 1.0.9: a wallet with $30k YES + $30k NO is now one whale, and a wallet with $200k on each outcome counts once.

Since 1.0.14, `winRate`, `totalPnl`, `roi`, and `resolvedTrades` (in `whale_profile`, `whale_discovery`, and `market_analysis` holders) come from the wallet's whole closed history, up to its 2,000 most recent positions. Earlier versions read only the Data API's default first page, the wallet's ten largest wins, so active wallets showed `resolvedTrades: 10` and `winRate: 1`, and `minWinRate` and `minPnl` filtered almost nothing. Since 1.0.14, `whaleSentiment` also counts trades by outcome, like `smartMoneyConsensus`: buying YES or selling another outcome is bullish, and buying NO or selling YES is bearish. Earlier versions counted every buy as bullish.

Dataset persistence happens before PPE charging. If Dataset persistence fails, charging is not attempted. If summary persistence fails after Dataset output, the run suppresses charging rather than risking duplicate customer-visible output or duplicate charges.

#### Illustrative `bulk_scan` item

This is an output shape illustration, not a runnable input.

```json
{
  "question": "Will Candidate X win the election?",
  "slug": "example-election-market",
  "eventSlug": "example-election-event",
  "conditionId": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "category": "Politics",
  "currentPrice": 0.52,
  "currentPriceOutcome": "Yes",
  "priceSource": "clob_midpoint",
  "priceFetchedAt": "2026-08-04T11:59:58.412Z",
  "volume24hr": 11503957.55,
  "healthScore": 65,
  "topHolderCount": 7,
  "tradeFlow": null,
  "metadata": {
    "generatedAt": "2026-08-04T12:00:00.000Z",
    "mode": "bulk_scan"
  }
}
```

### Cost control

This Actor uses Apify Pay Per Event pricing:

| Mode | PPE event | Price |
|---|---|---:|
| `bulk_scan` | `bulk_scan` | `$1.50` per eligible scan |
| `market_analysis` | `market_analysis` | `$0.15` per persisted market item |
| `alert_check` | `alert_check` | `$0.05` per check, whatever the number of checked condition IDs |
| `whale_profile` | `whale_profile` | `$0.25` per persisted wallet profile |
| `whale_discovery` | `bulk_scan` | `$1.50` per eligible scan |

Every run must allow at least `$1.50` of total charge; runs configured below that minimum are rejected before starting rather than finishing as an empty success. The cap bounds spend, it does not set it, so a one-wallet `whale_profile` run under a `$1.50` cap still charges `$0.25`.

Start with `maxMarkets: 5`, keep `topHoldersCount` at `20` or less, and enable orderbooks only for selected `market_analysis` runs. De-duplicate targets before repeated scheduled runs. Empty targets and zero eligible output do not plan the mode-specific PPE charge.

### Data sources and freshness

What each of the Gamma, Data, and CLOB APIs contributes is listed in the **Polymarket API without maintaining Gamma, Data, and CLOB pipelines** section above.

Each run is a snapshot of responses available during that run. `metadata.generatedAt` is Actor processing time, not an exchange settlement timestamp. Gamma's market prices are cached and can trail the order book by minutes, so `bulk_scan`, `whale_discovery`, and `market_analysis` price open markets from the CLOB order book, and `bulk_scan` rows and `market_analysis` `market` objects report it in `priceSource`/`priceFetchedAt`. Upstream API updates, event-tag taxonomy, late trades, and temporary source failures can change results between polls. Use Apify schedules for periodic snapshots; there is no streaming connection or push-notification channel in this Actor.

### FAQ

**Which Polymarket APIs does this Actor use?** Three public ones: Gamma (`gamma-api.polymarket.com`) for events, markets, tags, prices, and volume; Data (`data-api.polymarket.com`) for holders, trades, positions, closed positions, and activity; CLOB (`clob.polymarket.com`) for orderbooks in `market_analysis` with `includeOrderbook` enabled and for live market prices in `bulk_scan`, `whale_discovery`, and `market_analysis`. No Polymarket key or login is needed, and no browser is used.

**What wallet address format is accepted?** A trimmed value of lowercase `0x` followed by exactly 40 hexadecimal characters. Hex letters may be upper- or lowercase, duplicates are removed case-insensitively, and malformed values are rejected before any API work. Condition IDs follow the same rule with 64 hexadecimal characters.

**What does a whale profile contain?** `wallet`, a `summary` with `winRate`, `totalPnl`, `roi`, `resolvedTrades`, `activePositionValue`, and `activePositionCount`, the full `activePositions` array, up to 20 `recentActivity` entries inside `timeWindow`, and `metadata`. Win rate and P\&L come from closed positions only.

**How does alert mode work?** It polls. You supply condition IDs and run it on an Apify schedule; there is no streaming connection or push channel in the Actor. Each successfully checked unique condition ID produces one item, including a zero-trade summary, and matched items keep up to 10 trades. One run is one `$0.05` charge regardless of how many IDs it checked.

**Is there a minimum charge?** Each run must permit at least `$1.50` of total charge or the platform rejects it. Within that, you pay only for events actually charged: `$1.50` per eligible scan, `$0.25` per persisted wallet profile, `$0.15` per persisted market item, `$0.05` per check.

**Do I need wallet addresses before I start?** Only for `whale_profile`. Run `bulk_scan` or `whale_discovery` first to surface candidate wallets, then feed those addresses back in.

### Troubleshooting

**The Dataset is empty.** Check that the selected mode includes its required target field, that every target has the exact format above, and that the current source still exposes matching data. Omitting a required target field fails validation; an explicit empty target array intentionally returns zero items/no charge. Category scans can also return zero when current Gamma tags do not match.

**A scan returned fewer than `maxMarkets`.** `maxMarkets` is a ceiling. Category filtering, invalid source records, per-market API failures, or the run deadline can reduce the eligible output count.

**Trade flow is `null`.** No valid recent trades may remain after `timeWindow`, or the selected mode/source path may not provide trade-flow data. `timeWindow` does not remove active positions or all-time closed-history summaries.

**Orderbook data is missing.** Confirm the mode is `market_analysis`, `includeOrderbook` is `true`, and the source market has valid string CLOB token IDs. Malformed token IDs fail closed instead of reaching CLOB.

**A scheduled check found no large trades.** A successful `alert_check` still emits one summary per selected condition ID with zero matching trades, and plans exactly one `$0.05` check charge for the run. An empty target list emits nothing and plans no charge.

**The run is partial.** Inspect `RUN_SUMMARY` for partial failures, skipped records, time filtering, and planned/actual charge counts before retrying.

### Scheduling, API, MCP, and downstream automation

- **Schedules:** run the same bounded `alert_check` input periodically. Downstream notifications must be configured through Apify integrations or your own automation.
- **API:** call `jy-labs/polymarket-whale-tracker` with the same validated JSON used in Console, then read the default Dataset.
- **MCP/agents:** expose the Actor through your existing Apify MCP setup and pass the same input contract; MCP does not change output or billing cardinality.
- **Downstream:** key market workflows by `conditionId`/`eventSlug`, wallet workflows by wallet address, and read `RUN_SUMMARY` before deciding whether to retry a partial run.

#### Python API example

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("jy-labs/polymarket-whale-tracker").call(run_input={
    "mode": "bulk_scan",
    "category": "politics",
    "maxMarkets": 5,
    "whaleThreshold": 50000,
    "enableMlAnalysis": False,
})
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
print(items)
```

#### Scheduled-check API example

Replace the condition ID before running.

```bash
curl "https://api.apify.com/v2/acts/jy-labs~polymarket-whale-tracker/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "alert_check",
    "marketConditionIds": ["0x0000000000000000000000000000000000000000000000000000000000000000"],
    "tradeAlertThreshold": 10000,
    "timeWindow": "24h"
  }'
```

### Legal disclaimer

This Actor uses publicly available data for informational research. Computed metrics, classifications, and optional local ML output are not financial advice, trading recommendations, buy/sell signals, or guarantees. Prediction-market activity involves risk; independently verify source data and make your own decisions.

# Actor input Schema

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

Pick the workflow for this run.

- **1) Discovery** — use `bulk_scan` to scan active/high-volume markets for whale-heavy research signals ($1.50/scan).
- **2) Deep dive** — use `market_analysis` when you already know an event slug and need holder, orderbook, trade-flow, and whale metrics ($0.15/market).
- **3) Scheduled monitoring** — use `alert_check` with Apify schedules for scheduled/polled large-trade checks on known condition IDs ($0.05/check).
- **Wallet Profile** — use `whale_profile` to research provided wallet addresses, positions, P\&L, ROI, win rate, and recent public activity ($0.25/wallet).
- **Advanced Whale Discovery** — use `whale_discovery` to discover candidate whale wallets across active markets and summarize cross-market exposure ($1.50/scan via the bulk_scan PPE event).

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

market_analysis only. This field must be present for that mode. Values are trimmed, must match ^\[A-Za-z0-9]+(?:-\[A-Za-z0-9]+)\*$, and are de-duplicated in first-seen order. One event can resolve to multiple selected markets. An explicit empty array produces zero Dataset items and no mode-specific PPE charge.

## `marketConditionIds` (type: `array`):

alert_check only. This field must be present for that mode. Each trimmed value starts with lowercase 0x followed by exactly 64 hexadecimal characters. Hex letters may be upper- or lowercase; duplicates are removed case-insensitively. A successful check emits one Dataset item per selected unique condition ID, including zero-trade summaries. An explicit empty array produces zero Dataset items and no mode-specific PPE charge.

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

whale_profile only. This field must be present for that mode. Each trimmed value starts with lowercase 0x followed by exactly 40 hexadecimal characters. Hex letters may be upper- or lowercase; duplicates are removed case-insensitively. The Actor emits one Dataset item and plans one charge per successfully processed and persisted wallet profile. An explicit empty array produces zero Dataset items and no mode-specific PPE charge.

## `category` (type: `string`):

bulk_scan and whale_discovery only. Matches current Gamma event tags after case, whitespace, and hyphen normalization. Values: all, politics, crypto, sports, pop-culture, business, science. No aliases are promised, and current tag taxonomy can legitimately produce zero matches.

## `whaleThreshold` (type: `integer`):

bulk_scan and whale_discovery only. Minimum estimated current USD value a wallet holds in the scanned market, summed over every outcome it holds there (shares × current outcome price), not total wallet portfolio value. Each wallet counts once per market. Default: $50,000. Lower values include more wallets/signals.

## `tradeAlertThreshold` (type: `integer`):

Minimum individual trade size in USD for alert_check and supported market_analysis/bulk_scan trade-flow paths. Use alert_check with Apify schedules for polling, not streaming or push notifications. Default: $10,000.

## `timeWindow` (type: `string`):

Filters recent trades/activity only: market_analysis trade lookback; optional bulk_scan trade flow; alert_check polling; and whale_profile recentActivity. whale_discovery does not use this field. It does not limit active positions or all-time closed-history summaries. Future or invalid timestamps are skipped.

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

Include CLOB orderbook depth analysis in market_analysis only. Other modes ignore this setting.

## `includeTradeFlow` (type: `boolean`):

Consumed by market_analysis and bulk_scan only. Includes directional trade-flow analysis where valid recent trades exist. It does not add CLOB orderbooks and is ignored by alert_check, whale_profile, and whale_discovery.

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

Number of top holders requested and analyzed per outcome of each market in market_analysis, bulk_scan, and whale_discovery (5-20). Runtime requests and analyzes at most 20 holders per outcome.

## `maxMarkets` (type: `integer`):

Maximum number of markets to scan in bulk_scan or whale_discovery (1-50). For a first Discovery workflow run, start with 5 and increase after confirming output quality.

## `minWinRate` (type: `number`):

Optional for whale_discovery. Minimum historical win-rate filter for wallets with resolved trade history. Wallets without resolved history are evaluated by public position size instead.

## `minPnl` (type: `number`):

whale_discovery only. Minimum historical P\&L filter in USD for wallets with resolved history. Candidates without resolved history are exempt and assessed by active position size.

## `maxWhales` (type: `integer`):

Optional for whale_discovery. Maximum number of candidate wallets to include in the cross-market exposure summary.

## `enableMlAnalysis` (type: `boolean`):

Enable best-effort local ML work supported by the selected mode. No external AI API key or AI-provider fee is required. Normal PPE charges still apply; platform usage is included. Enrichment can be absent when data or feature prerequisites are insufficient; see mlFeatures for exact mode support.

## `mlFeatures` (type: `object`):

Mode-specific support: market_analysis can use all toggles; bulk_scan uses statisticalEnhancement; alert_check uses anomalyDetection and reportGeneration; whale_profile uses reportGeneration; whale_discovery currently has no ML post-processing path. Used only when Enable ML Analysis is on. Enrichment is best-effort, optional, and data/time dependent; unsupported or ineligible combinations leave base output unchanged. All toggles default to enabled.

## Actor input object example

```json
{
  "mode": "bulk_scan",
  "eventSlugs": [
    "presidential-election-winner-2028"
  ],
  "marketConditionIds": [],
  "walletAddresses": [],
  "category": "all",
  "whaleThreshold": 50000,
  "tradeAlertThreshold": 10000,
  "timeWindow": "24h",
  "includeOrderbook": true,
  "includeTradeFlow": true,
  "topHoldersCount": 20,
  "maxMarkets": 5,
  "minWinRate": 0.5,
  "minPnl": 0,
  "maxWhales": 10,
  "enableMlAnalysis": false,
  "mlFeatures": {
    "anomalyDetection": true,
    "whaleClustering": true,
    "statisticalEnhancement": true,
    "reportGeneration": true
  }
}
```

# Actor output Schema

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

Dataset containing structured analytics output. Each item represents one analyzed market (market_analysis, bulk_scan), one profiled wallet (whale_profile), one large-trade check result (alert_check), or a whale_discovery summary object.

# 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 = {
    "mode": "bulk_scan",
    "eventSlugs": [
        "presidential-election-winner-2028"
    ],
    "mlFeatures": {
        "anomalyDetection": true,
        "whaleClustering": true,
        "statisticalEnhancement": true,
        "reportGeneration": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jy-labs/polymarket-whale-tracker").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 = {
    "mode": "bulk_scan",
    "eventSlugs": ["presidential-election-winner-2028"],
    "mlFeatures": {
        "anomalyDetection": True,
        "whaleClustering": True,
        "statisticalEnhancement": True,
        "reportGeneration": True,
    },
}

# Run the Actor and wait for it to finish
run = client.actor("jy-labs/polymarket-whale-tracker").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 '{
  "mode": "bulk_scan",
  "eventSlugs": [
    "presidential-election-winner-2028"
  ],
  "mlFeatures": {
    "anomalyDetection": true,
    "whaleClustering": true,
    "statisticalEnhancement": true,
    "reportGeneration": true
  }
}' |
apify call jy-labs/polymarket-whale-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jy-labs/polymarket-whale-tracker"
        }
    }
}
```

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/e6sq7vzDqRUHXofzX/builds/LqHwGdVHVTlBsarej/openapi.json
