BlogDevelopment
Filtering Solana trades server-side before they hit your bot
Client-side filters waste bandwidth and CPU. Push mint and wallet constraints to the stream so only matching token_trades and wallet_trades arrive.
A global trades feed is useful for research. A production sniper or copy-trader usually wants one mint, one wallet set, or both. Filtering after download means paying for noise twice — once on the wire, once in your process — and reconnect storms get worse exactly when Solana is hottest.
Most teams discover this the hard way: the strategy looks fine in a quiet hour, then a meme wave arrives and the process spends its budget discarding events it never wanted. Latency charts blame the vendor. The real bug is an unbounded subscribe.
What belongs on the server
- Mint allowlists for
token_tradesyou intend to trade - Wallet allowlists for copy or watch lists on
wallet_trades - Venue constraints when your strategy only clears on specific programs
- Hard drops for event types your binary never handles
What belongs in the client is strategy: sizing, risk, and whether this particular fill is still interesting after your own state updates. Do not re-implement mint matching in application code if the stream already supports it. Client filters should be the exception for ephemeral UI state, not the default for production routing.
Failure modes of “filter later”
- CPU spikes on decode while the market moves
- Websocket backlog that looks like latency but is self-inflicted
- Silent loss when your process GC pauses under a firehose
- Misleading metrics that blame the vendor for your unbounded subscribe
- Ops pages that look “fine” while the trading loop is drowning in discards
The worst version is subtle: average latency looks acceptable because most messages are cheap no-ops, while the rare matching trade is delayed behind a queue of noise. Server-side filters shrink that queue before it exists.
How Tessium expects you to subscribe
Attach filters when you subscribe to token_trades and wallet_trades. The server drops non-matching events before they reach you. Start narrow in production, widen only when a dashboard or research job truly needs the global view.
Treat filter changes like deploys. A widened allowlist is a capacity change. A removed venue filter is a traffic change. Review them with the same seriousness as opening a new port. Put the allowlist next to the release notes so on-call knows what “normal” traffic should look like.
Checklist before you go live
- Confirm every production subscription has an explicit scope
- Alert when received events per second jump without a matching strategy change
- Keep a separate unfiltered research connection if you must — do not mix it with trading
- Document which mints and wallets are on the allowlist next to the deploy
- Load-test with a synthetic widen of filters so you know the cliff before mainnet finds it
Filters and flat pricing pull the same way
When the bill is not per event, you still want filters — for latency and for honesty in metrics. Flat pricing removes the incentive to under-subscribe out of fear; server-side filters remove the incentive to over-subscribe out of laziness. Use both. Tessium’s Streams docs show how scopes attach to subscriptions; the Pricing page explains why volume spikes do not become invoice spikes when subscriptions stay disciplined.
A short decision rule
If you cannot name the mint, wallet, or venue that justifies a message reaching your process, do not subscribe to that scope. Research jobs get their own connection and their own budget. Production stays narrow. That single split prevents most “why is the bot slow on busy days” threads.