WebSocket Streaming

Receive calculated indicator values pushed to your client in real time as each candle closes — no polling, no repeated HTTP calls. Establish one persistent connection and subscribe to as many streams as your plan allows.

WebSocket URL:

wss://v2.taapi.io/streaming

Timeframe throttles

Streaming is optimised for intraday intervals. Supported timeframes and their minimum push intervals:

Timeframe Min push interval
1m 2 seconds
5m 5 seconds
15m 8 seconds
1h 15 seconds

For macro intervals (4h, 1d, 1w) use REST polling instead — push frequency would offer no meaningful advantage over a scheduled GET.


Connection flow

1. Connect & authenticate

Open a WebSocket connection to wss://v2.taapi.io/streaming. Send the auth message immediately — the server drops unauthenticated connections after a short timeout.

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

Server response on success:

{
  "type": "auth_ok",
  "userId": "6a1b2c3d4e5f6a1b2c3d4e5f",
  "plan": {
    "socketSubscriptionsAllowed": 50,
    "streamThrottleMs": 5000
  }
}

Server response on failure:

{ "type": "auth_error", "error": "Unauthorized" }

2. Subscribe to an indicator

Each subscription requires a unique id that you define. This becomes your routing key — the server echoes it back prefixed with EXCHANGE_SYMBOL_interval_ in all update messages.

{
  "type":      "subscribe",
  "id":        "my_ema_stream",
  "exchange":  "bybit",
  "symbol":    "BTCUSDT",
  "interval":  "1m",
  "indicator": "ema",
  "params":    { "period": 20 }
}
Field Required Description
type Always "subscribe"
id Your unique routing key for this stream
exchange Exchange identifier, e.g. binance, bybit
symbol Trading pair, e.g. BTCUSDT, ETHUSDT
interval Candle interval: 1m 5m 15m 1h
indicator Indicator name, e.g. rsi, macd, ema
params Indicator-specific parameters, e.g. { "period": 20 }
candleClose Set to true to only receive updates when a candle closes (no intra-candle ticks)

Immediate confirmation from the server:

{
  "type":         "subscribed",
  "id":           "BYBIT_BTCUSDT_1m_my_ema_stream",
  "subscription": "BYBIT:BTCUSDT:1m",
  "indicator":    "ema"
}

3. Receive updates

The server pushes an update message each time new data is computed. All streams sharing the same exchange + symbol + interval are bundled into a single payload:

{
  "type":         "update",
  "subscription": "BYBIT:BTCUSDT:1m",
  "data": {
    "BYBIT_BTCUSDT_1m_my_ema_stream": {
      "value":     [76597.71],
      "timestamp": [1777374240]
    }
  }
}

Multi-output indicators deliver all output fields inside the same key:

{
  "BYBIT_BTCUSDT_1m_my_macd_stream": {
    "valueMACD":       [-18.63],
    "valueMACDSignal": [-6.47],
    "valueMACDHist":   [-12.15],
    "timestamp":       [1777374480]
  }
}

Bulk subscribe

For high-throughput setups, multiplex multiple indicators, symbols, and intervals into a single command:

{
  "type":      "subscribe_bulk",
  "exchange":  "bybit",
  "symbols":   ["BTCUSDT", "ETHUSDT"],
  "intervals": ["1m", "5m"],
  "indicators": [
    { "name": "rsi",  "id": "bulk_rsi",  "params": { "period": 14 } },
    { "name": "macd", "id": "bulk_macd", "params": { "fast": 12, "slow": 26, "signal": 9 } },
    { "name": "ema",  "id": "bulk_ema",  "params": { "period": 20 } }
  ]
}

The server responds in three stages:

// 1. Processing acknowledgement
{
  "type":          "subscribe_bulk_ack",
  "status":        "processing",
  "totalConsumed": 12,
  "message":       "Bulk subscription accepted. Processing 12 indicator subscriptions."
}

// 2. All streams registered
{
  "type":    "subscribe_bulk_complete",
  "subKeys": ["BYBIT:BTCUSDT:1m", "BYBIT:BTCUSDT:5m", "BYBIT:ETHUSDT:1m", "BYBIT:ETHUSDT:5m"],
  "count":   12,
  "message": "Successfully registered 12 indicator subscription(s) across 4 slot(s)."
}

// 3. Ongoing update pushes (same format as single subscribe)
{
  "type":         "update",
  "subscription": "BYBIT:BTCUSDT:1m",
  "data": {
    "BYBIT_BTCUSDT_1m_bulk_ema": { "value": [76572.61], "timestamp": [1777374480] },
    "BYBIT_BTCUSDT_1m_bulk_rsi": { "value": [32.78],    "timestamp": [1777374480] }
  }
}

Lifecycle commands

Unsubscribe a specific stream

{ "type": "unsubscribe", "id": "my_ema_stream" }

Unsubscribe all streams

{ "type": "unsubscribe_all" }

List active subscriptions

{ "type": "list", "unpack": true }

Complete example (JavaScript)

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

ws.onopen = () => {
  // 1. Authenticate immediately
  ws.send(JSON.stringify({
    type:  'auth',
    token: 'Bearer YOUR_API_KEY'
  }));
};

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

  if (msg.type === 'auth_ok') {
    // 2. Subscribe once authenticated
    ws.send(JSON.stringify({
      type:      'subscribe',
      id:        'my_rsi',
      exchange:  'bybit',
      symbol:    'BTCUSDT',
      interval:  '1m',
      indicator: 'rsi',
      params:    { period: 14 }
    }));
  }

  if (msg.type === 'update') {
    // 3. Route incoming data by your custom ID
    const rsi = msg.data['BYBIT_BTCUSDT_1m_my_rsi'];
    if (rsi) console.log('RSI:', rsi.value[0]);
  }

  if (msg.type === 'error') {
    console.error('Server error:', msg.message);
  }
};

ws.onerror = (err) => console.error('WebSocket error:', err);
ws.onclose = () => console.log('Connection closed');

Multiple subscriptions

Subscribe to as many streams as your plan allows on a single connection. Route incoming updates using the prefixed key pattern (EXCHANGE_SYMBOL_interval_yourId):

// After auth_ok — subscribe to several streams
const streams = [
  { id: 'rsi_btc',  exchange: 'bybit',   symbol: 'BTCUSDT', interval: '1m',  indicator: 'rsi' },
  { id: 'ema_eth',  exchange: 'bybit',   symbol: 'ETHUSDT', interval: '5m',  indicator: 'ema', params: { period: 20 } },
  { id: 'macd_sol', exchange: 'binance', symbol: 'SOLUSDT', interval: '15m', indicator: 'macd' },
];

streams.forEach(s => ws.send(JSON.stringify({ type: 'subscribe', ...s })));

// Route updates
ws.onmessage = ({ data }) => {
  const { type, subscription, data: values } = JSON.parse(data);
  if (type !== 'update') return;

  const [exchange, symbol, interval] = subscription.split(':');
  console.log(`[${exchange} ${symbol} ${interval}]`, values);
};

Reconnection

WebSocket connections can drop due to network interruptions. Implement exponential backoff:

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

  ws.onopen = () => {
    delay = 1000; // reset on success
    authenticate(ws);
  };

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

  return ws;
}

connect();

Health check

A simple HTTP endpoint confirms the streaming service is up:

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

Returns 200 OK when the service is running.


Error messages

Message Cause
Unauthorized Auth message missing or invalid API key
Already subscribed Duplicate subscribe for the same stream id
Unknown indicator Indicator name not recognised
Exchange not supported Exchange identifier is invalid
Rate limit exceeded Too many subscriptions for your plan

Was this page helpful? Send us feedback or open a support ticket.