WebSocket Streaming

Receive indicator values pushed to you every few seconds as the market moves, including while the candle is still forming, over a persistent connection.


The streaming service pushes indicator updates over a WebSocket connection. Instead of polling the REST API, you subscribe to indicators and receive values as they are computed.

WebSocket URL
wss://v2.taapi.io/streaming

Connection flow

  1. Open a WebSocket connection to wss://v2.taapi.io/streaming.
  2. Send an auth message with your API key. You must authenticate before subscribing.
  3. Send subscribe messages for the indicators you want.
  4. Receive update messages as indicator values are computed.
  5. Send unsubscribe messages when you no longer need an indicator, or list to see active subscriptions.

Authentication

Send this message immediately after connecting. All subsequent messages are ignored until authentication succeeds.

Send
{ "type": "auth", "token": "Bearer YOUR_API_KEY" }
Receive — success
{
  "type":   "auth_ok",
  "userId": "12345",
  "plan":   { "socketSubscriptionsAllowed": 20, "streamThrottleMs": 5000 }
}
Receive — failure
{ "type": "auth_error", "error": "Invalid or inactive token" }

Connections that fail authentication are closed by the server.

Subscribe

After authenticating, send a subscribe message for each indicator you want.

Subscribe — single indicator
{
  "type":       "subscribe",
  "id":         "my-rsi-id",
  "exchange":   "binance",
  "symbol":     "BTCUSDT",
  "interval":   "1m",
  "indicator":  "rsi",
  "params":     { "period": 14 }
}
FieldRequiredDescription
typeYesMust be "subscribe".
idYesSubscription identifier, e.g. my-rsi-id. It is required and will be included in the update events.
exchangeYesExchange identifier, e.g. binance.
symbolYesTrading pair, e.g. BTCUSDT.
intervalYesCandle interval: 1m, 5m, 15m or 1h. Longer timeframes are not available for streaming. Note that streaming uses interval, while the REST API uses timeframe.
indicatorYesIndicator name, e.g. rsi, ema, macd.
paramsNoIndicator-specific parameters, e.g. { "period": 14 }.

Receiving updates

After subscribing, the server sends update messages as values are computed.

Receive — update
{
  "type":         "update",
  "subscription": "binance:btcusdt:1m",
  "data": {
    "binance_btcusdt_1m_my-rsi-id": {
      "value":     [45.2],
      "timestamp": [1782389580]
    }
  }
}

The subscription key is lowercase and uses the format exchange:symbol:interval. The data object is keyed by a compound string combining exchange, symbol, interval, and the id you provided when subscribing.

Subscribe bulk

Subscribe to many indicators, symbols, and timeframes in one message using a subscribe_bulk message.

subscribe_bulk
{
  "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  } }
  ]
}

The server will subscribe to every combination of symbol × interval × indicator. Each indicator entry requires its own id and uses name (not indicator) for the indicator name.

Unsubscribe

To remove a single subscription, send an unsubscribe message with the generated compound ID that was returned when you subscribed. This ID is formed by the server as exchange_symbol_interval_yourId (all lowercase), for example:

  • You subscribed with id: "my-rsi-id" on binance / BTCUSDT / 1m
  • The server assigned the compound ID binance_btcusdt_1m_my-rsi-id
  • Use that full compound ID to unsubscribe
Unsubscribe — single
{
  "type": "unsubscribe",
  "id":   "binance_btcusdt_1m_my-rsi-id"
}
Receive — acknowledgement
{
  "type": "unsubscribed",
  "id":   "binance_btcusdt_1m_my-rsi-id"
}

You can retrieve the compound IDs for all your active subscriptions at any time by sending a list message (see below).

To remove all active subscriptions at once, send an unsubscribe_all message. The server replies with { "type": "unsubscribed_all", "message": "Successfully removed 4 slot(s)." }.

Unsubscribe — all
{ "type": "unsubscribe_all" }

