How to Integrate openclaw-windows-node with a Node.js Application: WebSocket Protocol Guide
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, 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, 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, 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.
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.
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 (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.
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 (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.
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, 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– ContainsBuildNodeConnectMessage(),BuildConnectAuth(), andStoreDeviceTokenForRole()implementations for handshake and authentication logic.src/OpenClaw.Shared/WebSocketClientBase.cs– Defines the base WebSocket wrapper with reconnection logic used by all clients.src/OpenClaw.Shared/DeviceIdentity.cs– Implements Ed25519 signing for bootstrap token flows and device identity management.docs/gateway-node-integration.md– Documents the command allowlist system and platform-specific policies.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.csstyle for bootstrap token flows. -
Declare capabilities in the
connectpayload withplatform: "windows"and acommandsarray matching the gateway allowlist. -
Handle invocations by listening for
node.invoke.requestevents and responding withnode.invoke.resultmessages containing the original request ID. -
Persist device tokens after the initial
hello-okresponse 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. 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →