# Polymarket Whale Tracker - Large Trades & Holders (`dami_studio/polymarket-whale-tracker`) Actor

Large Polymarket trades as rows: the market question, which outcome, the side, the size in USDC, the fill price, the time, the transaction hash and the wallet that signed it. You set the size threshold. Optional trader positions and biggest market holders. No API key, no login, no wallet.

- **URL**: https://apify.com/dami\_studio/polymarket-whale-tracker.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Business, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 trade returneds

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/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 Whale Tracker: large trades and large holders

Every trade on Polymarket is public. That is the point of the thing. What is awkward is that the site
shows you the feed and not much else: you cannot ask it for "every fill over $25,000 in the last six
hours, across all markets, as a spreadsheet". This actor does that.

Give it a size threshold. It comes back with one row per trade at or above it: the market question,
which outcome was bought or sold, the side, the USDC that changed hands, the fill price, the time, the
transaction hash and the wallet that signed it. Newest first. No API key, no login, no wallet.

Measured on 19 September 2026: at a $10,000 threshold the feed reaches back about **15 days**; at
$25,000, about **50 days**, which is as far as Polymarket's public trade history goes. A 1,000-row pull
took **0.4 seconds** and 790 KB.

### What a row looks like

A real one, pulled on 19 September 2026:

```json
{
  "tradedAt": "2026-09-20T00:46:16.000Z",
  "timestamp": 1789865176,
  "marketQuestion": "San Francisco Giants vs. Los Angeles Dodgers",
  "outcome": "Los Angeles Dodgers",
  "outcomeIndex": 1,
  "side": "BUY",
  "sizeUsdc": 57915,
  "shares": 74250,
  "price": 0.78,
  "traderAddress": "0x67542c3219b37fd1610aad290676ff91cdbfe3bc",
  "traderDisplayName": "maz26",
  "traderPseudonym": "Boring-Musician",
  "transactionHash": "0x39d38c0c8c689f442400b3af49fb9e8c1108591997e72d3832aa1c7f7bcc14c6",
  "transactionUrl": "https://polygonscan.com/tx/0x39d38c0c8c689f442400b3af49fb9e8c1108591997e72d3832aa1c7f7bcc14c6",
  "conditionId": "0xf44e25ab6dca8a223af837ccc4e9b7de449a416cdf73497ccc2949edb4aad278",
  "tokenId": "78251986380619051387635942808796998910249321744606630518939476508285601480362",
  "marketSlug": "mlb-sf-lad-2026-09-19",
  "eventSlug": "mlb-sf-lad-2026-09-19",
  "marketUrl": "https://polymarket.com/event/mlb-sf-lad-2026-09-19",
  "fetchedAt": "2026-09-20T00:46:31.000Z"
}
```

74,250 shares of the Dodgers at 78 cents. $57,915 on one ticket, and you can click straight through to
the transaction.

### Input

The only field you really need is the threshold.

```json
{
  "minTradeSize": 25000,
  "sizeBasis": "usdc",
  "sinceHoursAgo": 24,
  "maxTrades": 500
}
```

Watching three particular markets instead, paste the links:

```json
{
  "minTradeSize": 5000,
  "markets": [
    "https://polymarket.com/event/will-the-us-invade-iran-in-2026",
    "cfb-flst-ala-2026-09-19",
    "0xf44e25ab6dca8a223af837ccc4e9b7de449a416cdf73497ccc2949edb4aad278"
  ],
  "maxTrades": 1000
}
```

Links, bare slugs and raw condition ids all work, mixed together.

Following particular wallets:

```json
{
  "traders": ["0x67542c3219b37fd1610aad290676ff91cdbfe3bc"],
  "minTradeSize": 1000,
  "includeTraderPosition": true
}
```

| Field | What it does |
|---|---|
| `minTradeSize` | The threshold. Trades below it are never fetched and never charged. |
| `sizeBasis` | `usdc` measures the money that changed hands. `shares` measures the contract count, which catches big positions bought cheaply at long odds. 100,000 shares at 3 cents is $3,000 of stake on a 33-to-1 shot. |
| `side` | `BUY`, `SELL` or both. |
| `sinceHoursAgo` | A time window. Leave it empty for none. |
| `markets` | Polymarket links, slugs or condition ids. Empty means every market at once. |
| `traders` | Wallet addresses to follow. |
| `maxTrades` | Where to stop. Up to 50,000 in one run. |
| `includeTraderPosition` | Adds what that wallet currently holds in that market: shares, average entry, current value, open profit or loss. |
| `includeMarketHolders` | Adds the biggest holders of each outcome in the markets your trades touch. |
| `topHoldersPerMarket` | How many of them. |

