Skip to content
  • System
  • Light
  • Dark

Real-time stream example

View as Markdown

This client subscribes to every new launch and graduation plus the trades of one token, reconnects with backoff, resumes the messages it missed, and undoes reorged events. It runs on Node.js 22+ (built-in WebSocket) with a key that has the stream scope.

// stream.mjs: node stream.mjs
const KEY = process.env.CRIUS_API_KEY;
const TOKEN = "0x7b8892cea949bc60d494681d1bc3ea96071ab0b8";
const CHANNELS = ["launches:all", "graduations:all", `trades:${TOKEN}`, `price:${TOKEN}`];
const lastSeq = {}; // channel -> last seq seen, for resuming
let backoff = 1000;
function connect() {
const ws = new WebSocket(`wss://api.crius.sh/v1/robinhood/stream?api_key=${KEY}`);
let idle;
const touch = () => {
clearTimeout(idle);
idle = setTimeout(() => ws.close(), 45_000); // heartbeats come every 15 s
};
ws.onopen = () => {
backoff = 1000;
touch();
ws.send(JSON.stringify({ op: "subscribe", channels: CHANNELS }));
if (Object.keys(lastSeq).length) ws.send(JSON.stringify({ op: "resume", seqs: lastSeq }));
};
ws.onmessage = (e) => {
touch();
const m = JSON.parse(e.data);
if (m.seq) lastSeq[m.ch] = m.seq;
switch (true) {
case m.ch === "reorg":
console.warn(`reorg: blocks ${m.data.removed_blocks.join(", ")} replaced`);
break;
case m.data?.removed:
console.warn(`undo ${m.ch} ${m.data.id}`); // reverse whatever you did for this event id
break;
case m.ch.startsWith("launches:"):
console.log(`new ${m.data.launchpad} token ${m.data.address} by ${m.data.creator}`);
break;
case m.ch.startsWith("graduations:"):
console.log(`graduated ${m.data.token} → pool ${m.data.pool}`);
break;
case m.ch.startsWith("trades:"):
console.log(`${m.data.type} $${m.data.value_usd} by ${m.data.trader}`);
break;
case m.ch.startsWith("price:"):
console.log(`price $${m.data.usd}`);
break;
case m.ch === "error":
console.error(m.data);
break;
}
};
ws.onclose = () => {
clearTimeout(idle);
setTimeout(connect, backoff + Math.random() * 500);
backoff = Math.min(backoff * 2, 30_000);
};
ws.onerror = () => ws.close();
}
connect();

Browsers can’t set headers on WebSockets, so the key would have to go in the URL (?api_key=), where anyone can read it from your page. Connect from your backend instead and forward the events to your page (for example over Server-Sent Events). Keys restricted to browser origins are read-only and can’t open the stream.