Skip to main content

Stream Filtering Guide

Updated on
Feb 25, 2026

Overviewโ€‹

Hyperliquid streaming APIs support powerful filtering capabilities to help you receive only the data you need. Filters work across gRPC, JSON-RPC, and WebSocket protocols, allowing you to subscribe to specific events, users, trading pairs, and more.

Supported Protocols:


  • gRPC Streaming API - High-performance streaming with filters
  • JSON-RPC over WebSocket - Standard WebSocket filtering
  • WebSocket API - Real-time filtered subscriptions

Why Use Filtering?โ€‹

Without filtering, streaming from Hyperliquid can generate massive amounts of data. The exchange processes thousands of trades, orders, and events per minute across hundreds of trading pairs. Filtering is essential because it allows you to:

  • Reduce bandwidth and improve performance - Receive only relevant data instead of processing everything, significantly reducing network traffic and processing overhead
  • Focus on specific data - Track particular trading pairs, users, or event types instead of consuming all market data
  • Build efficient applications - Create focused applications without overwhelming data streams that could impact performance
  • Enable real-time decision making - Process targeted data faster for alerts, notifications, and trading decisions

Basic Filtering Conceptsโ€‹

Before diving into syntax, here are the key concepts:


  1. Streams - Different data types (trades, orders, events, etc.)
  2. Fields - Properties within each stream that can be filtered
  3. Values - Specific criteria you want to match
  4. Logic - How multiple filters combine (AND/OR)

Simple Example:

"I want to see only BTC trades that are buys (not sells)"

WebSocket Filter: {"coin": ["BTC"], "side": ["B"]}
gRPC Filter: {"coin": {"values": ["BTC"]}, "side": {"values": ["B"]}}

Available Streamsโ€‹

Stream NameDescriptionData Format
tradesFilled trades/executionsTuple: [user_address, fill_data]
ordersOrder status updatesObject with order fields
book_updatesOrder book changesObject with price/size
twap_ordersTWAP order statusesFlexible object
eventsLedger updates, deposits, withdrawals, fundingNested object
writer_actionsSystem actions, spot sendsObject with action type
blocksRaw replica commands (gRPC only, NO FILTERING)Full block data
StreamL2BookAggregated price levels (gRPC only โ€” coin specified in request)L2BookUpdate protobuf
StreamL4BookIndividual orders (gRPC only โ€” coin specified in request)L4BookUpdate protobuf

Filter Syntaxโ€‹

WebSocket and gRPC APIs use similar filter logic, but with different syntax:


{
"jsonrpc": "2.0",
"method": "hl_subscribe",
"params": {
"streamType": "trades",
"filters": {
"<field_name>": ["<value1>", "<value2>"]
},
"filterName": "optional_name"
},
"id": 1
}

Key points:

  • streamType: Stream name (trades, events, etc.)
  • filters: Each field maps directly to an array of values
  • filterName: Optional name for this filter (enables OR logic, unsubscribe by name)
  • Multiple streams require separate subscription requests

Filter Logicโ€‹

AND Across Fieldsโ€‹

When multiple fields are specified, ALL must match:

// WebSocket
{"filters": {"coin": ["BTC"], "side": ["B"]}}

Returns events where coin=BTC AND side=B

OR Within Fieldโ€‹

When multiple values are specified for one field, ANY can match:

// WebSocket
{"filters": {"coin": ["BTC", "ETH", "HYPE"]}}

Returns events where coin=BTC OR coin=ETH OR coin=HYPE

Combined Exampleโ€‹

// WebSocket
{"filters": {"coin": ["BTC", "ETH"], "side": ["B"]}}

Returns events where (coin=BTC OR coin=ETH) AND side=B

OR Across Named Filters (Advanced)โ€‹

Multiple subscriptions with different filterName values on the same stream = OR logic between them.

Request 1:

{
"jsonrpc": "2.0",
"method": "hl_subscribe",
"params": {
"streamType": "trades",
"filters": {
"coin": ["BTC"],
"side": ["B"]
},
"filterName": "btc_buys"
},
"id": 1
}

Request 2:

{
"jsonrpc": "2.0",
"method": "hl_subscribe",
"params": {
"streamType": "trades",
"filters": {
"coin": ["ETH"],
"side": ["A"]
},
"filterName": "eth_sells"
},
"id": 2
}

Returns (BTC AND side=B) OR (ETH AND side=A)

This is impossible with a single filter since AND applies across all fields.

Recursive Field Matchingโ€‹