#### The two extras cost requests

`includeTraderPosition` asks Polymarket once per wallet-and-market pair, and `includeMarketHolders`
once per market. Both are cached inside a run, so following one wallet across forty of its trades in
one market is one extra request, not forty. Both are off unless you turn them on.

### Large holders

With `includeMarketHolders` on, each row carries the biggest holders of that market:

```json
"marketTopHolders": [
  { "address": "0x2c3350...", "displayName": null, "pseudonym": "Substantial-Service",
    "shares": 327378.01, "outcomeIndex": 0, "avgPrice": 0.4123,
    "currentValueUsd": 176785.2, "totalPnlUsd": 41712.6 }
]
```

That is the other half of the question. A $60,000 buy reads very differently depending on whether the
wallet behind it already held half a million shares or is arriving for the first time.

### About the addresses

A Polymarket trade is signed by a wallet, and a wallet is not a person.

`traderAddress` is a public blockchain address. `traderDisplayName` and `traderPseudonym` are the
labels Polymarket itself publishes next to that address on its own public feed: a handle somebody
typed into a profile box, and a nickname the site generated. Neither is verified, neither is checked
against anything, and two rows carrying the same display name do not have to be the same person.

This actor never tries to work out who a wallet belongs to. It looks addresses up nowhere except
Polymarket's own public feed. No name services, no labelling databases, no clustering, no linking
addresses to social accounts or anything else. If you need that, this is not the tool, and you should
think hard about whether you need it at all.

Some wallets come back with a display name Polymarket generated out of the address itself, like
`0x2c335066FE58...-1759935795465`. That is not a name, so the field is left null.

### Pricing

You pay per trade returned. Nothing else.

- **Sample rows are free.** Run it with empty input and you get one labelled sample row showing the
  shape, uncharged.
- **Trades that miss your filters are free**, because they are never returned. The size threshold runs
  on Polymarket's side, so smaller trades do not even cross the wire.
- **A run that finds nothing costs nothing** beyond starting the run.
- **The extras are free.** Positions and holder lists ride along on the rows you already paid for.

### What this does not do

Worth knowing before you buy.

- **Polymarket's public trade history stops at about 50 days.** Past that the trades are still on the
  Polygon blockchain, but they are not in the feed this reads, and no setting here will reach them.
- **How far back a run reaches depends on your threshold**, because the depth is counted in trades,
  not in days. At $1,000 a run of 10,000 trades covers about 15 hours. At $10,000 it covers about 15
  days. At $25,000 you hit the 50-day wall before you run out of rows.
- **There is no date filter on Polymarket's side.** `sinceHoursAgo` is applied as the trades come in,
  newest first, and the run stops once it is past your window. Asking for "trades from last March"
  would mean paging through everything since, so the actor does not offer it.
- **Combination markets come without an outcome label.** A market like "X wins AND Y wins" returns the
  question and the size but an empty outcome on Polymarket's side, so `outcome` is null. About 1 row
  in 100 at a $5,000 threshold.
- **One row is one fill, not one order.** A large order filled against six counterparties is six rows
  sharing a transaction hash. That is genuinely six trades; it is also why the row count can be higher
  than the number of orders you were expecting.
- **`sizeUsdc` is the money that moved, not a profit or a conviction.** Somebody selling a position is
  a large trade too. `side` tells you which.
- **No orderbook, no price history, no market list.** This returns trades and holders. If you want the
  full market catalogue with odds and volume, that is a different job.
- **It reads. It does not trade.** There is no wallet here, no key, no order placement, and there
  never will be.

### Questions people ask

**Do I need a Polymarket account or an API key?**
No. This reads Polymarket's public data API, which answers without any credential. The actor holds no
keys and asks you for none.

**How fresh is the data?**
The newest trade in a run was 0 seconds old on every check made on 19 September 2026. There is an
older, cached version of Polymarket's feed that runs about four minutes behind; this actor does not
use it.

