The orderbook is a public endpoint — no authentication required. You can read prices and liquidity using the SDK or REST API directly.
import { ClobClient } from "@polymarket/clob-client";
const client = new ClobClient("https://clob.polymarket.com", 137);
Get the Orderbook
Fetch the full orderbook for a token, including all resting bid and ask levels:
const book = await client.getOrderBook("TOKEN_ID");
console.log("Best bid:", book.bids[0]);
console.log("Best ask:", book.asks[0]);
console.log("Tick size:", book.tick_size);
Response
{
"market": "0xbd31dc8a...",
"asset_id": "52114319501245...",
"timestamp": "2023-10-21T08:00:00Z",
"bids": [
{ "price": "0.48", "size": "1000" },
{ "price": "0.47", "size": "2500" }
],
"asks": [
{ "price": "0.52", "size": "800" },
{ "price": "0.53", "size": "1500" }
],
"min_order_size": "5",
"tick_size": "0.01",
"neg_risk": false,
"hash": "0xabc123..."
}
| Field | Description |
|---|
market | Condition ID of the market |
asset_id | Token ID |
bids | Buy orders sorted by price (highest first) |
asks | Sell orders sorted by price (lowest first) |
tick_size | Minimum price increment for this market |
min_order_size | Minimum order size for this market |
neg_risk | Whether this is a multi-outcome (neg risk) market |
hash | Hash of the orderbook state — use to detect changes |
Prices
Get the best available price for buying or selling a token:
const buyPrice = await client.getPrice("TOKEN_ID", "BUY");
console.log("Best ask:", buyPrice.price); // Price you'd pay to buy
const sellPrice = await client.getPrice("TOKEN_ID", "SELL");
console.log("Best bid:", sellPrice.price); // Price you'd receive to sell
Midpoints
The midpoint is the average of the best bid and best ask. This is the price displayed on Polymarket as the market’s implied probability.
const midpoint = await client.getMidpoint("TOKEN_ID");
console.log("Midpoint:", midpoint.mid); // e.g., "0.50"
If the bid-ask spread is wider than $0.10, Polymarket displays the last traded
price instead of the midpoint.
Spreads
The spread is the difference between the best ask and the best bid. Tighter spreads indicate more liquid markets.
const spread = await client.getSpread("TOKEN_ID");
console.log("Spread:", spread.spread); // e.g., "0.04"
Price History
Fetch historical price data for a token over various time intervals:
import { PriceHistoryInterval } from "@polymarket/clob-client";
const history = await client.getPricesHistory({
market: "TOKEN_ID", // Note: this param is named "market" but takes a token ID
interval: PriceHistoryInterval.ONE_DAY,
fidelity: 60, // Data points every 60 minutes
});
// Each entry: { t: timestamp, p: price }
history.forEach((point) => {
console.log(`${new Date(point.t * 1000).toISOString()}: ${point.p}`);
});
| Interval | Description |
|---|
1h | Last hour |
6h | Last 6 hours |
1d | Last day |
1w | Last week |
1m | Last month |
max | All available data |
interval is relative to the current time. Use startTs / endTs for
absolute time ranges. They are mutually exclusive — don’t combine them.
Estimate Fill Price
Calculate the effective price you’d pay for a market order of a given size, accounting for orderbook depth:
import { Side, OrderType } from "@polymarket/clob-client";
// What price would I pay to buy $500 worth?
const price = await client.calculateMarketPrice(
"TOKEN_ID",
Side.BUY,
500, // dollar amount
OrderType.FOK,
);
console.log("Estimated fill price:", price);
This walks the orderbook to estimate slippage. Useful for sizing market orders before submitting them.
Batch Requests
All orderbook queries have batch variants for fetching data across multiple tokens in a single request (up to 500 tokens):
| Single | Batch | REST |
|---|
getOrderBook() | getOrderBooks() | POST /books |
getPrice() | getPrices() | POST /prices |
getMidpoint() | getMidpoints() | POST /midpoints |
getSpread() | getSpreads() | POST /spreads |
getLastTradePrice() | getLastTradesPrices() | — |
BookParams for batch orderbook requests accepts a token_id and an optional
side parameter to filter by bid or ask side.
import { Side } from "@polymarket/clob-client";
// Fetch prices for multiple tokens
const prices = await client.getPrices([
{ token_id: "TOKEN_A", side: Side.BUY },
{ token_id: "TOKEN_B", side: Side.BUY },
]);
// Returns: { "TOKEN_A": { "BUY": "0.52" }, "TOKEN_B": { "BUY": "0.74" } }
Last Trade Price
Get the price and side of the most recent trade for a token:
const lastTrade = await client.getLastTradePrice("TOKEN_ID");
console.log(lastTrade.price, lastTrade.side);
// e.g., "0.52", "BUY"
Real-Time Updates
For live orderbook data, use the WebSocket API instead of polling. The market channel streams orderbook changes, price updates, and trade events in real time.
Connecting
const ws = new WebSocket(
"wss://ws-subscriptions-clob.polymarket.com/ws/market",
);
ws.onopen = () => {
ws.send(
JSON.stringify({
type: "market",
assets_ids: ["TOKEN_ID"],
custom_feature_enabled: true, // enables best_bid_ask, new_market, market_resolved events
}),
);
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.event_type) {
case "book": // full orderbook snapshot
case "price_change": // individual price level update
case "last_trade_price": // new trade executed
case "tick_size_change": // market tick size changed
case "best_bid_ask": // top-of-book update (requires custom_feature_enabled)
case "new_market": // new market created (requires custom_feature_enabled)
case "market_resolved": // market resolved (requires custom_feature_enabled)
}
};
Dynamic Subscribe and Unsubscribe
After connecting, you can change your subscriptions without reconnecting:
// Subscribe to additional tokens
ws.send(
JSON.stringify({
assets_ids: ["NEW_TOKEN_ID"],
operation: "subscribe",
}),
);
// Unsubscribe from tokens
ws.send(
JSON.stringify({
assets_ids: ["OLD_TOKEN_ID"],
operation: "unsubscribe",
}),
);
Event Types
| Event | Trigger | Key Fields |
|---|
book | On subscribe + when a trade affects the book | bids[], asks[], hash, timestamp |
price_change | New order placed or order cancelled | price_changes[] with price, size, side, best_bid, best_ask |
last_trade_price | Trade executed | price, side, size, fee_rate_bps |
tick_size_change | Price hits >0.96 or < 0.04 | old_tick_size, new_tick_size |
best_bid_ask | Top-of-book changes | best_bid, best_ask, spread |
new_market | Market created | question, assets_ids, outcomes |
market_resolved | Market resolved | winning_asset_id, winning_outcome |
best_bid_ask, new_market, and market_resolved require
custom_feature_enabled: true in your subscription message.
The tick_size_change event is critical for trading bots. If the tick size
changes and you continue using the old tick size, your orders will be
rejected.
Next Steps