Filters automatically search through nested JSON objects:

// This data:
{"inner": {"LedgerUpdate": {"users": ["0xABC"], "delta": {"type": "deposit"}}}}

// Matches this WebSocket filter:
{"filters": {"type": ["deposit"]}}

Special Filter Valuesโ€‹

ValueMeaningUse Case
"*"Field exists (any value)Find all liquidations: {"liquidation": {"values": ["*"]}}
"exists"Same as "*"Alternative syntax: {"liquidation": {"values": ["exists"]}}
"null"Field is nullFind unfilled TWAPs: {"twapId": {"values": ["null"]}}
Existence Filter Examples
// Find all trades that are liquidations (WebSocket)
{"filters": {"liquidation": ["*"]}}

// Find all trades with a builder (WebSocket)
{"filters": {"builder": ["*"]}}

// Find trades without TWAP ID (WebSocket)
{"filters": {"twapId": ["null"]}}

Stream-Specific Fieldsโ€‹

Trades Streamโ€‹

Filter completed trades and fills by user, trading pair, side, price, and execution details.

Format: Each event is a tuple [user_address, fill_data]

FieldTypeDescriptionExample Filter
userstringWallet address (matches tuple first element){"user": {"values": ["0x123..."]}}
coinstringTrading pair{"coin": {"values": ["BTC", "ETH"]}}
sidestring"A" (ask/sell) or "B" (bid/buy){"side": {"values": ["B"]}}
pxstringExecution price{"px": {"values": ["50000"]}}
szstringSize executedโ€”
dirstringDirection{"dir": {"values": ["Open Long", "Close Short"]}}
crossedbooleanCrossed the spread{"crossed": {"values": ["true"]}}
feestringFee amountโ€”
feeTokenstringFee token{"feeToken": {"values": ["USDC"]}}
hashstringTransaction hash{"hash": {"values": ["0xabc..."]}}
oidnumberOrder ID{"oid": {"values": ["12345"]}}
tidnumberTrade IDโ€”
cloidstringClient order ID (optional){"cloid": {"values": ["0x..."]}}
twapIdnumber/nullTWAP ID if from TWAP{"twapId": {"values": ["*"]}}
builderstringBuilder address (optional){"builder": {"values": ["0x999..."]}}
builderFeestringBuilder fee (optional)โ€”
liquidationobjectLiquidation data (optional){"liquidation": {"values": ["*"]}}
liquidation.liquidatedUserstringLiquidated user address{"liquidatedUser": {"values": ["0x..."]}}
liquidation.methodstringLiquidation method{"method": {"values": ["market"]}}
liquidation.markPxstringMark price at liquidationโ€”
Trades Filter Examples
// Get all BTC buys (WebSocket)
{"streamType": "trades", "filters": {"coin": ["BTC"], "side": ["B"]}}

// Get liquidations only (WebSocket)
{"streamType": "trades", "filters": {"liquidation": ["*"]}}

// Get trades for specific user (WebSocket)
{"streamType": "trades", "filters": {"user": ["0x727956612a8700627451204a3ae26268bd1a1525"]}}

// Get TWAP executions only (WebSocket)
{"streamType": "trades", "filters": {"twapId": ["*"]}}

Orders Streamโ€‹

Monitor order status updates including placements, cancellations, and partial fills.

FieldTypeDescriptionExample Filter
coinstringTrading pair{"coin": {"values": ["ETH"]}}
sidestring"A" or "B"{"side": {"values": ["A"]}}
limit_pxstringLimit priceโ€”
szstringCurrent sizeโ€”
orig_szstringOriginal sizeโ€”
oidnumberOrder ID{"oid": {"values": ["12345"]}}
timestampnumberOrder timestampโ€”
Orders Filter Examples
// Get all ETH orders (WebSocket)
{"streamType": "orders", "filters": {"coin": ["ETH"]}}

// Get sell orders only (WebSocket)
{"streamType": "orders", "filters": {"side": ["A"]}}

Book Updates Streamโ€‹

Track order book changes including price level updates and size modifications for bid and ask sides.

FieldTypeDescriptionExample Filter
coinstringTrading pair{"coin": {"values": ["BTC"]}}
sidestring"A" (ask) or "B" (bid){"side": {"values": ["B"]}}
pxstringPrice levelโ€”
szstringSize at levelโ€”
Book Updates Filter Examples
// Get BTC bid updates only (WebSocket)
{"streamType": "book_updates", "filters": {"coin": ["BTC"], "side": ["B"]}}

