PerpsWsClient provides streaming data over WebSocket. Connections are made directly to the DEX for lowest latency — the SDK discovers the WebSocket URL from GET /providers automatically.
All incoming data is normalized to the same types used by REST responses, so your application logic works identically whether data comes from a REST call or a WebSocket event.
Setup
PerpsWsClient lazily initializes connections — no WebSocket is opened until you call subscribe().
Subscribe
subscribe() is async and returns a Promise<() => void> — awaiting it yields the unsubscribe function. The descriptor’s dex field selects the venue (use the key from getProviders(), e.g., 'hyperliquid' or 'lighter').
subscribe() accepts an optional third argument, onStatus, a listener for the underlying connection’s health. It fires 'reconnecting' on a transient drop and the terminal 'disconnected' once auto-reconnect is abandoned, so consumers can surface a reconnecting/disconnected state instead of silently showing stale data.
getQuote
One-shot fill quote forsize USD notional of symbol on a single venue: VWAP expected fill, price impact (bps), base-tier taker fee, and funding (perps only). This is a plain request/response service (not a WS subscription) — the streaming counterpart is subscribeQuote, and both share the GetQuoteParams shape. Cross-venue comparison is a consumer-side loop over client.providers.
GetQuoteParams:
Throws a
PerpsError when the provider plugin is not registered, no market matches the symbol and type, or on network / parsing errors.
subscribeQuote
Stream live fill quotes for a market. The provider’s WS plugin layers the quote on its orderbook channel, so a concurrentorderbook subscription on the same market shares a single wire subscription. Async; returns a Promise<() => void> unsubscribe function.
Throws a
PerpsError when no WS provider factory is registered for params.provider, or no market matches the symbol and type.
Available Channels
marketsContext
Full context for every market on the DEX, keyed bymarketId. Use this when a UI needs mark price, oracle price, 24h volume, open interest, or funding for the whole market list.
marketContext
Full context for a specific market. The event data is aMarketContext snapshot, so consumers should replace their cached context for that market when a new event arrives.
orderbook
L2 orderbook for a specific market. Fires on every book update. Pass an optionaldepth to limit price levels (provider default if omitted), and an optional priceStep to request a price granularity — the desired bucket width in quote currency (e.g. 10 buckets a BTC book into $10-wide levels). Providers that aggregate the book server-side honour priceStep best-effort; providers that stream the full book ignore it, and undefined requests full precision.
candle
OHLCV candle updates for a specific market and interval.trades
Public trade prints for a specific market. Fires as trades execute on the venue.orderUpdates
Live order status changes for a user’s orders. Requires the user’s wallet address.fills
Live fill notifications for a user’s trades.positions
Live position updates for a user.spotBalances
Live spot balance updates for a user (e.g., USDC collateral held on the DEX).accountSummary
Live account roll-up for a user — portfolio value, available margin, margin used, and unrealized PnL. Requires the user’s wallet address. Field coverage matches the venue’s own stream (e.g. Hyperliquid’sportfolioValue covers perps equity only; spot balances have their own spotBalances channel).
Multiple Subscriptions
You can subscribe to multiple channels simultaneously. Each returns an independent unsubscribe function.Connection Lifecycle
- Lazy connection — The WebSocket connects on the first
subscribe()call for each DEX - Automatic reconnection — Jittered exponential backoff on disconnect. The first-retry delay is drawn once per socket from
[500, 1500)ms (to de-synchronize reconnect storms) and grows exponentially, capped at 10s. After 10 attempts the socket is declareddisconnected. - Resubscription — All active subscriptions are automatically re-sent after reconnection
- Keepalive — 30-second ping/pong heartbeat to detect stale connections
- Refcounted — Duplicate subscriptions to the same channel are deduplicated; the upstream subscription is removed only when the last listener unsubscribes
- Manual reconnect —
ws.reconnect(provider)forces an already-created provider whose socket reached terminaldisconnectedto reconnect with a fresh retry budget. It is a safe no-op when the provider is unknown or not terminal.
Cleanup
Always close the client when you’re done to release WebSocket connections:Type Safety
Thesubscribe method is fully typed — the callback receives the correct event type based on the subscription channel: