Choose the right browser mode first
Option 1: raw remote CDP from WSL2 to Windows
Use a remote browser profile pointing from WSL2 to a Windows Chrome CDP endpoint. Choose this when the Gateway stays inside WSL2, Chrome runs on Windows, and browser control needs to cross the WSL2/Windows boundary.Option 2: host-local Chrome MCP
Use theexisting-session driver (user profile) only when the Gateway runs
on the same host as Chrome, you want the local signed-in browser state, you do
not need cross-host browser transport, and you do not need responsebody,
PDF export, download interception, or batch actions (Chrome MCP profiles do
not support these).
For WSL2 Gateway + Windows Chrome, use raw remote CDP. Chrome MCP is
host-local, not a WSL2-to-Windows bridge.
Working architecture
- WSL2 runs the Gateway on
127.0.0.1:18789 - Windows opens the Control UI in a normal browser at
http://127.0.0.1:18789/ - Windows Chrome exposes a CDP endpoint on port
9222 - WSL2 can reach that Windows CDP endpoint
- OpenClaw points a browser profile at the address reachable from WSL2
Critical rule for the Control UI
When the UI is opened from Windows, use Windows localhost unless you have a deliberate HTTPS setup:Validate in layers
Work top to bottom; do not skip ahead. Fixing one layer can still leave a different error visible from a layer further down.Layer 1: verify Chrome is serving CDP on Windows
Diagnose IPv4 and IPv6 before changing portproxy
Chromium tries to bind remote debugging to127.0.0.1 first and falls back to
[::1] only if the IPv4 bind fails. A persistent v4tov4 rule listening on
127.0.0.1:9222 can occupy that endpoint before Chrome starts. Chrome then
falls back to [::1]:9222, while the old rule forwards IPv4 traffic back to
its own listener and returns an empty reply.
Check the actual listeners and proxy rules from Windows instead of inferring
them from the Chrome version:
tasklist /fi "PID eq <PID>" for each PID from netstat.
-
If
chrome.exeanswers on127.0.0.1, remove any portproxy rule that also listens on127.0.0.1:9222. Forward only the WSL2-reachable Windows adapter address to127.0.0.1. -
If
chrome.exeanswers only on[::1], point the WSL2-reachable listener at::1withv4tov6instead of forwarding to an unused IPv4 address:
0.0.0.0, a LAN address, or a tailnet address: CDP grants control of
the browser session.
Layer 2: verify WSL2 can reach that Windows endpoint
From WSL2, test the exact address you plan to use incdpUrl:
/json/versionreturns JSON with Browser / Protocol-Version metadata/json/listreturns JSON (an empty array is fine if no pages are open)
Layer 3: configure the correct browser profile
Point OpenClaw at the address reachable from WSL2:- use the WSL2-reachable address, not whatever only works on Windows
- keep
attachOnly: truefor externally managed browsers cdpUrlcan behttp://,https://,ws://, orwss://- use HTTP(S) when you want OpenClaw to discover
/json/version - use WS(S) only when the browser provider gives you a direct DevTools socket URL
- test the same URL with
curlbefore expecting OpenClaw to succeed
Layer 4: verify the Control UI layer separately
Openhttp://127.0.0.1:18789/ from Windows, then verify:
- the page origin matches what
gateway.controlUi.allowedOriginsexpects - token auth or pairing is configured correctly
- you are not debugging a Control UI auth problem as if it were a browser problem
Layer 5: verify end-to-end browser control
From WSL2:- the tab opens in Windows Chrome
browser tabsreturns the target- later actions (
snapshot,screenshot,navigate) work from the same profile
Common misleading errors
Fast triage checklist
- Windows: which of
127.0.0.1or[::1]answers on/json/version, and does that listener belong tochrome.exe? - WSL2: does
curl http://WINDOWS_HOST_OR_IP:9222/json/versionwork? - OpenClaw config: does
browser.profiles.<name>.cdpUrluse that exact WSL2-reachable address? - Control UI: are you opening
http://127.0.0.1:18789/instead of a LAN IP? - Are you trying to use
existing-sessionacross WSL2 and Windows instead of raw remote CDP?