Blog
WebSocketsTrading systemsNode.jsJavaScriptBinance

Binance Mini Ticker in JavaScript: Build a Reliable Market-Data Consumer

Build a reliable Binance miniticker consumer in JavaScript and Node.js. Learn stream selection, payload parsing, and robust WebSocket handling with Siebly.io.

Siebly.io11 min readMarkdown

Overview

Binance miniTicker is a compact Spot market-data stream. It gives you a 24 hour rolling window of price and volume, not the UTC day, and not a full market model. The single-symbol stream is @miniTicker. The all-symbol stream is !miniTicker@arr, and that array only contains tickers that changed. Binance documents both at a 1000ms update speed. A missing symbol means it did not change. It does not mean the price went to zero, and it does not mean you should clear stored state.

The npm package is binance. It opens the combined Spot stream, subscribes by topic name, answers ping frames, and reconnects after the exchange drops the socket, including the scheduled 24 hour disconnect. It does not throttle you. Public miniTicker data does not need API keys. Awaitable WebSocket API calls are a separate feature on this package: sendWSAPIRequest() and WebsocketAPIClient wait for one response. A miniTicker subscription does not. That WebSocket API surface is not on every Siebly package. Bitmart, for example, has no sendWSAPIRequest() and no WebsocketAPIClient.

Binance's own stream docs stay the source of truth for names, payloads, and limits. The SDK is the client you call.

Key Takeaways

  • Pick @miniTicker or !miniTicker@arr from the amount of data you actually need. Both are documented at 1000ms. The all-symbol array only includes tickers that changed.
  • The raw event type is 24hrMiniTicker. Price and volume fields arrive as strings: c, o, h, l, v, q.
  • await wsClient.subscribe(...) finishes when the client has connected and sent the subscription. Tickers arrive later on message, and on formattedMessage if you set beautify: true.
  • The client answers pings and reconnects on its own. You still decide what to do with a gap in events.
  • The SDK does not apply rate limits or retry failed REST calls. WebSocket topics are cached and resubscribed after a reconnect.

What Binance miniTicker data represents in a JavaScript application

A ticker event is an input. Before you store anything, know which fields Binance sends, which numbers you calculate yourself, and which symbol state you keep between events. The Binance JavaScript SDK is the client. Binance's stream docs define the contract.

Spot miniTicker publishes a 24 hour rolling window for one symbol, or for changed symbols only. The raw object looks like this:

Imported example

JavaScript
{
  "e": "24hrMiniTicker",
  "E": 1672515782136,
  "s": "BNBBTC",
  "c": "0.0025",
  "o": "0.0010",
  "h": "0.0025",
  "l": "0.0010",
  "v": "10000",
  "q": "18"
}

e is the event type, E is the event time, s is the symbol, c is close, o is open, h is high, l is low, v is base asset volume, and q is quote asset volume. Those price and volume values are strings. The all-symbol message is an array of the same objects, and only changed tickers are in it.

The SDK then adds wsMarket, streamName, wsKey, and isWSAPIResponse on each object it emits. Those are client fields. They are not part of Binance's payload. Coin-margined futures mini tickers can also include ps (the pair). Spot events do not.

How miniTicker differs from a full ticker event

@ticker is the wider 24 hour ticker. It adds price change, weighted average, best bid and ask, trade ids, and trade counts. Use miniTicker when close, open, high, low, and the two volumes are enough. If you need the rest, subscribe to @ticker.

The all-market full ticker stream !ticker@arr is deprecated in this SDK. The client comments mark it deprecated as of 2025-11-14, with a retirement date of 2026-03-26, and point you at @ticker or !miniTicker@arr.

The WebSocket protocol is only the transport. Keep the topic list, the parser, and your symbol map in separate places so you can change one without rewriting the others.

What a miniTicker consumer can and cannot infer

You can show the close, open, high, low, or volume you just received. You can store the event with its symbol and E. You can compute your own metrics if you document the formula and the window.

One event is not history. A symbol missing from !miniTicker@arr still has its last stored values. Check the shape before you write state. If a message is malformed, log it and skip it. Treat the stream as market data for your software, not as a forecast. The SDK will not slow you down to stay inside Binance's connection or message limits. That policy belongs in your process.

How the Binance miniTicker WebSocket stream delivers events

