Kalshi Whale Tracker (2026): How to Spot Big Trades With the API
The Short Answer
Kalshi's public trade data carries no account, user or wallet identifiers, so a Kalshi whale tracker follows size rather than people. The Trade API's GET /markets/trades needs no key and returns every trade with its market, contract count, prices, the taker's side, a block-trade flag and a timestamp, up to 1,000 per page. There is no size filter, so you compute each trade's dollar value in your own code. For a live feed, the WebSocket trade channel pushes every trade as it happens, though the connection needs an API key. In our checks on 3 October 2026, ten minutes of tape held 99,407 trades, and just 2 were worth $10,000 or more once combos and extreme prices were set aside.
Key Takeaways
- Kalshi trades carry no trader identity, so a whale on Kalshi is a large trade or a large resting order, not an account you can follow.
GET /markets/tradesis public, returns up to 1,000 trades a page with a cursor, and filters byticker,min_tsandmax_ts.- There is no size parameter: multiply
count_fpby the price of the taker's side and filter the dollar value yourself. - Many of the biggest prints are near-certain bets at 99 cents or more and combo markets, so filter those out before calling anything a whale.
- The order book is public and shows total size per price level, while Kalshi's WebSocket needs a signed connection.
Can you track whales on Kalshi?
Not the way people track them on Polymarket, where every trade is tied to a public wallet, as covered in the Polymarket Data API guide. Kalshi's public trade record has no account field at all. Kalshi does run an opt-in leaderboard and Kalshi Social profiles inside its app, but neither shows up in the trade data the API serves.
So a Kalshi whale tracker answers different questions: where large money is trading, which side it took, and where large size is waiting in the book. That still tells you a lot. A trader who takes the No side of a college football spread for 35,000 contracts at 49 cents has a strong view, whoever they are.
How do you get Kalshi trades from the API?
Call GET /markets/trades on https://external-api.kalshi.com/trade-api/v2. It is public, so there is no key and no signature.
| Parameter | What it does |
|---|---|
limit | Trades per page, from 1 to 1,000, default 100 |
cursor | The cursor from the previous page; an empty cursor means the last page |
ticker | Limits results to one market |
min_ts, max_ts | The time window, as Unix timestamps in seconds |
is_block_trade | true for block trades only, false to leave them out |
Each trade holds a trade_id, the market ticker, count_fp (contracts as a string such as "136.00"), yes_price_dollars and no_price_dollars, taker_outcome_side, is_block_trade and created_time. taker_outcome_side is the side the taker ended up on, so buying yes and selling no both count as yes. Skip the older taker_side, which Kalshi has deprecated.
Trades arrive newest first, and the live endpoint only covers trades since the historical cutoff, which was 3 August 2026 when we checked. Older trades come from GET /historical/trades, covered in Kalshi historical data.
This pulls the last five minutes of trades across every market and keeps the ones worth $5,000 or more, on Node 18 or newer with no dependencies:
const BASE = 'https://external-api.kalshi.com/trade-api/v2';
const since = Math.floor(Date.now() / 1000) - 300; // the last five minutes, in Unix seconds
const trades = [];
let cursor = '';
do {
const page = await (await fetch(`${BASE}/markets/trades?limit=1000&min_ts=${since}&cursor=${cursor}`)).json();
trades.push(...page.trades);
cursor = page.cursor;
} while (cursor);
const takerPrice = (t) => Number(t.taker_outcome_side === 'yes' ? t.yes_price_dollars : t.no_price_dollars);
const usd = (t) => Number(t.count_fp) * takerPrice(t);
const whales = trades.filter((t) => usd(t) >= 5_000);
console.log(trades.length, 'trades,', whales.length, 'worth $5,000 or more');
console.table(whales.map((t) => ({ market: t.ticker, taker: t.taker_outcome_side, contracts: t.count_fp, usd: Math.round(usd(t)) })));
Contracts times the price of the taker's side gives the trade's dollar size. Contract counts alone mislead: 10,000 contracts at 2 cents is a $200 trade. Five minutes of the whole exchange took about 60 requests and 30 seconds to page through in our checks, and each request costs 10 rate-limit tokens by default, as explained in Kalshi API rate limits. Add &ticker= to follow one market.
How do you filter Kalshi trades by size?
A dollar threshold is only the start. Two more steps separate conviction from noise.
Drop near-certain prices and combos. Many of the largest prints come from someone paying 99 cents or more for an outcome that is all but decided, such as a 15-minute Bitcoin market minutes before it closes, or a combo market priced at 99.9 cents. Kalshi's combo markets all have tickers starting with KXMVE. In a ten-minute window on 3 October 2026, 20 trades were worth $10,000 or more. After removing combos, which made up 14% of all trades, and trades priced below 5 cents or above 95 cents, only 2 remained.
Group the prints of one order. Kalshi defines a trade as a completed transaction between two users, so a taker order that fills against several resting orders shows up as several trades. In our data, those prints shared the same market, taker side and timestamp, down to the microsecond:
const contested = (t) => !t.ticker.startsWith('KXMVE') && takerPrice(t) >= 0.05 && takerPrice(t) <= 0.95;
const orders = new Map();
for (const t of trades.filter(contested)) {
const key = `${t.ticker}|${t.created_time}|${t.taker_outcome_side}`;
const o = orders.get(key) ?? { market: t.ticker, time: t.created_time, taker: t.taker_outcome_side, prints: 0, usd: 0 };
o.prints += 1;
o.usd += usd(t);
orders.set(key, o);
}
const bigOrders = [...orders.values()].filter((o) => o.usd >= 5_000).sort((a, b) => b.usd - a.usd);
console.table(bigOrders.map((o) => ({ ...o, usd: Math.round(o.usd) })));
This reuses trades, takerPrice and usd from the block above. Kalshi does not label which prints belong together, so treat a group as a likely single order, not a certainty. In one five-minute window, 11 prints at the same instant added up to $41,324 on No for South Carolina winning by more than 2.5 points, and 16 prints added up to $17,761 on Yes for the Democrats in the 2026 Texas Senate race.
What are block trades on Kalshi?
Block trades are large trades agreed between two parties and reported to Kalshi rather than matched on the order book. Kalshi's help center sets the rules: both parties must be Eligible Contract Participants, the minimum is 25,000 contracts, separate orders cannot be combined to reach it, and the trade must be reported within 15 minutes of agreement.
In the API, block trades sit in the same feed with is_block_trade set to true, and is_block_trade=true returns only those. They are rare. On 3 October 2026, a block-trade query over the previous 24 hours came back empty, and the same query over a week across every market timed out, so scope block searches to a ticker or a short window. Kalshi's request for quote system, one route to a block, is covered in the Kalshi RFQ API guide.
How do you stream Kalshi trades in real time?
A live tracker should listen rather than page. Kalshi's WebSocket at wss://external-api-ws.kalshi.com/trade-api/ws/v2 has a public trade channel, and without a market filter it sends every trade on the exchange as it executes. The catch is the handshake: it must be signed with an API key even though the channel carries public data, and in our checks an unsigned handshake was refused with HTTP 401.
import { createPrivateKey, sign, constants } from 'node:crypto';
import { readFileSync } from 'node:fs';
const key = createPrivateKey(readFileSync('kalshi-private-key.pem', 'utf8'));
const KEY_ID = 'YOUR_KEY_ID';
const MIN_USD = 5_000;
function signText(text) {
const data = Buffer.from(text);
const sig = key.asymmetricKeyType === 'ed25519'
? sign(null, data, key)
: sign('sha256', data, { key, padding: constants.RSA_PKCS1_PSS_PADDING, saltLength: constants.RSA_PSS_SALTLEN_DIGEST });
return sig.toString('base64');
}
const ts = String(Date.now());
const ws = new WebSocket('wss://external-api-ws.kalshi.com/trade-api/ws/v2', {
headers: {
'KALSHI-ACCESS-KEY': KEY_ID,
'KALSHI-ACCESS-TIMESTAMP': ts,
'KALSHI-ACCESS-SIGNATURE': signText(ts + 'GET' + '/trade-api/ws/v2'),
},
});
ws.onopen = () => ws.send(JSON.stringify({ id: 1, cmd: 'subscribe', params: { channels: ['trade'] } }));
ws.onmessage = ({ data }) => {
const frame = JSON.parse(data);
if (frame.type !== 'trade') return;
const t = frame.msg;
const price = Number(t.taker_outcome_side === 'yes' ? t.yes_price_dollars : t.no_price_dollars);
const usd = Number(t.count_fp) * price;
if (usd >= MIN_USD) console.log(new Date(t.ts_ms).toISOString(), t.market_ticker, t.taker_outcome_side, t.count_fp, Math.round(usd));
};
ws.onclose = (e) => console.log('closed', e.code);
The signed string is the millisecond timestamp, then GET, then /trade-api/ws/v2. Kalshi selects Ed25519 by default when you create a key and still accepts RSA keys, which sign with RSA-PSS over SHA-256, so the function handles both. We ran this on Node 24, whose built-in WebSocket accepts the headers option, as does the ws package. Messages carry the REST fields, with the market under market_ticker and the time as ts_ms. Keys are covered in how to get a Kalshi API key.
Can you see large resting orders in Kalshi's order book?
Yes, as totals per price. GET /markets/{ticker}/orderbook is public: Kalshi's guide says no authentication is required, and our anonymous calls returned full books. It returns yes_dollars and no_dollars, two lists of [price, contracts] bids sorted from lowest to highest price. A no bid at a price is a yes offer at one dollar minus that price. Each level is a total, so you cannot see who is behind it or how many orders it holds.
This lists the large levels within five cents of the best bid and offer:
const BASE = 'https://external-api.kalshi.com/trade-api/v2';
const ticker = 'SENATETX-26-D';
const MIN_CONTRACTS = 10_000;
const { orderbook_fp: book } = await (await fetch(`${BASE}/markets/${ticker}/orderbook`)).json();
const bids = book.yes_dollars.map(([p, size]) => ({ side: 'yes bid', price: Number(p), contracts: Number(size) }));
const asks = book.no_dollars.map(([p, size]) => ({ side: 'yes ask', price: Number((1 - Number(p)).toFixed(4)), contracts: Number(size) }));
const bestBid = Math.max(...bids.map((l) => l.price));
const bestAsk = Math.min(...asks.map((l) => l.price));
const walls = [...bids, ...asks].filter((l) =>
l.contracts >= MIN_CONTRACTS && l.price >= bestBid - 0.05 && l.price <= bestAsk + 0.05);
console.table(walls.sort((a, b) => b.contracts - a.contracts));
The five-cent band matters because the biggest levels can sit far from the market. On the Texas Senate market on 3 October 2026, the largest were 5.1 million contracts offered at 99.9 cents and 2.2 million bid at 0.1 cents, while the market quoted 63 cents bid and 64 offered. Inside the band, the largest was 62,145 contracts bid at 60 cents.
To scan many markets, GET /markets/orderbooks returns up to 100 books per call, with the tickers parameter repeated once per market. For live changes, the orderbook_delta WebSocket channel sends a snapshot and then deltas, as covered in the Kalshi order book API guide.
How do you watch big trades across venues?
Size means more in context. The same event often trades on Kalshi and Polymarket at once, and a big print on one venue reads differently when the other is quiet. The Predictefy API returns Kalshi's recent trades through client.kalshi.fetchTrades, the same call it uses for other venues' tapes, and its WebSocket streams Kalshi trades next to them, so one size filter covers every venue you follow.
A big trade shows that someone committed money, not that they are right, and following it carries the same risk as any other trade.
Frequently Asked Questions
Can you see who is trading on Kalshi?
No. Kalshi's public trade data has no account, user or wallet field. Each trade shows the market, contract count, prices, the taker's side, a block-trade flag and the time. Kalshi's opt-in leaderboard and social profiles live in its app and are not attached to trades in the API.
How do I find large trades on Kalshi?
Page through GET /markets/trades with min_ts set to the start of your window, multiply each trade's count_fp by the price of the taker's side, and keep trades above your dollar threshold. The endpoint is public and returns up to 1,000 trades per page.
What is a block trade on Kalshi?
A trade of at least 25,000 contracts agreed between two Eligible Contract Participants and reported to Kalshi within 15 minutes, instead of being matched on the order book. In the API, block trades carry is_block_trade set to true.
Does the Kalshi trades API need an API key?
Not over REST. GET /markets/trades, GET /historical/trades and the order book endpoints are public. The WebSocket connection must be signed with an API key, even for the public trade channel.
Can you see large orders in the Kalshi order book?
You can see large resting size, not individual orders. GET /markets/{ticker}/orderbook returns the total contracts bid at each price for yes and no, with no order IDs or owners.