Skip to main content

Getting started with real-time WebSocket streaming

Receive live indicator updates over a WebSocket connection instead of polling the REST API

With WebSocket streaming you open one connection, subscribe to the indicators you care about, and TAAPI.IO pushes new values to you every few seconds as the market moves, including while the candle is still forming. You don't need to poll the API, and you won't run into REST rate limits.

1. Connect

wss://v2.taapi.io/streaming

2. Authenticate

Send your v2 API key as the first message, using the same key as for the REST API:

{ "type": "auth", "token": "Bearer YOUR_API_KEY" }

If it succeeds, you receive an auth_ok message, which also shows how many subscriptions your plan allows:

{
"type": "auth_ok",
"plan": { "socketSubscriptionsAllowed": 500, "streamThrottleMs": 5000 }
}

If the key is wrong, you receive { "type": "auth_error", "error": "Invalid or inactive token" } and the connection is closed.

3. Subscribe to an indicator

{
"type": "subscribe",
"id": "my_rsi",
"exchange": "binance",
"symbol": "BTCUSDT",
"interval": "1m",
"indicator": "rsi",
"params": { "period": 14 }
}
  • id: any name you choose for this subscription.

  • interval: the candle timeframe. Streaming supports 1m, 5m, 15m and 1h. Note that streaming uses interval, while the REST API uses timeframe.

  • params: the same indicator parameters you would use in the REST API.

The server confirms with the full subscription id. Keep it, because you need it to unsubscribe:

{
"type": "subscribed",
"id": "binance_btcusdt_1m_my_rsi",
"subscription": "binance:btcusdt:1m",
"indicator": "rsi"
}

Subscribe to many at once

Use subscribe_bulk to subscribe to every combination of symbols × intervals × indicators in one message. Note that each indicator uses name here, not indicator:

{
"type": "subscribe_bulk",
"exchange": "binance",
"symbols": ["BTCUSDT", "ETHUSDT"],
"intervals": ["1m", "5m"],
"indicators": [
{ "id": "my_rsi", "name": "rsi", "params": { "period": 14 } },
{ "id": "my_ema", "name": "ema", "params": { "period": 9 } }
]
}

4. Receive updates

You get the current value straight away, and then a new update as the price changes. Each update is keyed by the subscription id and uses the same array format as the REST API:

{
"type": "update",
"subscription": "binance:btcusdt:1m",
"data": {
"binance_btcusdt_1m_my_rsi": { "value": [41.99], "timestamp": [1793656260] }
}
}

Updates for subscriptions on the same exchange, symbol and interval arrive together in one message. How often updates are sent depends on your plan (streamThrottleMs in the auth_ok message).

5. Manage your subscriptions

  • List your active subscriptions: { "type": "list" }. Add "unpack": true to get a flat array instead of a grouped object.

  • Unsubscribe from one, using the full id from the subscribed message: { "type": "unsubscribe", "id": "binance_btcusdt_1m_my_rsi" }

  • Unsubscribe from everything: { "type": "unsubscribe_all" }

Staying connected

  • Keep the connection alive by sending a WebSocket ping frame (or a { "type": "ping" } message) about every 30 seconds.

  • Reconnect automatically if the connection drops, ideally with an increasing delay between attempts (1 second, then 2, 4, and so on, up to about 30 seconds).

  • After reconnecting, authenticate and subscribe again. Subscriptions are not restored automatically.

Full example (JavaScript)

const ws = new WebSocket("wss://v2.taapi.io/streaming");

ws.onopen = () => {
ws.send(JSON.stringify({ type: "auth", token: "Bearer YOUR_API_KEY" }));
};

ws.onmessage = (event) => {
const msg = JSON.parse(event.data);

if (msg.type === "auth_ok") {
ws.send(JSON.stringify({
type: "subscribe", id: "my_rsi",
exchange: "binance", symbol: "BTCUSDT", interval: "1m",
indicator: "rsi", params: { period: 14 }
}));
}

if (msg.type === "update") {
for (const [id, result] of Object.entries(msg.data)) {
console.log(id, result.value[0]);
}
}

if (msg.type === "error" || msg.type === "auth_error") {
console.error(msg.error);
}
};

Tip: keep your API key on your server. Don't open the WebSocket connection directly from your users' browsers, because that would expose your key.

Did this answer your question?