Track Solana Events: WebSockets, RPC, and Webhooks Guide.

Okay, grab your terminal. You're gonna love this. First thing I do when I wanna track some Solana action? Spin up a dead simple WebSocket sub to watch an account balance change. Why? 'Cause it's instant real time feedback. No polling bullshit.

Install @solana/web3.js real quick: npm init -y && npm i @solana/web3.js. Paste this into a file called watch.js:

const solanaWeb3 = require('@solana/web3.js');
const connection = new solanaWeb3.Connection('https://api.devnet.solana.com');
const wsEndpoint = 'wss://api.devnet.solana.com'; const ACCOUNTTOWATCH = new solanaWeb3.PublicKey('YOURWALLETHERE'); const subId = connection.onAccountChange(ACCOUNTTOWATCH, (accountInfo) => { console.log('Balance changed!', accountInfo.lamports / solanaWeb3.LAMPORTSPERSOL, 'SOL');
}, 'confirmed'); console.log('Watching.. Sub ID:', subId);
setTimeout(() => connection.removeAccountChangeListener(subId), 30000); // Clean up after 30s

Run node watch.js. Send some devnet SOL to that address. Boom-logs it instantly. That's your "why it works": Solana pushes changes over WebSocket. Milliseconds. In my experience, free public endpoints flake out after a bit, so snag a QuickNode free tier URL pronto.

Why Bother Tracking Solana Events Anyway?

Picture this: You're building a bot that snags new token launches. Or alerting on whale dumps. Or just debugging your program's tx fails. Events are your eyes on chain. Transaction logs, account updates-it's all there.

The thing is, Solana blasts ~50k TPS sometimes. Polling RPC every second? You'll hit rate limits and burn cash. WebSockets? Free pushes. RPC polling for history. Webhooks? We'll hit that later-they're like WebSockets but outsourced.

Sound familiar? Yeah, I chased ghosts for hours polling once. Never again.

WebSockets: The Real Time King

So WebSockets connect to Solana's wss://api.mainnet beta.solana.com (or your RPC provider). You subscribe once, get events forever. Until it stales-then reconnect, dummy.

Account Changes - Watch Balances Flip

  1. Get a WS endpoint. Public one's wss://api.devnet.solana.com. Better? QuickNode dashboard → copy WS URL.
  2. Code it up. Like above, but mainnet. Expect ~0.000005 SOL priority fees on txes that trigger these.
  3. Test: Airdrop or transfer. See the lamports shift live.
  4. Pro tip: Use "confirmed" commitment. "Finalized" lags 1-2 slots.

Issue? Connection drops after 10 mins idle. I usually ping every 30s: connection._rpcWebSocket.send('ping');. Keeps it alive.

Program Logs - Sniff Smart Contract Events

Want DeFi swaps? NFT mints? Subscribe to a program ID.

  • Token program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
  • Jupiter? Grab from Solscan.