// Get updates for multiple coins (WebSocket)
{"streamType": "book_updates", "filters": {"coin": ["BTC", "ETH", "SOL"]}}

Events Streamโ€‹

Filter ledger updates including deposits, withdrawals, transfers, vault operations, and funding events.

Note: Events have nested structure with various types.

FieldTypeDescriptionExample Filter
usersarrayAffected users{"users": {"values": ["0x..."]}}
typestringEvent type{"type": {"values": ["deposit", "withdraw"]}}
usdcstringUSDC amountโ€”
tokennumberToken ID{"token": {"values": ["124"]}}

Common Event Types:

  • deposit - USDC deposit
  • withdraw - USDC withdrawal
  • internalTransfer - Internal transfer
  • spotTransfer - Spot transfer
  • liquidation - Liquidation event
  • funding - Funding payment
  • vaultDeposit / vaultWithdraw - Vault operations
Events Filter Examples
// Get deposits only (WebSocket)
{"streamType": "events", "filters": {"type": ["deposit"]}}

// Get all events for a user (WebSocket)
{"streamType": "events", "filters": {"users": ["0xabc..."]}}

// Get vault operations (WebSocket)
{"streamType": "events", "filters": {"type": ["vaultDeposit", "vaultWithdraw"]}}

Writer Actions Streamโ€‹

Monitor system actions including spot token transfers, perps operations, and core system activities.

FieldTypeDescriptionExample Filter
userstringUser address{"user": {"values": ["0x200..."]}}
noncenumberAction nonceโ€”
evm_tx_hashstringEVM transaction hash{"evm_tx_hash": {"values": ["0x..."]}}
action.typestringAction type{"type": {"values": ["SystemSpotSendAction"]}}
action.destinationstringDestination address{"destination": {"values": ["0x..."]}}
action.tokennumberToken ID{"token": {"values": ["124"]}}
action.weinumberAmount in weiโ€”

Common Action Types:

  • SystemSpotSendAction - Spot token transfer
  • SystemPerpsAction - Perps system action
  • CoreWriterAction - Core writer action
Writer Actions Filter Examples
// Get spot sends only (WebSocket)
{"streamType": "writer_actions", "filters": {"type": ["SystemSpotSendAction"]}}

// Get actions for specific token (WebSocket)
{"streamType": "writer_actions", "filters": {"token": ["124"]}}

// Get actions for specific user (WebSocket)
{"streamType": "writer_actions", "filters": {"user": ["0x200..."]}}

TWAP Orders Streamโ€‹

Track Time-Weighted Average Price order status updates including running, completed, and cancelled TWAP orders.

FieldTypeDescriptionExample Filter
userstringUser address{"user": {"values": ["0x..."]}}
coinstringTrading pair{"coin": {"values": ["BTC"]}}
sidestring"A" or "B"{"side": {"values": ["B"]}}
statusstringTWAP status{"status": {"values": ["running", "completed"]}}

StreamL2Book and StreamL4Book (OrderBookStreaming)โ€‹

The StreamL2Book and StreamL4Book streams are part of a separate gRPC service (OrderBookStreaming) and use a different filtering model. Instead of the filter object syntax used by StreamData, these streams accept the coin directly as a request parameter:

// L2 โ€” coin specified as a request field
L2BookRequest { coin: "BTC", n_levels: 20 }

// L4 โ€” coin specified as a request field
L4BookRequest { coin: "ETH" }

Key differences from StreamData filtering:


  • gRPC only โ€” StreamL2Book/StreamL4Book are not available via WebSocket or JSON-RPC
  • Same coin filtering capabilities โ€” The node accepts the same coin parameters as StreamData

See the StreamL2Book and StreamL4Book dataset pages for full details.

Filter Limitsโ€‹

To ensure optimal performance and prevent abuse, Hyperliquid enforces limits on the number of filter values per field and total filter complexity:

LimitDefaultDescription
Max values per user/address field100Max addresses in one filter
Max values per coin field50Max coins in one filter
Max values per type field20Max types in one filter
Max total values500Sum of all filter values
Max named filters per stream10Max named filters (filterName) per stream type
Unknown fieldsAllowedAny field can be filtered (uses highest limit)
Limit Error Response
{
"error": {
"code": -32602,
"message": "Filter validation failed: Too many values for field 'user': 150 (max: 100)"
}
}

Complete Examplesโ€‹

WebSocket Examplesโ€‹

