Polymarket API Rate Limits, WebSocket Streaming, and Best Practices
Technical reference covering Polymarket CLOB API rate limit tiers, how to maintain a low-latency WebSocket connection for real-time order book updates, and reconnection strategies for production trading systems.
Polymarket's CLOB runs on a hybrid architecture: an off-chain Central Limit Order Book matching engine backed by on-chain settlement on Polygon. That split means you have two independent data surfaces to manage — the REST/WebSocket API for order book state and order management, and the chain itself for settlement confirmation and position reconciliation. Both have limits that will bite you if you treat them as an afterthought.
The Two API Surfaces and Their Rate Limits
The Gamma API (https://gamma-api.polymarket.com) serves market metadata, historical data, and enriched market information. It is unauthenticated for read operations and tolerates roughly 600 requests per minute per IP on most endpoints before returning 429s. Use it for initial market discovery, condition ID lookups, and historical price series — not for anything latency-sensitive.
The CLOB API (https://clob.polymarket.com) is the trading surface. It handles order placement, cancellation, and order book queries. The effective limits here are tighter:
- Unauthenticated reads (order book snapshots, mid-price): ~120 requests per minute per IP
- Authenticated order operations (POST to
/order, DELETE to/order): rate limited at the account level. Current production behavior is roughly 10 order actions per second before the exchange returns aTooManyRequestsError. Burst headroom exists but is short — expect hard rejection after ~15 queued actions without spacing. GET /ordersand fill history endpoints: treated as heavy reads, budget ~30 requests per minute per API key
These numbers are not formally published in SLA form. They are observed behavior from running production bots, and they shift during periods of high market activity. Instrument every response and track your 429 rate continuously — it is the clearest signal you have that you are approaching a ceiling.
WebSocket Subscriptions: What to Use and How
The CLOB WebSocket lives at wss://ws-subscriptions-clob.polymarket.com/ws/. After connecting, you subscribe by sending a JSON frame. Two channel types matter most for bot builders:
market channel — public, unauthenticated. Subscribe by passing a market object with an assets_ids array containing the asset_id values (one per order book side — YES and NO tokens each have their own ID). You receive:
- Full L2 book snapshots on subscribe
- Incremental diff updates on every book change: price level, size, and side
- Trade prints as they occur
Apply diffs in sequence against a local book. Do not re-snapshot via REST unless you detect a sequence gap.
user channel — authenticated. Requires an apiKey, secret, and passphrase in the subscription payload (L1 authentication using your API credentials, distinct from your on-chain signing key). Delivers:
- Fill events tied to your API key
- Order state transitions (acknowledged, matched, cancelled)
- Position updates
For most strategies, the user channel is the correct fill source. Reconciling your inventory from userFills events is significantly more reliable than polling /orders on a timer — and avoids hammering the authenticated read budget.
Keeping the Connection Alive
The server issues a ping frame every 10 seconds. If your client does not respond with a pong within a reasonable window (empirically 30 seconds), the connection is silently dropped. Many WebSocket libraries handle this automatically, but verify: some Node.js libraries require an explicit autoPong option; Python's websockets library handles it by default but only if you are in the async recv() loop.
Beyond the ping cycle, you should treat connection loss as a scheduled event, not an exception. In volatile periods — tight elections, rapidly-resolving markets — the CLOB WebSocket will disconnect under load. Every bot we have shipped implements:
- Exponential backoff reconnect starting at 500ms, capping at 30 seconds, with jitter to avoid thundering-herd on large events
- A full re-snapshot on reconnect before resuming diff processing
- A staleness timer: if no update arrives within 45 seconds on an active market, treat the connection as silently dead and reconnect immediately rather than waiting for a ping timeout
Order Placement: Signing and Submission
Every order is a typed EIP-712 message signed with your L1 private key (the Ethereum key associated with your Polymarket account), not an API key. The py-clob-client library handles struct encoding and signing, but the key hierarchy matters: your signing key authorizes trading on your account, so keep it separate from the wallet that holds collateral. Exposure of the trading key allows order manipulation; exposure of the collateral wallet allows fund theft. Treat them as distinct threat models.
For batch operations, the /orders POST endpoint accepts arrays. Grouping multi-leg entries — for example, entering both YES and NO positions as part of a market-neutral book — into a single signed request keeps your order action count down and reduces the window for partial fills.
Always include a clientOrderId (a UUID you generate) on every order. The CLOB returns fills tagged with this ID, which makes inventory reconciliation deterministic even if you restart mid-session. Without it, matching your open orders to your fill stream degrades to fuzzy timestamp matching.
Production Patterns That Actually Matter
A few things learned from running this in production:
Pre-flight simulation before live capital. The Gamma API exposes historical order book snapshots. Build a replay harness that runs your quoting logic against recorded sessions before touching a live market. Resolution criteria mismatches — especially around early-settlement and void conditions — are easiest to catch here.
Sequence gap detection. The CLOB WebSocket does not expose a sequence number on public channels, but you can detect missed updates by tracking book consistency: if a diff references a price level that does not exist in your local book, you have a gap. Trigger an immediate REST snapshot and reconnect.
Quota-aware order manager. Implement a token bucket in front of every /order POST call. Fill the bucket at 8 tokens per second (below the ~10 limit, leaving headroom for spikes), and block rather than drop when empty. Dropping requests silently introduces inventory drift; blocking makes the constraint visible in your latency metrics.
Track taker fees in your fill logic. Polymarket charges a fee on winning trades (currently 2% of profit on winning positions). Your PnL calculation must account for this or your edge estimates will be systematically overstated on the profitable side.
For the full picture of how we wire these details into a production arbitrage system — including multi-market inventory management and kill-switch logic — see the cross-market arbitrage article. The trading-bot services page covers how we scope and build CLOB integrations end to end.
If you are building a Polymarket bot and want production infrastructure rather than prototype code, talk to us — we have shipped this stack and can move fast.
Need a bot like this built?
We design, build and run trading bots on Solana, Hyperliquid and Polymarket.
Start a projectMore from the blog
Public vs Paid RPC: How to Run a Fair Benchmark
A fair comparison of public and paid RPC endpoints must account for quotas, workload, freshness and support guarantees.
Read articleRPC Benchmark Percentiles Explained: p50, p95 and p99
Why averages hide the latency spikes that break trading bots, wallets and production blockchain applications.
Read articleHyperliquid REST vs WebSocket Benchmark: What to Measure
A benchmark plan for Hyperliquid market data that separates request latency from streaming freshness and recovery.
Read article