connection.onLogs( new solanaWeb3.PublicKey('PROGRAMIDHERE'), (logs) => { if (logs.err) return; console.log('Logs:', logs.logs); // Parse for events like "Transfer" }, 'confirmed'
);

Logs are arrays of strings. Anchor programs emit base64 events-decode 'em with borsh. Why bother? Catch "InitializeMint" for new tokens before Dexscreener indexes.

RPC Polling: When You Need History, Not Live

WebSockets are future only. Need past txes? Poll RPC. It's dumb simple but rate limited on free tiers (100 reqs/sec).

I use this for backfills. Like, "gimme last 100 txs on this wallet."

MethodWhat It DoesLimitCost
getSignaturesForAddressTx signatures for addr1000Low
getParsedTransactionsFull tx detailsBatch 100 sigsMedium
getAccountInfoCurrent balance/state1Free ish

Full script? Here's one I tweaked from QuickNode guides. Tracks 5 txs, parses instructions.

const getTxHistory = async (address, numTx = 5) => { const pubkey = new solanaWeb3.PublicKey(address); const connection = new solanaWeb3.Connection('YOURRPCHTTP_URL'); const sigs = await connection.getSignaturesForAddress(pubkey, { limit: numTx }); const sigList = sigs.map(tx => tx.signature); const details = await connection.getParsedTransactions(sigList, { maxSupportedTransactionVersion: 0 }); sigs.forEach((sig, i) => { const date = new Date(sigs[i].blockTime * 1000); console.log(Tx ${i+1}: ${sig.signature} at ${date}); const instructions = details[i]?.transaction.message.instructions; instructions?.forEach((inst, n) => { console.log( Instr ${n+1}: ${inst.programId.toString()}); }); });
}; getTxHistory('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // USDC mint

Run it. Spots program IDs like Pump.fun swaps. Problem? Big wallets have 10k+ txs. Paginate with before: lastSig. Fees? ~1-5ms per call, dirt cheap.

Mix 'Em: WebSocket + RPC Hybrid

Best setup? WebSocket for live, RPC for catch up. On app start:

  1. Poll last 50 txs via RPC. Process 'em.
  2. Sub WebSocket from there. No duplicates if you track signatures.
  3. Store in SQLite or Redis. Dupe check sigs.

In my experience, this catches 99% without gaps. Why does it matter? Slots finalize in ms. Miss one? Your bot buys at bad price.

Webhooks: Let Someone Else Handle the Socket Drama

Hate managing reconnections? Webhooks push to your endpoint. Helius or QuickNode do this sweet.

Setup: Sign up Helius.dev (free tier 1k reqs/day). Create webhook for "account updates" on your wallet. POSTs JSON to your ngrok URL.

  • Payload: sig, slot, account data.
  • Verify sig with their secret.
  • Rate: Matches WebSocket speed.

Code a tiny Express server:

app.post('/webhook', (req, res) => { const event = req.body; if (event.account?.lamportsChanged) { console.log('Balance ping!', event.account.lamports / 1e9); } res.sendStatus(200);
});

Pros: No WS in your code. Cons: Vendor lock, ~$50/mo for heavy use. I use for prod alerts only.

Webhook Gotchas

They retry failed deliveries 5x. Always 200 OK fast. Timeouts kill ya. Test with ngrok.

Production Traps I've Fallen Into

Okay, real talk. Public RPCs throttle at 100 connos. Get QuickNode Marketplace-$9/mo starter covers 25M units.

Reconnects: Wrap subs in try catch. Exponential backoff: 1s → 2s → 4s.

Parsing logs? Anchor events are Program log: Event: base64data. Use @coral xyz/anchor to unpack.

Scale? Shard subs across processes. One per program. Redis pubsub for internal events.

Token Tracking Example: Snipe New Mints

Let's build something fun. Watch Raydium pools for new tokens.

  1. Sub to Raydium program: 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
  2. Filter logs for "initialize" (grep 'init' or decode).
  3. Extract mint addr from log data.
  4. Buy if liquidity >0.1 SOL, mc <10k. (Use Jupiter API for swap.)

Full code's like 100 lines. DM if you want it-I've sniped 50x pumps this way. Risks? Rug pulls. Always sim on devnet first.

Python Folks? Here's Your Jam

If JS ain't your vibe, Solana.py rocks. Async WS subs out the box.

import asyncio
from solana.rpc.websocket_api import connect
from solders.pubkey import Pubkey async def main(): async with connect("wss://api.mainnet beta.solana.com") as ws: await ws.accountsubscribe(Pubkey.fromstring("YOUR_ADDR")) async for msg in ws: print(msg) asyncio.run(main())

Types: accountsubscribe, logssubscribe, signature_subscribe. Clean. Runs forever-Ctrl+C to kill.

What's next? Pick one method, code it today. WebSockets for speed. RPC for depth. Webhooks for ease. Hit snags? Common: "Subscription not found"-means bad commitment level. Fix: Stick to "confirmed".

You're set. Go track some events. 🚀

(