For the complete documentation index, see llms.txt. This page is also available as Markdown.

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:

  1. Subscribes to the trades topic for SOL/USDC on a shared WebSocket.

  2. Records the startup backfill without alerting on it, so only new trades fire.

  3. Calls onWhale once for each trade at or above the size threshold, even across reconnects.

  4. 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

Prerequisites

Project Setup

1

Create the project

The only dependency is dotenv, for loading your key.

2

Configure your key and threshold

Create a .env file in the project root:

The API key travels in the apiKey query parameter of the WebSocket URL, not in a header. Keep it in .env and out of version control.

Get your API KEY from your GetBlock dashboard

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.

3

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.

The acknowledgement for a subscription is the only message with a top-level string result. Notifications carry their data under params.result, and params.subscription says which subscription they belong to.

4

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 hydrate rows 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.

  • deletes are ignored. On the trades topic, almost every delete is simply the oldest trade leaving the 100-row window. It doesn't mean a trade was reversed.

5

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.

6

Wire it together and run

The entry point creates the stream, registers both watchers, formats each alert, and connects.

To send alerts somewhere other than the terminal, replace the two console.log calls in the watchWhales callback with a Telegram, Discord, or webhook call. whales.js already guarantees each trade reaches that callback at most once.

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.

Field
Type
What it tells you

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

Symptom
Likely cause
Fix

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?