# How to Integrate openclaw-windows-node with a Node.js Application: WebSocket Protocol Guide

> Integrate openclaw-windows-node with Node.js using WebSockets. Build a connect handshake and handle invoke requests to control your application from an OpenClaw gateway.

- Repository: [openclaw/openclaw-windows-node](https://github.com/openclaw/openclaw-windows-node)
- Tags: how-to-guide
- Published: 2026-06-06

---

**You can integrate a Node.js application with the openclaw-windows-node ecosystem by implementing the same WebSocket protocol used by the C# Windows node, constructing a `connect` handshake with platform-specific metadata, and handling `node.invoke.request` events to execute commands.** This allows your JavaScript code to register capabilities and receive instructions from an OpenClaw gateway just like the native Windows client.

The `openclaw/openclaw-windows-node` repository provides a full-featured node implementation written in C# that connects to OpenClaw gateways over WebSocket. While the official client runs as a Windows tray application, any runtime—including Node.js—can interoperate with the same infrastructure by speaking the identical JSON protocol and authentication flows. By mirroring the handshake logic found in [`src/OpenClaw.Shared/WindowsNodeClient.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/src/OpenClaw.Shared/WindowsNodeClient.cs), your application can advertise capabilities such as `screen.snapshot` or `camera.list` and respond to remote invocation requests.

## Understanding the OpenClaw Protocol Architecture

### The WebSocket Handshake Process

Every connection to an OpenClaw gateway begins with a `connect` request that negotiates protocol versions and advertises node capabilities. In [`src/OpenClaw.Shared/WindowsNodeClient.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/src/OpenClaw.Shared/WindowsNodeClient.cs), the `BuildNodeConnectMessage()` method constructs a payload containing a `client` object with `platform: "windows"` and `deviceFamily: "Windows"`, alongside `caps` (capability categories) and `commands` (the specific commands the node can execute) sourced from `NodeRegistration` (lines 24–31). Your Node.js client must replicate this exact schema to be recognized as a valid Windows-compatible node.

### Gateway Command Allowlist Validation

The OpenClaw gateway maintains a strict allowlist system that validates commands against both the node's declared capabilities and platform-specific policies. According to [`docs/gateway-node-integration.md`](https://github.com/openclaw/openclaw-windows-node/blob/main/docs/gateway-node-integration.md), the gateway verifies that requested commands are declared in the node's `commands` array and are permitted for the `"windows"` platform. Standard allowed commands include `screen.snapshot`, `camera.list`, and `location.get`. If your Node.js client requires "dangerous" commands like `camera.snap`, you must first add them to the gateway's `gateway.nodes.allowCommands` configuration before the handshake will succeed.

## Implementing the Node.js Client Step by Step

### Install Required Dependencies

Begin by installing a WebSocket client library and utilities for UUID generation.

```bash
npm install ws uuid

```

For bootstrap token authentication (optional), you will also need an Ed25519 implementation such as `ed25519-supercop`.

### Construct the Connect Payload

Mirror the C# implementation in `BuildNodeConnectMessage()` by creating a JSON payload that includes protocol versions, client metadata, and capability declarations. The `client` object must specify `platform: "windows"` and `deviceFamily: "Windows"` to match the gateway's policy expectations, even when running in Node.js.

```javascript
const { v4: uuidv4 } = require('uuid');

function buildConnectMessage(gatewayToken) {
  return {
    type: 'req',
    id: uuidv4(),
    method: 'connect',
    params: {
      minProtocol: 3,
      maxProtocol: 4,
      client: {
        id: 'node-host',
        version: '0.1.0',
        platform: 'windows',          // Required for gateway policy matching
        deviceFamily: 'Windows',
        mode: 'node',
        displayName: 'Node.js Client',
      },
      role: 'node',
      caps: ['demo'],                 // Capability categories
      commands: ['screen.snapshot'], // Commands this node supports
      permissions: {},
      auth: gatewayToken ? { token: gatewayToken } : {},
      locale: 'en-US',
      userAgent: 'openclaw-nodejs/0.1.0',
      device: {
        id: 'nodejs-client-' + uuidv4(),
      },
    },
  };
}

```

### Handle Authentication Methods

The `BuildConnectAuth()` method in [`WindowsNodeClient.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/WindowsNodeClient.cs) (lines 72–85) supports three authentication strategies: **device tokens** (persistent credentials), **bootstrap tokens** (QR-flow with Ed25519 signing), and **gateway tokens** (pre-shared secrets). For a straightforward Node.js integration, use a **gateway token** configured in your gateway settings, which requires no cryptographic signing. If implementing bootstrap token support, replicate the Ed25519 signing logic found in [`src/OpenClaw.Shared/DeviceIdentity.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/src/OpenClaw.Shared/DeviceIdentity.cs).

### Process Invoke Requests

Once connected, your client must listen for `node.invoke.request` events—messages with `type: "event"` and `"event": "node.invoke.request"`—and extract the `requestId`, `command`, and `args` fields. This mirrors the C# client's `HandleNodeInvokeEventAsync()` logic. Validate that the requested command exists in your declared `commands` array before execution.

### Send Results and Persist Device Tokens

After executing a command, send a `node.invoke.result` response containing the original `requestId`, a boolean `ok` status, and the result payload or error details. Following a successful `hello-ok` response from the gateway, extract and persist the `auth.deviceToken` for subsequent connections. This replicates the `StoreDeviceTokenForRole()` logic in [`WindowsNodeClient.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/WindowsNodeClient.cs) (lines 172–176), enabling persistent authentication across application restarts.

## Complete Node.js Integration Example

The following implementation connects to an OpenClaw gateway, authenticates with a gateway token, advertises a `screen.snapshot` capability, and responds to invocation requests.

```javascript
const WebSocket = require('ws');
const { v4: uuidv4 } = require('uuid');

const GATEWAY_URL = 'wss://my-gateway.example.com/ws';
const GATEWAY_TOKEN = 'my-gateway-token';
const DEVICE_ID = 'nodejs-client-' + uuidv4();

function buildConnectMessage() {
  return {
    type: 'req',
    id: uuidv4(),
    method: 'connect',
    params: {
      minProtocol: 3,
      maxProtocol: 4,
      client: {
        id: 'node-host',
        version: '0.1.0',
        platform: 'windows',
        deviceFamily: 'Windows',
        mode: 'node',
        displayName: `Node.js Client (${require('os').hostname()})`,
      },
      role: 'node',
      caps: ['demo'],
      commands: ['screen.snapshot'],
      permissions: {},
      auth: { token: GATEWAY_TOKEN },
      locale: 'en-US',
      userAgent: 'openclaw-nodejs/0.1.0',
      device: { id: DEVICE_ID },
    },
  };
}

const ws = new WebSocket(GATEWAY_URL);

ws.on('open', () => {
  console.log('WebSocket connected');
  ws.send(JSON.stringify(buildConnectMessage()));
});

ws.on('message', (data) => {
  const msg = JSON.parse(data);
  if (msg.type !== 'event') return;

  switch (msg.event) {
    case 'node.invoke.request':
      handleInvoke(msg.payload);
      break;
    case 'hello-ok':
      console.log('Paired successfully. Device token:', msg.payload?.auth?.deviceToken);
      // TODO: Persist token for future connections
      break;
    case 'health':
      console.log('Gateway health:', msg.payload);
      break;
  }
});

async function handleInvoke(payload) {
  const { requestId, command, args } = payload;
  
  if (command === 'screen.snapshot') {
    // Implement actual screenshot logic here
    const result = { imageBase64: 'base64-encoded-image-data' };
    sendResult(requestId, true, result);
  } else {
    sendResult(requestId, false, null, `Unsupported command: ${command}`);
  }
}

function sendResult(requestId, ok, result, errorMessage = null) {
  const response = {
    type: 'req',
    id: uuidv4(),
    method: 'node.invoke.result',
    params: {
      id: requestId,
      nodeId: DEVICE_ID,
      ok,
      payload: result,
      error: errorMessage ? { message: errorMessage } : null,
    },
  };
  ws.send(JSON.stringify(response));
}

```

## Managing Capability Changes and Re-pairing

The OpenClaw gateway snapshots your node's command list at the moment a pairing request is approved. If you modify your Node.js client to add or remove commands from the `commands` array, you must force a new pairing process. According to [`docs/gateway-node-integration.md`](https://github.com/openclaw/openclaw-windows-node/blob/main/docs/gateway-node-integration.md), this requires rejecting the old device authorization in the gateway admin interface and approving a fresh connection. The C# Windows node follows this same behavior when its capabilities are updated, ensuring the gateway always maintains an accurate security boundary.

## Key Source Files Reference

When debugging your integration, reference these specific files in the `openclaw/openclaw-windows-node` repository:

- **[`src/OpenClaw.Shared/WindowsNodeClient.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/src/OpenClaw.Shared/WindowsNodeClient.cs)** – Contains `BuildNodeConnectMessage()`, `BuildConnectAuth()`, and `StoreDeviceTokenForRole()` implementations for handshake and authentication logic.
- **[`src/OpenClaw.Shared/WebSocketClientBase.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/src/OpenClaw.Shared/WebSocketClientBase.cs)** – Defines the base WebSocket wrapper with reconnection logic used by all clients.
- **[`src/OpenClaw.Shared/DeviceIdentity.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/src/OpenClaw.Shared/DeviceIdentity.cs)** – Implements Ed25519 signing for bootstrap token flows and device identity management.
- **[`docs/gateway-node-integration.md`](https://github.com/openclaw/openclaw-windows-node/blob/main/docs/gateway-node-integration.md)** – Documents the command allowlist system and platform-specific policies.
- **[`docs/CONNECTION_ARCHITECTURE.md`](https://github.com/openclaw/openclaw-windows-node/blob/main/docs/CONNECTION_ARCHITECTURE.md)** – Provides high-level diagrams of how nodes, operators, and gateways interact.

## Summary

- **Integrate openclaw-windows-node with Node.js** by replicating the WebSocket JSON protocol used by the C# implementation.

- **Authenticate** using gateway tokens for simple setups, or implement Ed25519 signing in [`DeviceIdentity.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/DeviceIdentity.cs) style for bootstrap token flows.
- **Declare capabilities** in the `connect` payload with `platform: "windows"` and a `commands` array matching the gateway allowlist.
- **Handle invocations** by listening for `node.invoke.request` events and responding with `node.invoke.result` messages containing the original request ID.
- **Persist device tokens** after the initial `hello-ok` response to enable automatic reconnection without re-pairing.
- **Re-pair when updating** your command list, as the gateway caches capabilities at approval time.

## Frequently Asked Questions

### Can I use Socket.io instead of the native WebSocket library?

While Socket.io provides convenience features, the OpenClaw gateway expects raw WebSocket messages with a specific JSON schema. If you use Socket.io, you must disable its default event multiplexing and message protocol, ensuring the underlying transport sends plain JSON strings matching the `type`, `id`, `method`, and `params` structure defined in [`WindowsNodeClient.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/WindowsNodeClient.cs). The standard `ws` library is recommended for protocol accuracy.

### Do I need to implement Ed25519 signing for my Node.js client?

Ed25519 signing is only required if you are using **bootstrap tokens** (the QR-code pairing flow) as defined in `BuildConnectAuth()`. If you configure your gateway with a pre-shared **gateway token** and pass it in the `auth.token` field, you can skip cryptographic signing entirely. The C# client stores persistent credentials via `StoreDeviceTokenForRole()` after the first successful bootstrap, which your Node.js client can similarly persist to a local JSON file.

### Why must I use `platform: "windows"` in a Node.js application?

The gateway's command allowlist system validates requests against platform-specific policies. By declaring `platform: "windows"` and `deviceFamily: "Windows"` in your `connect` payload, you signal compatibility with the Windows node policy, which determines which commands (like `screen.snapshot` vs. `camera.snap`) are permitted. This metadata is evaluated alongside your `commands` array in the gateway's security layer.

### How do I handle connection drops or automatic reconnects?

Mirror the pattern in [`WebSocketClientBase.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/WebSocketClientBase.cs) by implementing exponential backoff reconnection logic. When reconnecting, reuse the persisted **device token** from your last successful `hello-ok` response instead of requesting a new pairing. If the gateway rejects the token (expired or revoked), fall back to your gateway token or bootstrap token flow to establish a fresh authenticated session.