pnclFEED Free key

Quickstart notes

Read the Pinnacle WebSocket feed in Node.js

The WebSocket contract in Node: connect, subscribe within five seconds, answer pings, and read the snapshot before the updates. One file, no dependencies.

The WebSocket quickstart on this site is written in Python. The contract is identical from Node.js, and modern Node ships a built-in WebSocket client, so the whole reader fits in one file with no dependencies. Here is the same connection, translated.

The contract, Node edition

The socket sits next to the REST API and takes your key on the URL as ?key=, with the header form also accepted on the upgrade request, as the WebSocket page documents, checked 2026-10-04. Three rules carry the session: send a subscribe message within five seconds of connecting or the socket closes; the first frame on each stream is a snapshot and everything after it is an update; answer each ping frame with a pong.

The reader in one file

const WS = process.env.ODDS_WS_URL;
const KEY = process.env.ODDS_API_KEY;

function main() {
  const ws = new WebSocket(`${WS}?key=${KEY}`);
  const SUB = JSON.stringify({ type: "subscribe",
    streams: ["live"], sport_ids: [1, 2] });
  const PONG = JSON.stringify({ type: "pong" });

  ws.addEventListener("open", () => ws.send(SUB));
  ws.addEventListener("message", (ev) => {
    const f = JSON.parse(ev.data);
    if (f.type === "ping") ws.send(PONG);
    else if (f.type === "snapshot")
      console.log("baseline", (f.events || []).length);
    else console.log(f.type, f);
  });
  ws.addEventListener("close", () => setTimeout(main, 5000));
}
main();

The open handler must send the subscribe immediately, because the five-second window starts when the connection does. The subscribe message names streams and sport IDs; you can subscribe by up to 200 event IDs per stream instead, per the same page.

Reading the first minute

A healthy first minute has a shape. The socket opens, your subscribe goes out inside the window, and the snapshot arrives carrying the baseline of everything you subscribed to. Updates then land as prices change, at whatever pace the board moves. Quiet stretches between frames are normal; the ping frames are the heartbeat in between, and each one wants its pong.

If the socket closes in the first seconds, the usual suspect is a subscribe that left too late or never left. Check the open handler before anything else.

Before you run it

Two checks first. The add-on: raw frames need the WebSocket add-on on a poll, poll + push or bulk plan, as the pricing page lists, checked 2026-10-04. And the baseline habit: whatever you do with update frames, build your state from the snapshot first, because a reconnect hands you a new snapshot and invalidates the old one.

From reading to state

Printing frames is the smoke test. The real consumer keeps a map of event state, applies each update to it, and treats every reconnect as a full reset. The Python version's notes on recovery apply unchanged; only the library differs.

One socket, one subscribe, snapshot first. Node reads the stream exactly like Python does, one frame at a time.