API · Reference

Polymarket has two realtime systems, on two different hosts. The CLOB WebSocket streams the order book and your own order updates; the RTDS feed streams live price data (crypto, equities) and comments. Mixing the two up is the most common mistake. This page keeps them straight, with the exact endpoints, the heartbeat, and a correct reconnect.

The two hosts
  • CLOB: wss://ws-subscriptions-clob.polymarket.com/ws/ · channels market (public, order book), user (auth, your orders/fills), sports (live game state for sports markets), and an rfq gateway (live Request-for-Quote state - see the RFQ section).
  • RTDS: wss://ws-live-data.polymarket.com · topics crypto_prices, crypto_prices_chainlink, equity_prices, comments.

CLOB market channel (no auth)

Subscribe to one or more token IDs and receive the order book and updates: an initial book snapshot, then price_change, tick_size_change and last_trade_price events. No credentials needed.

import asyncio, json, websockets

async def stream(token_ids):
    url = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
    async with websockets.connect(url, ping_interval=10) as ws:
        await ws.send(json.dumps({"assets_ids": token_ids, "type": "market"}))
        async for msg in ws:
            evt = json.loads(msg)
            print(evt.get("event_type"), evt)

asyncio.run(stream([TOKEN_ID]))
import WebSocket from "ws";
const ws = new WebSocket("wss://ws-subscriptions-clob.polymarket.com/ws/market");
ws.on("open", () => ws.send(JSON.stringify({ assets_ids: [TOKEN_ID], type: "market" })));
ws.on("message", (d) => console.log(JSON.parse(d)));

CLOB user channel (auth)

The user channel reports your order lifecycle (placements, matches, cancels). It needs your API key/secret/passphrase and you subscribe by condition_id (market), not token ID. Connect to wss://ws-subscriptions-clob.polymarket.com/ws/user and include your auth in the subscribe payload:

await ws.send(json.dumps({
    "type": "user",
    "markets": [CONDITION_ID],          # subscribe by condition_id, not token_id
    "auth": {"apiKey": API_KEY, "secret": SECRET, "passphrase": PASSPHRASE},
}))
# events: "order" (placed/cancelled) and "trade" (your fills)

RTDS price feeds

A separate host, wss://ws-live-data.polymarket.com, for live price data, not order books. Subscribe to a topic: crypto_prices (Binance), crypto_prices_chainlink (Chainlink oracle), equity_prices, or comments. Useful for the underlying signal in crypto/equity prediction-market bots.

Heartbeat & reconnect

  • Heartbeat: send a PING roughly every 10 seconds; the server replies PONG. Miss it and the connection drops.
  • Modify live: you can add/remove topics or assets on an open connection; you don't need to reconnect to change your subscription.
  • Reconnect correctly: after any drop, re-fetch the REST order-book snapshot (GET /book) before trusting incremental updates again. Streamed deltas you missed while disconnected are gone; the REST snapshot re-syncs your local book.

The whole pattern in one resilient loop - heartbeat, reconnect with backoff, and a REST resync on every (re)connect:

import asyncio, json, time, requests, websockets

async def resilient_stream(token_id, on_event):
    url = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
    backoff = 1
    while True:
        try:
            async with websockets.connect(url, ping_interval=10) as ws:
                # 1) REST snapshot first so the local book is correct before deltas
                book = requests.get("https://clob.polymarket.com/book",
                                    params={"token_id": token_id}).json()
                on_event({"event_type": "snapshot", "book": book})
                # 2) subscribe and stream
                await ws.send(json.dumps({"assets_ids": [token_id], "type": "market"}))
                backoff = 1                       # reset after a clean connect
                async for msg in ws:
                    on_event(json.loads(msg))
        except Exception as e:
            print("ws drop, resync in", backoff, "s:", e)
            await asyncio.sleep(backoff)
            backoff = min(backoff * 2, 30)        # exponential backoff, capped
Don't confuse the hosts. Order books and your orders come from the CLOB host (ws-subscriptions-clob); crypto/equity prices and comments come from RTDS (ws-live-data). They are different services with different payloads.

Next: CLOB REST reference · Rate limits & backoff · Build: stream the book in a bot.