Basic Subscription
// Subscribe to trades stream
{"jsonrpc":"2.0","method":"hl_subscribe","params":{"streamType":"trades"},"id":1}

// Response
{"jsonrpc":"2.0","result":{"subscribed":["trades"]},"id":1}
Filtered Subscriptions
// Filter trades by coin and side
{
"jsonrpc": "2.0",
"method": "hl_subscribe",
"params": {
"streamType": "trades",
"filters": {
"coin": ["BTC", "ETH"],
"side": ["B"]
}
},
"id": 1
}

// Get all liquidations
{
"jsonrpc": "2.0",
"method": "hl_subscribe",
"params": {
"streamType": "trades",
"filters": {
"liquidation": ["*"]
}
},
"id": 1
}

// Get deposits for specific user
{
"jsonrpc": "2.0",
"method": "hl_subscribe",
"params": {
"streamType": "events",
"filters": {
"type": ["deposit"],
"users": ["0xabc..."]
}
},
"id": 1
}

// Get SystemSpotSendAction events
{
"jsonrpc": "2.0",
"method": "hl_subscribe",
"params": {
"streamType": "writer_actions",
"filters": {
"type": ["SystemSpotSendAction"]
}
},
"id": 1
}
Unsubscribe
// Unsubscribe from specific filter
{"jsonrpc":"2.0","method":"hl_unsubscribe","params":{"filterName":"btc_trades"},"id":2}

// Unsubscribe from stream type
{"jsonrpc":"2.0","method":"hl_unsubscribe","params":{"streamType":"trades"},"id":3}

wscat One-Linersโ€‹

Quick Testing Commands
# All trades (no filter)
wscat -c wss://endpoint/ws -w 9999
{"jsonrpc":"2.0","method":"hl_subscribe","params":{"streamType":"trades"},"id":1}

# BTC trades only
wscat -c wss://endpoint/ws -w 9999
{"jsonrpc":"2.0","method":"hl_subscribe","params":{"streamType":"trades","filters":{"coin":["BTC"]}},"id":1}

# Liquidations only
wscat -c wss://endpoint/ws -w 9999
{"jsonrpc":"2.0","method":"hl_subscribe","params":{"streamType":"trades","filters":{"liquidation":["*"]}},"id":1}

# Specific user's trades
wscat -c wss://endpoint/ws -w 9999
{"jsonrpc":"2.0","method":"hl_subscribe","params":{"streamType":"trades","filters":{"user":["0x123..."]}},"id":1}

gRPC Examplesโ€‹

gRPC Filter Examples
// JavaScript gRPC example
const request = {
subscribe: {
stream_type: 'TRADES',
filters: {
"coin": { values: ["BTC", "ETH"] },
"side": { values: ["B"] }
}
}
};

// Python gRPC example
request = {
"subscribe": {
"stream_type": "TRADES",
"filters": {
"liquidation": {"values": ["*"]},
"coin": {"values": ["BTC"]}
}
}
}

// Go gRPC example
request := &pb.SubscribeRequest{
Subscribe: &pb.Subscribe{
StreamType: pb.StreamType_TRADES,
Filters: map[string]*pb.FilterValues{
"coin": {Values: []string{"BTC", "ETH"}},
"user": {Values: []string{"0x123..."}},
},
},
}

Response Formatโ€‹

Subscription Confirmationโ€‹

{"jsonrpc":"2.0","result":{"subscribed":["trades"]},"id":1}

Stream Dataโ€‹

{
"stream": "trades",
"block_number": 817824278,
"data": {
"block_number": 817824278,
"block_time": "2025-12-04T17:00:15.929034389",
"local_time": "2025-12-04T17:00:16.076556955",
"events": [
["0x727956612a8700627451204a3ae26268bd1a1525", {"coin": "HYPE", "side": "B", ...}]
]
}
}

Important Notesโ€‹


  • Case Sensitivity: Field names and values are case-insensitive ("Coin" = "coin" = "COIN", "btc" = "BTC")
  • Address Matching: Addresses are case-insensitive ("0xABC" = "0xabc")
  • Empty Filters: No filters = receive all events (no filtering applied)
  • Whitespace: Values are automatically trimmed of whitespace
  • Per-Stream Filters: Each stream can have independent filters
  • Recursive Matching: Filters search through nested JSON structures automatically
  • Tuple Format: TRADES stream uses [user, data] format; user filter matches the first element
  • Blocks Stream: The blocks stream does NOT support filtering (gRPC only, raw data)

Share this doc