Skip to main content
The WebSocket gives near-real-time updates on the order book, live prices, and your own account. Public streams need no authentication; private streams are signed exactly like a REST request.
Subscribe by adding one or more stream= query parameters to the connection URL. You can combine as many as you like — including public and private together — so a client needs one connection, not several.
Each message is a JSON object keyed by the stream name, so one handler can switch on the key:

Channel reference

{market} is a market id; {period} a k-line period; {symbol} a Coinbase product id.
Order-book increments carry a sequence. If it skips, re-subscribe to get a fresh .ob-snap and resume from there — a client that ignores the gap will drift out of sync with the book and quote prices that no longer exist.

Authenticating a private connection

The upgrade request is HMAC-signed like any other GET, so the signed path must include the full ?stream=… query string:
See Authentication for the canonical message.

Underlying price feed

?stream=crypto.{symbol} republishes the venue a candle-direction market settles against, so the line a member watches and the price they are paid on cannot diverge.
Throttled to roughly one message per second, newest-wins.
bucket_open is for drawing. Settlement reads the authoritative closed candle — see How markets are resolved.

Private streams

Order — every create, partial fill, full fill, cancel, and rejection:
Trade — your own fills. Balance — changes to the pool collateralising your orders, i.e. the mirror of your Safe:
Balance values are strings — parse as decimals, not floats.
Settlement does not credit a winner automatically. On-chain resolution only makes the winning outcome token redeemable; the balance moves when you redeem. Do not wait on a balance event at resolution time — see Redeeming winnings.
Balance updates are triggered by order creation (locking stake plus the taker-fee reserve), cancellation, partial fills, rejection, redemption, and voids. Position — your holding in a market, after anything changes it: a fill, an exit, settlement, or a void.
sellable_qty is what you can offer right now — qty less anything already committed to a resting sell. realized_pnl banks at the moment you exit, so it moves on a sale rather than waiting for the market to resolve.

Reading the tape

Each fill on {market}.trades carries taker_side: the outcome the aggressor bought, meaning the side that crossed the spread and paid the taker fee. It is "yes", "no", or "". Without it a tape is only a list of prices. Direction inferred from the price moving says nothing about the many fills that print at the same price as the one before them, and a buy and a sell print identically.
"" means unknown, not “neither”. Fills matched before taker attribution was recorded report "", and so does any row read from the historical tape. Render those as unattributed — do not pick a side for them.
The same field, under the same rule, is on the REST tape at GET /public/markets/{market}/contracts/recent.

Authentication

Signing the private upgrade request.

API overview

Base URLs and conventions.

Recurring markets

What the crypto feed is for, and what settles a window.

Fees

Why a resting order locks more than its stake.