---
title: "WebSocket protocol"
description: "The remote-FFT wire protocol the visualizer speaks in websocket mode, and the reference servers."
canonical_url: "https://www.fftvisualizer.com/guide/websocket-protocol"
---
# WebSocket protocol

> The remote-FFT wire protocol the visualizer speaks in websocket mode, and the reference servers.

In `websocket` mode the visualizer connects to a server that has **already computed** the
FFT and streams it as compact binary frames — so the browser only draws. This lets the FFT
run on a separate device (a Raspberry Pi, a media server) feeding any number of browsers.

## The pre-computed-FFT protocol

`mode: 'websocket'` expects a server that sends **pre-computed** FFT frames.

**1. Config message (JSON), once on connect:**

```json
{ "type": "config", "mode": "fft", "bins": 80, "fps": 120 }
```

**2. Binary FFT frames, continuously:**

- One `uint8` (0–255) per frequency bin — `bins` bytes per frame
- 0 = silence, 255 = maximum amplitude
- Typically 100 Hz – 18 kHz, exponentially spaced

For best results the server should capture at 48 kHz+, apply a Hann/Hamming window, compute
a 1024–2048-point FFT, map to exponentially-spaced bands, apply A-weighting, convert to dB,
normalize to 0–255, and stream at 60–120 fps.

## Reference servers

The repository's `backend-examples/` has servers that capture system audio, compute FFT, and
stream it in this format: **Python** (pyalsaaudio + numpy, incl. a Raspberry Pi variant),
**Node.js** (node-audiorecorder + fft.js), and **Rust** (cpal + rustfft).

## Two different WebSocket protocols

Don't confuse the visualizer's `websocket` mode with the raw-PCM engines:

<table>
<thead>
  <tr>
    <th>
      
    </th>
    
    <th>
      Sends over the wire
    </th>
    
    <th>
      FFT runs
    </th>
    
    <th>
      Consumed by
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <strong>
        Pre-computed FFT
      </strong>
      
       <em>
        (this page)
      </em>
    </td>
    
    <td>
      <code>
        uint8
      </code>
      
       FFT magnitudes
    </td>
    
    <td>
      On the server
    </td>
    
    <td>
      <code>
        FFTVisualizer
      </code>
      
       <code>
        mode: 'websocket'
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <strong>
        Raw PCM
      </strong>
    </td>
    
    <td>
      Interleaved PCM audio
    </td>
    
    <td>
      In the browser (WASM)
    </td>
    
    <td>
      Core <a href="https://www.fftvisualizer.com/core/audio-engines">
        <code>
          createWebSocketFft
        </code>
      </a>
      
       / Vue <a href="https://www.fftvisualizer.com/vue/composables">
        <code>
          useWebSocketFft
        </code>
      </a>
    </td>
  </tr>
</tbody>
</table>

The raw-PCM path streams audio and does the FFT client-side; feed its output into the
visualizer with `mode: 'external'`. Its config message uses `"mode": "pcm"` with
`sampleRate`, `bitDepth`, and `channels` fields instead of the `fft` config above.


## Sitemap

See the full [sitemap](https://www.fftvisualizer.com/sitemap.md) for all pages.
