Skip to content

Receive crypto listing alerts in Node.js

Connect a Node.js receiver to the New Listings Feed crypto listing WebSocket API. This guide selects Binance, Upbit and Bithumb spot listings, checks Upbit quote markets and prints every announced ticker. Use it to build the event handling for a latency-sensitive trading bot.

Use a FREE key for this integration example. It delivers parsed Full events with a 3-second configured delay. The program prints announcements; it does not place orders.

Start with Node.js and a free key

Install Node.js and the ws package, then get a key from the WebSocket product page. Store it in the NLF_API_KEY environment variable on the machine running the example. Keep the key out of browser JavaScript, source control and published logs.

Save the program below as listings.cjs and run node listings.cjs. The ws library lets a Node.js client send the bearer authorization header required by New Listings Feed. The browser WebSocket constructor does not expose that header option.

The FREE key receives parsed events with a 3-second configured delay. Use it to test this receiver before choosing a paid stream.

Choose exchange, event and market separately

The connection requests exchange=binance,upbit,bithumb and market_type=spot. Exchange values within one filter are alternatives; different filters must all match. The program still checks parser.classification.event because a spot notice can be a listing or a delisting.

For Upbit, a new USDT or BTC market is not the same event as a KRW addition. The client accepts only events whose parser.classification.markets contains krw. A notice covering KRW and USDT passes; a USDT-only notice or one with no markets field does not.

Announcement messages and X posts use different top-level types. Both can carry a parsed listing, so the receiver accepts announcement and tweet before checking their classification.

Run the listing receiver

This example opens one connection. A READY message confirms the applied subscription. Event rows include the original source URL and both microsecond timestamps, so the output retains more than a ticker.

// npm install ws
// Save as listings.cjs. Set NLF_API_KEY in your environment, then:
// node listings.cjs
const WebSocket = require('ws');

const key = process.env.NLF_API_KEY;
if (!key) throw new Error('Set NLF_API_KEY before connecting.');

const url = new URL('wss://ws.newlistings.pro/v2/full');
url.searchParams.set('exchange', 'binance,upbit,bithumb');
url.searchParams.set('market_type', 'spot');

const ws = new WebSocket(url, {
  headers: { authorization: `Bearer ${key}` },
});

ws.on('message', (raw) => {
  let message;
  try { message = JSON.parse(raw.toString()); }
  catch {
    console.error('Invalid JSON. Closing the connection.');
    ws.close();
    return;
  }
  if (!message || typeof message !== 'object') return;

  if (message.type === 'success' && message.code === 'READY') {
    console.log({ ready: true, subscription: message.subscription });
    return;
  }
  if (message.type === 'error') {
    console.error(message.code, message.message);
    ws.close();
    return;
  }
  if (!['announcement', 'tweet'].includes(message.type)) return;

  const parser = message.parser;
  if (!parser || !['binance', 'upbit', 'bithumb'].includes(parser.exchange)) return;
  if (parser.classification?.event !== 'listing' ||
      parser.classification.type !== 'spot') return;

  // Only KRW additions for Upbit. Binance and Bithumb need no markets field.
  if (parser.exchange === 'upbit' &&
      !parser.classification.markets?.includes('krw')) return;

  for (const asset of parser.assets ?? []) {
    if (!asset.symbol) continue;
    console.log({
      exchange: parser.exchange,
      symbol: asset.symbol,
      markets: parser.classification.markets,
      display: parser.display,
      source: message.url,
      detected_time_us: message.detected_time_us,
      sent_time_us: message.sent_time_us,
    });
  }
});

ws.on('error', (error) => console.error(error.message));
ws.on('close', (code) => console.log({ closed: code }));

Read every asset in the announcement

One exchange notice can list several tokens. Full keeps them in parser.assets, so the loop prints each symbol separately while retaining the same source URL. Do not assume that the first array entry is the only asset.

Keep the exchange and event type with the symbol. A Binance spot announcement, Binance futures contract and Coinbase roadmap addition describe different events even when the token name is the same.

FREE assets contain ticker symbols. STARTER and PRO can also include confirmed contracts, DEX pairs, project metrics and suggested matches when available. An inferred contract under suggested_match has a different meaning from an exchange-published address in contracts.

Check delivery and connection behavior

An authenticated connection can be quiet between announcements. Use READY and the documented connection lifecycle to distinguish a healthy idle connection from a rejected key. The ws library answers protocol pings automatically.

The short receiver stops when the connection closes. Before running unattended, use the official reconnect examples, which handle HTTP upgrade failures, rate limits and bounded retry delays. Neither live stream replays events missed during a disconnect; paid Full history is a separate HTTPS API.

Once the selected events are correct, measure arrival on the server that will run your bot. Printing to a terminal is an integration check, not a speed benchmark. The measurement guide explains clock uncertainty and the different timestamp boundaries on Fast and Full.

Keep reading

Get a free key