**What counts as a whale?**
You decide. That is what `minTradeSize` is. $10,000 is a reasonable starting point; the largest single fill
seen while building this was $57,915.

**Can I run it on a schedule?**
Yes, and `sinceHoursAgo` is built for it. Set it a little longer than your schedule interval. Every
15 minutes with a 1-hour window means a slow run never leaves a gap.

**Why are two rows sharing a transaction hash?**
One order can fill against several counterparties in the same transaction. Each fill is its own row,
with its own size and price.

**Is `shares` or `usdc` the right threshold?**
`usdc` for "who is moving real money". `shares` for "who is taking a big swing at long odds", where
the stake is small but the position is enormous.

**Does it work on every market?**
Every market on Polymarket, including sports, politics, crypto and the rolling 15-minute markets. The
rolling markets do not carry an outcome index, so that field comes back null on them.

### Output

Rows land in the dataset. The run also writes a `RUN_REPORT` record to the key-value store with what
each search listed and returned, how many trades fell below the threshold or outside the window, which
markets could not be found, and why the run stopped. When something is missing, that is where it says
so.

# Actor input Schema

## `minTradeSize` (type: `integer`):

Only return trades at or above this size. Measured in USDC by default, so 10000 means trades where at least $10,000 changed hands. Polymarket applies this on its side, so smaller trades are never fetched and never charged.

## `sizeBasis` (type: `string`):

USDC measures the money that changed hands (shares x price). Shares measures the contract count, which picks up big positions bought cheaply at long odds.

## `side` (type: `string`):

Keep only buys, only sells, or both. Buy and sell are from the taker's point of view.

## `sinceHoursAgo` (type: `integer`):

Leave empty for no time limit. Polymarket has no date parameter, so the run reads newest first and stops once it is past your window.

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

Narrow the search to particular markets. Paste Polymarket links (https://polymarket.com/event/...), market slugs, or raw condition ids. Leave empty to watch every market at once.

## `traders` (type: `array`):

Narrow the search to particular wallets, as 0x addresses. Anything that is not a 0x address is skipped and reported rather than quietly widening the search.

## `maxTrades` (type: `integer`):

Stop after this many. A run tops out at 50,000; past that, add a time window or a market and run it again.

## `includeTraderPosition` (type: `boolean`):

Adds shares held, average entry price, current value and open profit or loss, as Polymarket publishes them. Costs one extra request per trader and market, so it makes a run slower.

## `includeMarketHolders` (type: `boolean`):

Adds the biggest holders of each outcome in the markets your trades touch. One extra request per market, whatever the number of trades in it.

## `topHoldersPerMarket` (type: `integer`):

Only used when the largest holders are switched on. Polymarket returns at most 500 per outcome.

## Actor input object example

```json
{
  "minTradeSize": 10000,
  "sizeBasis": "usdc",
  "side": "any",
  "sinceHoursAgo": 24,
  "markets": [],
  "traders": [],
  "maxTrades": 200,
  "topHoldersPerMarket": 10
}
```

# Actor output Schema

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

One row per trade at or above your size threshold, newest first. Optionally carries that wallet's current position in the market and the market's largest holders.

## `report` (type: `string`):

What each search listed and returned, how many trades fell below your threshold or outside your window, which markets could not be found, and why the run stopped.

# 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 = {
    "minTradeSize": 10000,
    "sizeBasis": "usdc",
    "side": "any",
    "sinceHoursAgo": 24,
    "markets": [],
    "traders": [],
    "maxTrades": 200,
    "includeTraderPosition": false,
    "includeMarketHolders": false,
    "topHoldersPerMarket": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/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 = {
    "minTradeSize": 10000,
    "sizeBasis": "usdc",
    "side": "any",
    "sinceHoursAgo": 24,
    "markets": [],
    "traders": [],
    "maxTrades": 200,
    "includeTraderPosition": False,
    "includeMarketHolders": False,
    "topHoldersPerMarket": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/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 '{
  "minTradeSize": 10000,
  "sizeBasis": "usdc",
  "side": "any",
  "sinceHoursAgo": 24,
  "markets": [],
  "traders": [],
  "maxTrades": 200,
  "includeTraderPosition": false,
  "includeMarketHolders": false,
  "topHoldersPerMarket": 10
}' |
apify call dami_studio/polymarket-whale-tracker --silent --output-dataset

```

## MCP server setup

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