Connect OpenClaw Nodes: Setup Guide for Remote Devices
Pairing + status
Section titled “Pairing + status”WS nodes use device pairing to stay secure. When a node connects, it presents a device identity, and the Gateway creates a pairing request with the role: node. You can approve these requests using the devices CLI or the UI.
Quick CLI commands to manage this:
openclaw devices listopenclaw devices approve <requestId>openclaw devices reject <requestId>openclaw nodes statusopenclaw nodes describe --node <idOrNameOrIp>If a node tries to reconnect with different auth details—like a new role, different scopes, or a changed public key—the old pending request is replaced by a new requestId. You should run openclaw devices list again before you approve the connection.
A few things to keep in mind:
- The
nodes statuscommand only shows a node as paired if its device pairing role specifically includesnode. - The
node.pair.*commands (likeopenclaw nodes pending/approve/reject) manage a separate gateway-owned node pairing store. This store does not block the initial WebSocketconnecthandshake.
Remote node host (system.run)
Section titled “Remote node host (system.run)”You should use a node host when your Gateway is running on one machine but you want your commands to execute on a different one. In this setup, the model still communicates with the gateway, and the gateway forwards exec calls to the node host whenever you select host=node.
What runs where
Section titled “What runs where”The work is split between the machines to keep things organized:
- Gateway host: This machine receives messages, runs the model, and routes tool calls to the right place.
- Node host: This machine handles the actual execution of
system.runorsystem.which. - Approvals: Security is handled on the node host via the
~/.openclaw/exec-approvals.jsonfile. - Context: Approval-backed node runs are tied to the exact request context to prevent unauthorized changes.
Regarding execution safety: for direct shell or runtime file executions, OpenClaw tries to bind to one specific local file. If that file changes before execution, the run is denied. If OpenClaw cannot identify exactly one concrete local file for a command, it will deny the execution instead of guessing. In those cases, you should use sandboxing, separate hosts, or a trusted allowlist.
Start a node host (foreground)
Section titled “Start a node host (foreground)”Run this on the machine you want to use as a node:
openclaw node run --host <gateway-host> --port 18789 --display-name "Build Node"Remote gateway via SSH tunnel (loopback bind)
Section titled “Remote gateway via SSH tunnel (loopback bind)”If your Gateway is set to bind to loopback (gateway.bind=loopback), which is the default in local mode, remote node hosts won’t be able to connect directly. You can get around this by creating an SSH tunnel and pointing the node host at the local end of that tunnel.
Example (node host -> gateway host):
# Terminal A (keep running): forward local 18790 -> gateway 127.0.0.1:18789ssh -N -L 18790:127.0.0.1:18789 user@gateway-host
# Terminal B: export the gateway token and connect through the tunnelexport OPENCLAW_GATEWAY_TOKEN="<gateway-token>"openclaw node run --host 127.0.0.1 --port 18790 --display-name "Build Node"Auth details to remember:
openclaw node runworks with either a token or a password.- Using environment variables like
OPENCLAW_GATEWAY_TOKENorOPENCLAW_GATEWAY_PASSWORDis the recommended approach. - The system falls back to
gateway.auth.tokenorgateway.auth.passwordin your config. - In local mode, the node host ignores
gateway.remote.tokenandgateway.remote.password. - In remote mode, those remote tokens are used according to standard precedence rules.
- If local
gateway.auth.*SecretRefs are set but can’t be resolved, the auth will fail for safety. - Node-host auth resolution specifically looks for
OPENCLAW_GATEWAY_*env vars.
Start a node host (service)
Section titled “Start a node host (service)”If you want the node host to run in the background as a service, use these commands:
openclaw node install --host <gateway-host> --port 18789 --display-name "Build Node"openclaw node restartPair + name
Section titled “Pair + name”Back on the gateway host, you’ll need to finalize the connection:
openclaw devices listopenclaw devices approve <requestId>openclaw nodes statusIf the node retries with new auth details, just run openclaw devices list again and approve the latest requestId. You can set the name using the --display-name flag when you first run or install the node, or rename it later from the gateway using openclaw nodes rename --node <id|name|ip> --name "Build Node".
Allowlist the commands
Section titled “Allowlist the commands”Exec approvals are specific to each node host. You can add commands to the allowlist directly from the gateway:
openclaw approvals allowlist add --node <id|name|ip> "/usr/bin/uname"openclaw approvals allowlist add --node <id|name|ip> "/usr/bin/sw_vers"These approvals are stored on the node host in the ~/.openclaw/exec-approvals.json file.
Point exec at the node
Section titled “Point exec at the node”To make the node your default for execution, update your gateway config:
openclaw config set tools.exec.host nodeopenclaw config set tools.exec.security allowlistopenclaw config set tools.exec.node "<id-or-name>"You can also do this on a per-session basis by using the command:
/exec host=node security=allowlist node=<id-or-name>Once this is configured, any exec call with host=node will run on that specific node host, provided the command is on the allowlist. You can find more details in the Node host CLI, Exec tool, and Exec approvals documentation.
Invoking commands
Section titled “Invoking commands”If you need to perform raw RPC calls, you can use the low-level invoke command. This is useful for direct interaction with the node’s command surface.
openclaw nodes invoke --node <idOrNameOrIp> --command canvas.eval --params '{"javaScript":"location.href"}'While this raw method works, there are higher-level helpers available for common tasks like sending media attachments to an agent.
Screenshots (canvas snapshots)
Section titled “Screenshots (canvas snapshots)”When a node is displaying the Canvas (WebView), you can use canvas.snapshot to get the current view as a { format, base64 } object. There is a handy CLI helper that handles writing this to a temporary file and printing the MEDIA:<path> for you.
openclaw nodes canvas snapshot --node <idOrNameOrIp> --format pngopenclaw nodes canvas snapshot --node <idOrNameOrIp> --format jpg --max-width 1200 --quality 0.9Canvas controls
Section titled “Canvas controls”You can also control the canvas remotely with these commands:
openclaw nodes canvas present --node <idOrNameOrIp> --target https://example.comopenclaw nodes canvas hide --node <idOrNameOrIp>openclaw nodes canvas navigate https://example.com --node <idOrNameOrIp>openclaw nodes canvas eval --node <idOrNameOrIp> --js "document.title"A few notes on usage:
- The
canvas presentcommand takes URLs or local file paths via--target. You can also use--x,--y,--width, and--heightto position the window. - The
canvas evalcommand accepts JavaScript either through the--jsflag or as a positional argument.
A2UI (Canvas)
Section titled “A2UI (Canvas)”For A2UI interactions, use the following commands to push or reset data:
openclaw nodes canvas a2ui push --node <idOrNameOrIp> --text "Hello"openclaw nodes canvas a2ui push --node <idOrNameOrIp> --jsonl ./payload.jsonlopenclaw nodes canvas a2ui reset --node <idOrNameOrIp>Note that currently only A2UI v0.8 JSONL is supported; v0.9 or createSurface calls will be rejected.
Photos + videos (node camera)
Section titled “Photos + videos (node camera)”If you need to capture media from your nodes, the camera toolset is your best friend. You can quickly list available cameras or snap a photo using these commands:
openclaw nodes camera list --node <idOrNameOrIp>openclaw nodes camera snap --node <idOrNameOrIp> # default: both facings (2 MEDIA lines)openclaw nodes camera snap --node <idOrNameOrIp> --facing frontFor video clips, use the clip command. You can specify the duration and choose whether to include audio:
openclaw nodes camera clip --node <idOrNameOrIp> --duration 10sopenclaw nodes camera clip --node <idOrNameOrIp> --duration 3000 --no-audioThere are a few things to keep in mind for a smooth experience:
- The node must be foregrounded for
canvas.*andcamera.*calls. If it is in the background, you will see aNODE_BACKGROUND_UNAVAILABLEerror. - Clip duration is currently capped at 60 seconds. This prevents base64 payloads from becoming too large to handle.
- Android devices will ask for
CAMERAandRECORD_AUDIOpermissions. If these are denied, the command fails with*_PERMISSION_REQUIRED.
Screen recordings (nodes)
Section titled “Screen recordings (nodes)”When you need to see exactly what is happening on a node’s display, you can use screen.record to generate an mp4 file. Here is how you run it:
openclaw nodes screen record --node <idOrNameOrIp> --duration 10s --fps 10openclaw nodes screen record --node <idOrNameOrIp> --duration 10s --fps 10 --no-audioA few tips for screen recording:
- Availability depends on the specific node platform you are using.
- Recordings are clamped to a maximum of 60 seconds.
- You can use the
--no-audioflag to stop microphone capture. - If the node has multiple displays, use the
--screen <index>flag to pick the right one.
Location (nodes)
Section titled “Location (nodes)”You can retrieve geographic coordinates from nodes using location.get, provided the feature is enabled in the settings.
The CLI helper makes this easy:
openclaw nodes location get --node <idOrNameOrIp>openclaw nodes location get --node <idOrNameOrIp> --accuracy precise --max-age 15000 --location-timeout 10000Keep these details in mind:
- Location services are off by default for privacy.
- “Always” tracking requires specific system permissions, and background fetching works on a best-effort basis.
- The data you get back includes latitude, longitude, accuracy in meters, and a timestamp.
SMS (Android nodes)
Section titled “SMS (Android nodes)”For Android nodes that support telephony, you can send text messages once the user grants the SMS permission.
You can trigger this using a low-level invoke command:
openclaw nodes invoke --node <idOrNameOrIp> --command sms.send --params '{"to":"+15555550123","message":"Hello from OpenClaw"}'Before you try this, remember:
- You must accept the permission prompt on the Android device itself before the node advertises this capability.
- This won’t work on Wi-Fi-only devices. If there is no telephony support,
sms.sendwill not be available.
Android device + personal data commands
Section titled “Android device + personal data commands”Android nodes can show extra command families when you turn on the right capabilities. You can use these families to interact with device data:
device.status,device.info,device.permissions,device.healthnotifications.list,notifications.actionsphotos.latestcontacts.search,contacts.addcalendar.events,calendar.addcallLog.searchsms.searchmotion.activity,motion.pedometer
Here is how you can invoke these commands:
openclaw nodes invoke --node <idOrNameOrIp> --command device.status --params '{}'openclaw nodes invoke --node <idOrNameOrIp> --command notifications.list --params '{}'openclaw nodes invoke --node <idOrNameOrIp> --command photos.latest --params '{"limit":1}'Keep in mind that motion commands are gated by the sensors available on your specific device.
System commands (node host / mac node)
Section titled “System commands (node host / mac node)”The macOS node gives you access to system.run, system.notify, system.execApprovals.get, and system.execApprovals.set. If you are using the headless node host, you get system.run, system.which, system.execApprovals.get, and system.execApprovals.set.
You can try these examples:
openclaw nodes notify --node <idOrNameOrIp> --title "Ping" --body "Gateway ready"openclaw nodes invoke --node <idOrNameOrIp> --command system.which --params '{"name":"git"}'Here are the details on how these system commands behave:
- When you use
system.run, the payload includes the stdout, stderr, exit code, and execution metadata. - Shell execution now moves through the
exectool withhost=node. Thenodescommand stays as the direct-RPC surface for explicit node commands. - You won’t find
system.runorsystem.run.prepareinnodes invoke; those are only available on the exec path. system.notifyfollows the notification permission state set in the macOS app.- If a node has unknown
platformordeviceFamilymetadata, it uses a safe default allowlist that excludessystem.runandsystem.which. If you need these for an unknown platform, add them yourself usinggateway.nodes.allowCommands. system.runsupports several flags:--cwd,--env KEY=VAL,--command-timeout, and--needs-screen-recording.- For shell wrappers like
bash,sh, orzsh, any request-scoped--envvalues are limited to a specific allowlist:TERM,LANG,LC_*,COLORTERM,NO_COLOR, andFORCE_COLOR. - For allow-always decisions in allowlist mode, dispatch wrappers such as
env,nice,nohup,stdbuf, ortimeoutkeep the inner executable paths. If unwrapping isn’t safe, no allowlist entry is saved automatically. - On Windows node hosts in allowlist mode, running shell wrappers via
cmd.exe /crequires manual approval. An allowlist entry alone won’t auto-allow the wrapper form. system.notifysupports--priority <passive|active|timeSensitive>and--delivery <system|overlay|auto>.- Node hosts ignore
PATHoverrides and strip out risky startup or shell keys likeDYLD_*,LD_*,NODE_OPTIONS,PYTHON*,PERL*,RUBYOPT,SHELLOPTS, andPS4. If you need extraPATHentries, configure the node host service environment or install tools in standard locations. - On macOS node mode,
system.runis gated by the exec approvals in the macOS app (Settings → Exec approvals). - The Ask, allowlist, full, and denied behaviors work the same as the headless node host; denied prompts return
SYSTEM_RUN_DENIED. - On the headless node host,
system.runis gated by exec approvals stored in~/.openclaw/exec-approvals.json.
Exec node binding
Section titled “Exec node binding”When you have multiple nodes running, you can bind exec to one specific node. This sets your default for exec host=node, though you can still override this setting for individual agents if needed.
To set a global default for your setup, run this command:
openclaw config set tools.exec.node "node-id-or-name"If you want a specific agent to use a different node, you can apply an override. First, check your agent list, then target the specific index:
openclaw config get agents.listopenclaw config set agents.list[0].tools.exec.node "node-id-or-name"If you decide to let the system use any available node again, you just need to unset those configuration keys:
openclaw config unset tools.exec.nodeopenclaw config unset agents.list[0].tools.exec.nodePermissions map
Section titled “Permissions map”Nodes can include a permissions map that you will see when using node.list or node.describe. This map is keyed by the specific permission name—for example, screenRecording or accessibility. A true value means the permission has been granted for that node.
Headless node host (cross-platform)
Section titled “Headless node host (cross-platform)”If you don’t need a UI, you can run a headless node host. This version connects to the Gateway WebSocket and lets you use system.run and system.which. It is a great choice for Linux or Windows setups, or if you want to run a minimal node right next to your server.
To get it started, run this command:
openclaw node run --host <gateway-host> --port 18789Keep these points in mind:
- You still need to pair the device. The Gateway will show a pairing prompt when you try to connect.
- The node host saves your node id, token, display name, and gateway connection info in
~/.openclaw/node.json. - Local exec approvals are enforced through
~/.openclaw/exec-approvals.json(you can read more in the Exec approvals documentation). - On macOS, the headless node host runs
system.runlocally by default. You can setOPENCLAW_NODE_EXEC_HOST=appto route those commands through the companion app host. If you want the process to fail when the app host is missing, addOPENCLAW_NODE_EXEC_FALLBACK=0. - If your Gateway WebSocket uses TLS, make sure to add the
--tlsor--tls-fingerprintflags.
Mac node mode
Section titled “Mac node mode”- The macOS menubar app connects to the Gateway WS server as a node. This allows you to run
openclaw nodes …against your Mac. - When you use remote mode, the app opens an SSH tunnel for the Gateway port and connects through
localhost.
OpenClaw Expert
Still stuck?
If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.