How to Build a Solana Whale Trade Alert Bot with GetBlock Solana Market Data
A step-by-step guide to building a bot that alerts on large SOL/USDC trades in real time, with buy/sell pressure context, using GetBlock Solana Market Data.
When a wallet swaps $30,000 of SOL in one go, the traders watching know about it within seconds, and everyone else finds out from the price chart afterwards. Catching those trades yourself is harder than it looks on Solana: the same swap can route through Raydium, Orca, Meteora or a Jupiter aggregation, and each program encodes it differently. You would need to stream every block, decode swaps from each venue, convert raw token amounts into prices, and do it fast enough for the alert to still matter. A single large trade also says little without context: a big buy lands differently in a market that is already buy-heavy.
GetBlock Solana Market Data streams trades that are already decoded and normalized across venues, together with rolling buy/sell volume, over a single WebSocket.
In this guide, you'll build a whale trade alert bot that flags every SOL/USDC trade above a size you choose, adds the market's current buy/sell pressure to each alert, and recovers trades it missed during a short disconnect.
What you'll build
A watchWhales(stream, options, onWhale) function that:
Subscribes to the
tradestopic for SOL/USDC on a shared WebSocket.Records the startup backfill without alerting on it, so only new trades fire.
Calls
onWhaleonce for each trade at or above the size threshold, even across reconnects.Recovers large trades that landed while the connection was down.
It runs alongside a watchPressure() subscription to the volume topic on the same socket, so every alert also shows whether the last five minutes have been buy-heavy or sell-heavy.
How it works
Keep hydrate at 100 on the trades subscription. Each push reflects a retained set of that size, and in testing on SOL/USDC, hydrate: 10 silently dropped about 10% of trades and hydrate: 1 dropped 67%. At 100, no trades were dropped across throttle values from 100ms to 2s.
Prerequisites
Node.js 20+ — the bot uses the built-in global
WebSocket, so no WebSocket library is needed.A Solana Market Data API key with the product activated on it.
Basic JavaScript knowledge.
Project Setup
Configure your key and threshold
Create a .env file in the project root:
MIN_USDC is the smallest trade that triggers an alert, measured in the quote token. For SOL/USDC that is effectively US dollars. At 10000, a test run produced eight alerts in four minutes, several landing in the same second. Raise it for fewer, bigger alerts.
Share one socket between subscriptions
The stream module owns the connection. It sends every registered subscription when the socket opens, routes each notification to its handler by subscription ID, and tells the handler whether the message is that subscription's opening backfill. If the connection drops, it reconnects and replays everything.
Detect whale trades
This is the core of the bot. Every trade has a stable id, and the module keeps a bounded set of the IDs it has already processed.
Three details decide whether the bot is correct:
The first backfill stays silent. The opening
hydraterows are trades from before the bot started. The module records their IDs but doesn't alert, so startup doesn't flood your channel.Later backfills are checked, not skipped. After a reconnect, the new backfill holds the most recent trades, including any that landed while the bot was offline. Trades already in the seen set are skipped, and the rest alert normally — so outage whales still get reported, and nothing is reported twice.
deletesare ignored. On thetradestopic, almost every delete is simply the oldest trade leaving the 100-row window. It doesn't mean a trade was reversed.
Recovery only reaches as far back as the backfill: the last 100 trades on the pair, which is roughly 5–7 seconds of SOL/USDC activity. A longer outage loses the older trades. That's why stream.js retries after one second before backing off.
Track buy/sell pressure
The volume topic returns buy_sell_ratio for each window: buy volume divided by sell volume. With hydrate: 1 the subscription holds only the current window, so this module always has the latest reading.
When a window closes, the new one arrives in inserts and the finished one leaves in deletes, so reconciling by id keeps exactly one row. A single notification can also carry several versions of the same row in updates; applying them in order leaves the newest.
Wire it together and run
The entry point creates the stream, registers both watchers, formats each alert, and connects.
Start the bot:
Expected output:
Each alert shows the side and size of the trade, its execution price, and how the past five minutes have leaned, with the swap count so you can judge how much data sits behind the ratio. The Solscan link opens the transaction itself.
Understanding the response
The bot reads these fields from the two topics. Numbers arrive as strings to preserve precision, so convert them with Number() only where you compare or format them.
id
number
Stable identifier for the row. The bot's key for de-duplicating alerts.
quote_volume
string
trades: how much of the quote token changed hands. For SOL/USDC, the trade's size in dollars.
base_volume
string
trades: how much SOL changed hands, already adjusted for decimals.
price
string
trades: execution price in the quote token.
is_buy
boolean
trades: true when the trade is classified as a buy.
signer
string
trades: the wallet that signed the transaction — the "whale".
signature
string
trades: the transaction signature, used for the Solscan link.
timestamp
string
trades: when the trade happened, in ISO 8601 format.
slot
string
trades: the Solana slot the trade landed in.
buy_sell_ratio
string
volume: buy volume divided by sell volume for the window. Above 1 means net buying.
total_swaps
string
volume: how many swaps the window contains. A low count means the ratio rests on little data.
buy_volume / sell_volume
string
volume: the two sides of the ratio, in the base token.
window_start
string
volume: start of the window, used to pick the most recent one.
Troubleshooting
Stream closed (code 1006) repeating with growing delays
The key is rejected during the WebSocket handshake
Check GETBLOCK_API_KEY and that Solana Market Data is activated on that key.
No alerts for several minutes
The threshold is above anything trading right now
Lower MIN_USDC in .env, for example to 5000, and restart.
A burst of alerts the moment the bot starts
The opening backfill is being treated as new trades
Skip alerts for the first backfill only, as whales.js does with primed.
The same trade is alerted twice after a reconnect
Trades aren't de-duplicated by id
Keep a set of processed IDs and skip any trade already in it.
Large trades you can see on-chain never alert during busy periods
hydrate on the trades subscription was lowered
Keep hydrate: 100. Smaller values drop trades when several land between pushes.
Trades from an outage are missing after reconnecting
The outage outlasted the backfill, which holds only the last 100 trades
Keep the reconnect delay short. For guaranteed coverage, add a second source for the gap.
Pressure shows an extreme value such as 0.00
The five-minute window just rolled over and contains only a few swaps
Check the swap count in the alert, or use a longer window for a steadier reading.
Pressure always shows n/a
The volume subscription hasn't delivered yet, or was rejected
Look for a Subscription 2 rejected line in the output.
Subscription 2 rejected: … window must be one of …
An unsupported window value, such as 15m
Use one of the listed values.
Conclusion
You built a Solana whale alert bot that shares one GetBlock WebSocket between a trades subscription and a volume subscription, routing each notification by its subscription ID. It keeps hydrate at its maximum so no trade is dropped, stays silent on the first backfill, de-duplicates alerts by trade id so a reconnect recovers outage trades without repeats, and attaches the latest buy_sell_ratio to every alert.
Resources
Last updated
Was this helpful?