List subscriptions

Send
{ "type": "list" }
Receive
{
  "type": "subscriptions",
  "data": {
    "binance:btcusdt:1m": [
      { "id": "binance_btcusdt_1m_my-rsi-id", "indicator": "rsi", ... }
    ]
  }
}

Pass "unpack": true to receive a flat array instead of the grouped object — useful when you want to iterate subscriptions directly.

Send — flat array
{ "type": "list", "unpack": true }
Receive — flat array
{
  "type": "subscriptions",
  "data": [
    { "id": "binance_btcusdt_1m_my-rsi-id", "indicator": "rsi",
      "exchange": "binance", "symbol": "BTCUSDT", "timeframe": "1m", ... },
    { "id": "binance_ethusdt_5m_my-ema-id", "indicator": "ema",
      "exchange": "binance", "symbol": "ETHUSDT", "timeframe": "5m", ... }
  ]
}

Throttle limits

Your plan's streaming limits are returned in the plan object of the auth_ok message:

FieldDescription
socketSubscriptionsAllowedMaximum number of subscription slots. A slot is one exchange + symbol + interval combination (for example binance:btcusdt:1m), so several indicators on the same asset and interval share one slot.
streamThrottleMsMinimum time in milliseconds between updates pushed to you for the same slot (default 5000).

Subscribe and unsubscribe messages are also rate-limited per connection (bursts of up to 100, refilled at 20 per second). If you exceed this, the server replies with { "type": "error", "error": "Rate limit exceeded. Please slow down your subscription operations." }. Use subscribe_bulk to add many subscriptions in one message.

Error messages

The server sends error messages for invalid subscribe/unsubscribe requests without closing the connection:

Error message format
{
  "type":  "error",
  "error": "Human-readable description of the problem"
}

Reconnection and heartbeat

WebSocket connections can drop due to network issues or server restarts. Build your client to handle disconnects gracefully:

  • Reconnect with exponential backoff. Start with a 1-second delay and double it on each failed attempt, up to a maximum (e.g. 30 seconds). Reset the counter on a successful reconnect.
  • Re-authenticate and re-subscribe after reconnecting. The server does not restore subscriptions automatically — you must repeat the auth message and all subscribe messages after each reconnect.
  • Ping/pong. Send a WebSocket ping frame periodically (every 30 seconds is common) to keep the connection alive through proxies and firewalls. The server will respond with a pong frame.
Node.js — reconnect example
const WebSocket = require('ws');

let ws;
let delay = 1000;

function connect() {
  ws = new WebSocket('wss://v2.taapi.io/streaming');

  ws.on('open', () => {
    delay = 1000; // reset backoff
    ws.send(JSON.stringify({ type: 'auth', token: 'Bearer YOUR_API_KEY' }));
  });

  ws.on('message', (raw) => {
    const msg = JSON.parse(raw);
    if (msg.type === 'auth_ok') {
      // re-subscribe after connect/reconnect
      ws.send(JSON.stringify({
        type: 'subscribe', id: 'my-rsi-id',
        exchange: 'binance', symbol: 'BTCUSDT',
        interval: '1m', indicator: 'rsi',
        params: { period: 14 }
      }));
    }
    if (msg.type === 'update') {
      console.log(msg.subscription, msg.data);
    }
  });

  ws.on('close', () => {
    console.log(`Disconnected. Reconnecting in ${delay}ms…`);
    setTimeout(connect, delay);
    delay = Math.min(delay * 2, 30000);
  });

  ws.on('error', (err) => {
    console.error('WS error:', err.message);
    ws.close();
  });

  // keepalive ping every 30 s
  setInterval(() => { if (ws.readyState === WebSocket.OPEN) ws.ping(); }, 30000);
}

connect();

Health check

HTTP health endpoint
GET https://v2.taapi.io/streaming/health

See the full list of indicators, or start for free.