A raw browser or ws client can open wss://stream.binance.com:9443/ws/btcusdt@miniTicker or wss://stream.binance.com:9443/ws/!miniTicker@arr. The binance package does not take those URLs. Spot topics go to the wsKey 'main', which is the combined stream at wss://stream.binance.com:9443/stream. You pass topic strings. The client unwraps the { stream, data } envelope before it emits, so your handler sees the ticker object or the array, plus the extra client fields above.

Binance documents !miniTicker@arr as an array of tickers that changed, updated every 1000ms. That is the published speed, not a timer you should schedule against. A reconnect, a quiet symbol, or a dropped message will not line up with a 1 second clock. For a wider description of processing data as it arrives, IBM's page on real-time data is a decent background read.

Read the stream contract before writing the consumer

Check Binance's current page for the stream name, the lowercase symbol, the payload, and the update speed before you lock those into code. The Binance JavaScript tutorial shows how this package is set up.

For one symbol, expect an object with e === '24hrMiniTicker'. For all symbols, expect an array of those objects. The package exports is24hrMiniTickerRaw and isAll24hrMiniTickerRaw for the raw message event. There is no formatted type guard for this stream. isAll24hrMiniTickerRaw reads data[0] with no length check, so an empty array throws. Test Array.isArray(data) && data.length > 0 first.

Subscriptions and awaitable WebSocket operations are different

subscribe(), subscribeSymbolMini24hrTicker(), and subscribeAllMini24hrTickers() return a promise. await means the client connected and requested the topics. It does not mean a ticker arrived. Tickers show up on the event emitter.

sendWSAPIRequest() and WebsocketAPIClient are the other path. You await one command and get one response. getSpot24hrTicker({ symbol, type: 'MINI' }) is that kind of call. The body uses names like symbol, lastPrice, openPrice, volume, and quoteVolume, plus open time, close time, and trade ids. That is a snapshot from the WebSocket API, not a 24hrMiniTicker stream event. Do not parse one with the other's field list.

Public miniTicker needs no keys. WebSocket API trading calls do. On Binance, Ed25519 keys can log in once. HMAC and RSA sign each command.

Choose individual or all-symbol miniTicker streams for the workload

StreamWhat you subscribe toWhat each message contains
One symbolbtcusdt@miniTicker, or subscribeSymbolMini24hrTicker('BTCUSDT', 'spot')One 24hrMiniTicker object.
All symbols!miniTicker@arr, or subscribeAllMini24hrTickers('spot')An array of tickers that changed since the last push.

Both are documented at 1000ms. Traffic still depends on how many symbols move. Measure it, and read Binance's current limits on connections and streams per connection. The client logs a warning when one connection is carrying a lot of topics. It does not split them for you. If Binance keeps disconnecting you, use more than one WebsocketClient.

The same helpers accept 'usdm' and 'coinm'. Spot uses wsKey 'main'. USD-M mini tickers use 'usdmMarket'.

When an individual-symbol stream fits

Use it for a small, named set. One topic per symbol makes the scope obvious. When the set changes, subscribe or unsubscribe as part of that change. unsubscribe() removes the topic from the cache so a later reconnect will not put it back.

When an all-symbol stream fits

Use it when you want broad coverage and you are ready to filter. Keep the latest object per symbol if you need a snapshot, because unchanged names are left out. Confirm coverage against the current Binance docs before you promise a symbol will appear.

REST polling asks for a snapshot on your schedule. The WebSocket pushes events. Neither one gives you history by itself. If you need both, store the REST snapshot, then apply stream events on top, and decide which timestamp wins.

Build a resilient Node.js miniTicker consumer without hidden assumptions

Split the work. The client owns the socket. Your code checks the payload, maps it into your own type, and updates state. Binance defines the fields. The SDK quickstart is only the setup.

  1. Connect: Call subscribe with the topic and 'main'. Listen for open, reconnecting, reconnected, and exception. No API key for this public stream.
  2. Validate: Use the raw type guards, or check eventType === '24hrMiniTicker' on a beautified event. Skip empty arrays.
  3. Parse: Read E and s from the raw event, or eventTime and symbol from the formatted one. Reject a payload that is missing them.
  4. Normalize: Copy the fields you keep into your own object. Leave the raw message in the log if you need it later.
  5. Update state: Write that object under the symbol. On the all-symbol array, do this once per element. Do not delete symbols that were absent.
  6. Test: Feed fixtures for a single object, a changed-only array, a bad payload, a duplicate E, and a reconnect. Do not depend on the live socket to produce the same sequence twice.

Validate and normalize events before updating state

With beautify: false (the default), message gives you the short keys and string numbers. With beautify: true, formattedMessage renames them and parses the known numeric strings:

Imported example

JavaScript
{
  eventType: '24hrMiniTicker',
  eventTime: 1672515782136,
  symbol: 'BNBBTC',
  close: 0.0025,
  open: 0.001,
  high: 0.0025,
  low: 0.001,
  baseAssetVolume: 10000,
  quoteAssetVolume: 18
}

parseFloat runs on close, open, high, low, baseAssetVolume, and quoteAssetVolume. eventType stays the string 24hrMiniTicker. Use E or eventTime to spot an older event. Equal timestamps are not a reason to drop the event. Define that rule yourself.

Test recovery paths and keep operational boundaries explicit

Binance keeps a market-data WebSocket for 24 hours, sends ping frames, and disconnects if it does not get a pong. This client answers those pings and reconnects when the socket dies, including that 24 hour drop. Cached topics are subscribed again. You get reconnecting and then reconnected. Set disableHeartbeat: true only if you intend to handle this yourself. The client still cannot promise the stream never gaps. After reconnected, decide whether you need a REST snapshot to fill the hole.

Connection and stream limits stay your problem. The Siebly.io SDK page lists the packages. For this article, the package name on npm is binance.

Implement Binance miniTicker with Siebly.io as the integration layer

Install the client and subscribe. This follows examples/WebSockets/Public/ws-public.ts.

Imported example

JavaScript
import { is24hrMiniTickerRaw, isAll24hrMiniTickerRaw, WebsocketClient } from "binance";

const wsClient = new WebsocketClient({
  // Optional. Formatted events are emitted on "formattedMessage".
  beautify: true,
});

wsClient.on("open", (data) => {
  console.log("connection opened:", data.wsKey);
});

wsClient.on("reconnecting", (data) => {
  console.log("reconnecting", data?.wsKey);
});

wsClient.on("reconnected", (data) => {
  console.log("reconnected", data?.wsKey);
});

wsClient.on("exception", (data) => {
  console.error("ws exception", data?.wsKey);
});

// Raw event. Prices and volumes are still strings.
wsClient.on("message", (data) => {
  if (is24hrMiniTickerRaw(data)) {
    console.log(data.s, data.c, data.E, data.streamName);
    return;
  }

  if (Array.isArray(data) && data.length > 0 && isAll24hrMiniTickerRaw(data)) {
    for (const ticker of data) {
      console.log(ticker.s, ticker.c, ticker.E);
    }
  }
});

// Readable keys and numbers. There is no formatted type guard for miniTicker.
wsClient.on("formattedMessage", (data) => {
  const events = Array.isArray(data) ? data : [data];

  for (const event of events) {
    if (event.eventType !== "24hrMiniTicker") {
      continue;
    }

    console.log(event.symbol, event.close, event.eventTime);
  }
});

// "main" is the Spot combined stream: wss://stream.binance.com:9443/stream
await wsClient.subscribe(["btcusdt@miniTicker", "!miniTicker@arr"], "main");

The helper methods build those topic strings for you. Spot, USD-M, and COIN-M are the three market arguments. They are in the same public example, commented out:

Imported example

JavaScript
await wsClient.subscribeSymbolMini24hrTicker("BTCUSDT", "spot");
await wsClient.subscribeAllMini24hrTickers("spot");

// await wsClient.subscribeSymbolMini24hrTicker('BTCUSDT', 'usdm');
// await wsClient.subscribeAllMini24hrTickers('coinm');

await on those calls waits for the subscription request, not for the first ticker.

Keep the SDK boundary explicit

Use the client to connect, subscribe, heartbeat, and reconnect. Keep validation, your symbol map, and any throttling in your code. Private REST and WebSocket API calls are where the package signs requests, sets timestamps, and types the bodies. A public miniTicker consumer does not need that.

If you do want a one-shot ticker over the WebSocket API, that is a different method and a different payload. From examples/WebSockets/WS-API/ws-api-client.ts:

Imported example

JavaScript
import { WebsocketAPIClient } from "binance";

const wsClient = new WebsocketAPIClient({
  api_key: process.env.API_KEY_COM,
  api_secret: process.env.API_SECRET_COM,
  beautify: true,
});

const response = await wsClient.getSpot24hrTicker({
  symbol: "BTCUSDT",
  type: "MINI",
});

console.log(response);

type: 'MINI' here is the WebSocket API mini ticker (symbol, lastPrice, openPrice, volume, and so on). It is not the 24hrMiniTicker stream. Public market calls on that API can run without a key, but trading calls need one, and you should keep keys server-side with withdrawal permission off.

The same await pattern exists as a raw command:

Imported example

JavaScript
import { WebsocketClient, WS_KEY_MAP } from "binance";

const wsClient = new WebsocketClient();

const response = await wsClient.sendWSAPIRequest(WS_KEY_MAP.mainWSAPI, "ticker.24hr", {
  symbol: "BTCUSDT",
  type: "MINI",
});

That promise resolves with the response, or rejects. Stream subscriptions never work this way.

Move from a public-data prototype to a maintained integration

Start with one symbol and the message handler. Add the all-symbol array once the single-object path is boring. Then add beautify if you want the long names. Test a bad payload and a reconnect before you write anything to a database.

Package setup is on the Binance JavaScript SDK page and the tutorial. Stream names and limits stay on Binance's docs.

Build your market-data consumer on a clear contract

Subscribe to btcusdt@miniTicker or !miniTicker@arr through WebsocketClient, check for 24hrMiniTicker before you touch state, and keep the last value for symbols the all-market array skipped. Let the client handle ping, pong, and the 24 hour reconnect. Handle gaps, throttling, and storage yourself.

The Siebly.io SDK list is the index. This consumer uses the binance package.

Frequently Asked Questions

What is Binance miniTicker?

It is a 24 hour rolling mini ticker on Binance market streams. The event type is 24hrMiniTicker. One symbol uses @miniTicker. All changed symbols use !miniTicker@arr. Fields, in the raw payload, are e, E, s, c, o, h, l, v, and q. Price and volume are strings. Check the current Binance stream page before you depend on that list.

How do I use the miniTicker WebSocket stream in Node.js?

Install binance, create a WebsocketClient, and subscribe with the topic and the wsKey 'main'. Handle message for the raw object. Turn on beautify: true if you also want formattedMessage. is24hrMiniTickerRaw and isAll24hrMiniTickerRaw cover the raw shapes. Guard the array guard with a length check. The tutorial walks through package setup.

What is the difference between miniTicker and ticker data?

@ticker includes price change, bid and ask, and trade counts on top of the open, high, low, close, and volume fields. miniTicker stops at those compact fields. The SDK marks !ticker@arr as deprecated and points at @ticker or !miniTicker@arr. The WebSocket API method getSpot24hrTicker({ type: 'MINI' }) is a third shape again. Read the payload you actually subscribed to.

Does Binance miniTicker provide data for every symbol?

@miniTicker is one symbol. !miniTicker@arr is every symbol that changed in that 1000ms window, not every listed symbol on every message. Store the last event per symbol if you need a full board.

Can a Siebly SDK handle miniTicker rate limits automatically?

No. The binance client does not throttle subscriptions or REST calls. It will warn when one connection has a large topic list. Binance's limits still apply, and your process has to respect them. WebSocket API replies can include a rateLimits array. The client does not slow down because of it.

Do I need API credentials to read Binance miniTicker data?

No. Public market streams subscribe without a key. Add credentials only when you call a private REST route or an authenticated WebSocket API command. Keep those secrets on the server, use a key that cannot withdraw, and do not paste them into examples or logs.

Should I use REST polling or a miniTicker WebSocket stream?

Use the stream when you want Binance to push the 24 hour mini ticker as symbols move. Use REST when you want a snapshot on a timer you control, or a backfill after reconnected. The SDK exposes both. The stream path is WebsocketClient. The REST path is MainClient for Spot.

Related articles

Continue from here

Related Siebly resources

All articles

Subscribe on Substack

Complete the Substack form below to join our newsletter. Substack handles all subscriber data directly.