How to stream a prediction market order book
Five live book feeds across four venues, and the parts that decide whether your local book is right — deltas versus replacements, missed messages, reconnects.
Pick the venue first. Polymarket's market channel is keyless and sends a book snapshot then price changes; Kalshi signs even its public handshake and sends deltas; Limitless replaces the whole book each frame; Polymarket US puts its markets stream behind the same identity check as trading. The feed is the easy half. Keeping a local book that still matches the venue is the rest of it.
The short way
Two things decide the shape of the code, and neither of them is the language you write it in: whether the venue sends you the changes to a book or the whole book each time, and whether you are allowed to connect at all without an account.
If you just want a live ladder on screen today, start with
the Polymarket CLOB API, because it is the only one here that takes
no credentials. Open the market channel, send one subscribe frame naming the outcome token ids you
care about, and the server answers with a book event — the full bids and asks with a hash and a
timestamp — followed by price_change as levels move, last_trade_price when a trade prints, and
tick_size_change when the price crosses into the finer grid near the ends.
import json
from websockets.sync.client import connect
# Outcome token ids come from the catalogue side of Polymarket, not from here.
URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
with connect(URL) as ws:
ws.send(json.dumps({"assets_ids": [TOKEN_ID], "type": "market"}))
for raw in ws:
message = json.loads(raw)
# `book` is the snapshot. `price_change` moved a level. `last_trade_price` was a fill.
Two details from Polymarket's own streaming notes will bite the first version of that loop. You are
expected to send a PING roughly every ten seconds and the server answers PONG; go quiet and the
connection goes. And price_change fires when an order is placed or cancelled, which is not a
trade — last_trade_price is the event that means somebody was filled. The token ids themselves
come from the Gamma API, which is the catalogue half of the same
integration.
If the reader is in the United States, none of that is the answer, because trading on that platform is not open to them. The two US-accessible streams both sit behind an account.
What the options are
The Kalshi API is the most conventional feed in this category and the one closest to a futures venue: the WebSocket carries incremental order book updates, market tickers, public trades and your own fills, and it is the exchange's own record rather than a reconstruction. The catch is at the handshake rather than in the data. The socket is not public — the connection itself returns 401 without signed headers, even for channels that only carry public information, so there is no keyless live stream and no way to prototype one. The key is an RSA key pair generated inside an account that has already passed identity verification.
pykalshi is where the delta arithmetic stops being your problem. It is a
third-party MIT client, one author, five runtime dependencies, and its OrderbookManager applies
the deltas and hands back the current book; the typed messages — tickers, order book snapshots and
deltas, trades — arrive as an async iterator you can pattern-match on, with automatic retries and
typed errors around them. That is the piece every market-making script otherwise writes badly once.
It is one person's library, it does not cover the whole API by its own admission, and it learns
about an API change when something breaks.
The Limitless API is the odd one out and usefully so. Real time is Socket.IO
at a /markets namespace, and the public market-data events need no signed handshake at all;
subscribe_market_prices takes market addresses for its AMM markets and market slugs for its CLOB
markets, and the server emits one orderbookUpdate per subscribed slug straight away. What arrives
is a complete book replacement rather than a delta — bids highest-first, asks lowest-first, the
whole current state, coalesced so that several changes in quick succession arrive as one message.
Each frame carries a version that increases per market, which the documentation suggests using to
drop a frame that arrives out of order just after you resubscribe. The server runs the heartbeat
itself, and the docs ask you not to send PING frames of your own.
The Polymarket US API is the US-regulated counterpart, and its split
between hosts is the whole story: the public gateway serves the book over REST with no credentials,
while the markets stream lives on the authenticated host at /v1/ws/markets and takes the same
API-key headers as every write. Subscriptions are typed — a full order book with market statistics,
a lite variant carrying price data only, and a separate trade subscription — and each one is capped
at 100 markets, with more subscriptions rather than a higher cap as the documented way past it. The
server sends a {"heartbeat": {}} message periodically, and the guidance for everything else is
exponential backoff.
{
"subscribe": {
"requestId": "book-1",
"subscriptionType": "SUBSCRIPTION_TYPE_MARKET_DATA",
"marketSlugs": ["your-market-slug"]
}
}
The credential that opens that socket is created from a developer portal on an account opened in the venue's iOS app, after identity verification — so the stream is gated by the same thing the orders are. Placing an order from code is the other half of that work.
Where this breaks
Snapshot-plus-delta only works if you can tell that a message is missing, and mostly you cannot.
Polymarket's book event carries a hash, which answers "does the book I am holding match the one
you just described" — it does not tell you which message you dropped, and there is no sequence
number on the market channel to count. The cost of that at scale is recorded on our
PolyOrderbooks card: the published dataset's README says the delta feed
runs at roughly 24,000 events a second with no sequence numbers, so dropped messages cannot be
detected from the stream at all, and the collector re-reads the full book over REST every 60 seconds
to bound the drift. That REST re-read is the resynchronisation procedure, and it is one you have
to write. Limitless sidesteps the question by never sending a delta — but its version restarts
after a backend failover, so a jump in it is an ordering hint and not a gap alarm. Kalshi is the one
that sends real deltas off a snapshot, which is precisely why pykalshi exists.
One connection does not carry the catalogue. Polymarket US is explicit: 100 markets per
subscription, open another subscription if you need more. Limitless publishes no per-connection cap
and instead has a trap the documentation states plainly — emitting subscribe_market_prices again
replaces the previous subscription on that connection rather than adding to it, so the obvious
loop that subscribes one market at a time ends up watching only the last one, and a call that means
to follow both AMM and CLOB markets has to pass both parameters together. On the rented feeds the
limit is simply a line on the price list: DepthFeed runs from one live
subscription on its free plan to five on one connection, 25 on two, and 100 with wildcards on five,
and Predexon caps its mid tier at 10 subscriptions of 10 items across three
channels.
A reconnect is a hole in your data, and nothing here replays it. None of these venues documents a message backlog or a catch-up window. What a reconnect gets you is a fresh snapshot, which repairs your book and does nothing for your record: every trade that printed while you were away is missing from your file unless you go back to REST and fetch it. Watch the heartbeat rather than the socket state — Polymarket US tells you to reconnect when heartbeats stop, Limitless runs the heartbeat server-side, and the Polymarket market channel expects the ping from you — and treat the gap as data loss to be backfilled, not as a blip.
A venue with no central limit order book has no book to stream. Everything above runs a central limit order book; much of this sector does not. The Manifold API has a WebSocket with a per-market topic, but the venue is a CPMM automated market maker with resting limit orders sitting on top of the curve, so what that topic carries is updates to those resting orders — the price a position actually costs you there is the curve's impact, not a level you can read off a ladder. The Futuur API fails the other way: it does publish an order book per question per currency mode, but it has no WebSocket, no streaming endpoint and no push channel of any kind, so "live" there means polling a cache that is a few seconds stale. Decide which of the three you are pointed at before writing a book-shaped consumer; where a prediction market's liquidity comes from is the background on why a venue picks one.
A streamed top of book is not a fill. It is what was resting a moment ago, on a venue that
decides what you get after you send. Limitless rejects a signed order whose receive window has
passed with HTTP 425. Polymarket documents matching-engine maintenance windows and a post-only mode
after a restart, which a naive bot reads as rejections. Polymarket US delivers the per-entry outcome
of a batch on the private order stream rather than in the HTTP response, and its canceledOrderIds
is an echo of the request rather than a confirmation — so a 200 tells you nothing about what
happened. And Kalshi answers 429 with no Retry-After and no rate-limit headers, so whatever
polling runs alongside your stream needs a bucket model you wrote yourself. Size the position on the
depth you can still see after the round trip, not on the frame that prompted it.
If you outgrow this
If the question is more venues than you want connections for, tools with a streaming feed is the listing and tools that cover more than one venue is the overlap. Predictefy puts sixteen venues behind one verb family and sends full book snapshots rather than deltas, metered at two credits per connection-minute with two streaming connections on its free plan; Predexon sells tick-level history beside its socket. Adjacent versus DepthFeed versus Predexon is the head to head, and the thing each of them flattens to fit several venues in one schema is usually the part of the book you were streaming for. FinFeedAPI is worth knowing about for the opposite reason: no WebSocket on its prediction-market product at all, but raw limit-order events — adds, updates, deletes — pulled from flat files for replay.
And if what you actually needed was the book from before you connected, no venue will sell it to you: Polymarket's own documentation says the depth that produced a price is not retained, and Limitless says past activity has to be reassembled from price history, feed events and your own fills. DepthFeed and PolyOrderbooks record it independently, both across a crypto slice rather than the whole catalogue, and the shape of each archive follows the shape of the feed behind it — DepthFeed captures Polymarket off the CLOB WebSocket and Kalshi by paced full-depth REST polling, which is why its own measured Kalshi latency is about a second and its Polymarket latency is about ten milliseconds.
The approaches, in order
Cards in the catalogue that do this, ordered editorially. Paid placement does not affect this order.
1.Polymarket CLOB API
The keyless one. A public market channel keyed by outcome token id — a full book snapshot on subscribe, then price changes and last trade prices as they land.
Order books, prices and order placement on Polymarket's matching engine.
Free tier onlyFree tier
2.Kalshi API
Snapshots and deltas on the exchange's own socket, except that the handshake is signed even for public channels, so there is no keyless live stream here.
REST, WebSocket and FIX access to a CFTC-regulated event exchange.
Free tier onlyFree tier
3.pykalshi
The third-party Kalshi client whose OrderbookManager applies the deltas and hands back the current book — the piece most streaming scripts write badly once.
Unofficial Kalshi client with what the generated SDK leaves out - streams and retries.
FreeFree tierOpen source
4.Limitless API
Socket.IO on a markets namespace, where each order book frame is the whole book rather than a delta, carrying a version number to order frames by.
REST and WebSocket for markets, books, candles and trading on Base.
Free tier onlyFree tier
5.Polymarket US API
The US-accessible stream. Books and trades on the authenticated host, capped at 100 markets a subscription, behind the same identity check as trading.
A keyless public gateway for reading, and a signed key behind KYC for trading.
Free tier onlyFree tier
FAQ
Which of these can I stream without an account?
One, cleanly. Polymarket's market channel takes no credentials at all, and Limitless lists its market-data events as public with no signed handshake needed. Kalshi's WebSocket returns 401 without signed headers even on channels carrying only public data, and the Polymarket US markets stream lives on the authenticated host behind an identity check. Reading a book is still not permission to trade against it.
Do any of these give me a sequence number I can detect a gap with?
Not in the form most people expect. Limitless puts a version on each order book frame, which increases per frame and restarts after a backend failover — an ordering hint rather than a gap detector. Polymarket's book event carries a hash, which tells you whether your book matches, not which message you dropped. Polymarket US documents no sequence field and no replay.
How many markets can one connection carry?
Polymarket US caps a subscription at 100 markets and tells you to open more subscriptions rather than raising it. Limitless publishes no per-connection cap but replaces a subscription when you emit it again, so a loop that subscribes market by market ends up watching only the last one. On the rented cross-venue feeds the cap is a line on the price list.
Can I get the book from before I connected?
Not from the venues. Polymarket's own documentation says the depth behind a price is not retained, and Limitless says past activity has to be reassembled from price history, feed events and your own fills. Recorded ladders are a product somebody sells, and the two in this catalogue both cover a crypto slice rather than the whole catalogue.
Sources
- Real-time data streaming — Polymarket, read
- Markets WebSocket — Polymarket US, read
- WebSocket overview — Limitless Exchange, read
- Market data over WebSocket — Limitless Exchange, read
The catalogue next door
This page names a handful of cards. The rest of them are in Prediction Market Data APIs, each filled in against the same schema, with the fields to narrow it yourself.
Last updated . Corrected in place: this is a reference page, not a dated post.