WSL2 Windows Chrome Remote CDP Troubleshooting Guide

Troubleshoot issues when OpenClaw Gateway in WSL2 controls Chrome on Windows via remote CDP. Covers CDP transport, security, and token problems for developers using split-host setups.

Read this when

  • Running OpenClaw Gateway in WSL2 while Chrome lives on Windows
  • Seeing overlapping browser/control-ui errors across WSL2 and Windows
  • Deciding between host-local Chrome MCP and raw remote CDP in split-host setups

In the typical split-host architecture, OpenClaw Gateway operates within WSL2 while Chrome runs on the Windows side, requiring browser control to traverse the WSL2 to Windows boundary. Multiple independent issues can arise simultaneously (refer to issue #39369): CDP transport, Control UI origin security, and token or pairing mechanisms may each fail independently yet produce errors that look alike. Work through the layers listed below in sequence rather than trying to guess which component is broken.

Choose the right browser mode first

Option 1: raw remote CDP from WSL2 to Windows

Configure a remote browser profile that connects from WSL2 to a Windows Chrome CDP endpoint. Use this setup when the Gateway remains inside WSL2, Chrome is on Windows, and browser control must cross the WSL2 to Windows boundary.

Option 2: host-local Chrome MCP

Only use the existing-session driver (user profile) when the Gateway and Chrome reside on the same machine, you want the locally signed-in browser state, cross-host browser transport is unnecessary, and you do not require responsebody, PDF export, download interception, or batch actions (Chrome MCP profiles lack support for these).

For a WSL2 Gateway paired with Windows Chrome, employ raw remote CDP. Chrome MCP is host-local and does not act as a WSL2 to Windows bridge.

Working architecture

  • WSL2 hosts the Gateway on 127.0.0.1:18789
  • Windows opens the Control UI in a standard browser at http://127.0.0.1:18789/
  • Windows Chrome exposes a CDP endpoint on port 9222
  • WSL2 can access that Windows CDP endpoint
  • OpenClaw directs a browser profile to the address reachable from WSL2

Critical rule for the Control UI

When opening the UI from Windows, use Windows localhost unless you have intentionally set up HTTPS:

http://127.0.0.1:18789/

Avoid defaulting to a LAN IP. Plain HTTP over a LAN or tailnet address can cause insecure origin or device auth problems unrelated to CDP. See Control UI.

Validate in layers

Proceed from top to bottom without jumping ahead. Fixing one layer may still leave a different error visible from a layer further down.

Layer 1: verify Chrome is serving CDP on Windows

chrome.exe --remote-debugging-port=9222 --user-data-dir="$env:LOCALAPPDATA\OpenClaw\ChromeCDP"

Chrome 136 and later ignore remote debugging command line switches for the default Chrome data directory. Use a separate, non-default data directory as shown above. Refer to Chrome's remote-debugging security change. This does not make the normal signed-in Chrome profile remotely controllable.

Verify Chrome itself from Windows first:

curl.exe http://127.0.0.1:9222/json/version
curl.exe http://127.0.0.1:9222/json/list

If this fails, diagnose the Windows listeners below. OpenClaw is not yet the issue.

Diagnose IPv4 and IPv6 before changing portproxy

Chromium attempts to bind remote debugging to 127.0.0.1 first, falling 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:

netstat -ano | findstr :9222
netsh interface portproxy show all
curl.exe http://127.0.0.1:9222/json/version
curl.exe http://[::1]:9222/json/version

Use tasklist /fi "PID eq <PID>" for each PID from netstat.

  • If chrome.exe answers on 127.0.0.1, remove any portproxy rule that also listens on 127.0.0.1:9222. Forward only the WSL2-reachable Windows adapter address to 127.0.0.1.

  • If chrome.exe answers only on [::1], point the WSL2-reachable listener at ::1 with v4tov6 instead of forwarding to an unused IPv4 address:

    netsh interface portproxy add v4tov6 listenaddress=WINDOWS_HOST_OR_IP listenport=9222 connectaddress=::1 connectport=9222
    

Bind the listener to the adapter address that WSL2 needs. Do not expose the CDP port on 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 in cdpUrl:

curl http://WINDOWS_HOST_OR_IP:9222/json/version
curl http://WINDOWS_HOST_OR_IP:9222/json/list

Good result:

  • /json/version returns JSON with Browser / Protocol-Version metadata
  • /json/list returns JSON (an empty array is fine if no pages are open)

If this fails, Windows is not yet exposing the port to WSL2, the address is incorrect for the WSL2 side, or firewall, port forwarding, or proxying is missing. Resolve that before touching OpenClaw config.

Layer 3: configure the correct browser profile

Point OpenClaw at the address reachable from WSL2:

{
  browser: {
    enabled: true,
    defaultProfile: "remote",
    profiles: {
      remote: {
        cdpUrl: "http://WINDOWS_HOST_OR_IP:9222",
        attachOnly: true,
        color: "#00AA00",
      },
    },
  },
}

Notes:

  • use the WSL2-reachable address, not one that only works on Windows
  • keep attachOnly: true for externally managed browsers
  • cdpUrl can be http://, https://, ws://, or wss://
  • 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 curl before expecting OpenClaw to succeed

Layer 4: verify the Control UI layer separately

Open http://127.0.0.1:18789/ from Windows, then verify:

  • the page origin matches what gateway.controlUi.allowedOrigins expects
  • token auth or pairing is configured correctly
  • you are not debugging a Control UI auth problem as if it were a browser problem

Helpful page: Control UI.

Layer 5: verify end-to-end browser control

From WSL2:

openclaw browser --browser-profile remote open https://example.com
openclaw browser --browser-profile remote tabs

Good result:

  • the tab launches within Windows Chrome
  • browser tabs returns the target
  • subsequent operations (snapshot, screenshot, navigate) run under that same profile

Common misleading errors

MessageMeaning
control-ui-insecure-authThe issue is with the UI origin or secure context, not with the CDP transport layer
token_missingThe authentication configuration is incorrect
pairing requiredThe device has not been approved
Remote CDP for profile "remote" is not reachableWSL2 cannot connect to the cdpUrl that was set
empty CDP reply / other side closed through a portproxyEither the Windows listener is misconfigured or a self-loop exists; check both loopback address families and netsh interface portproxy show all
Browser attachOnly is enabled and CDP websocket for profile "remote" is not reachableThe HTTP endpoint responded, but opening the DevTools WebSocket failed
stale viewport / dark-mode / locale / offline overrides after a remote sessionExecute openclaw browser --browser-profile remote stop to close the session and clear the cached Playwright/CDP connection without restarting the Gateway or the external browser
timeout during CDP reachabilityTypically still a CDP reachability problem, or the remote endpoint is slow or unreachable
Playwright page enumeration timed out after 3000msThe remote CDP connected, but reading its persistent tab stalled
No Chrome tabs found for profile="user"A local Chrome MCP profile was chosen, but no host-local tabs are present

Fast triage checklist

  1. On Windows: which of 127.0.0.1 or [::1] responds on /json/version, and does that listener belong to chrome.exe?
  2. On WSL2: does curl http://WINDOWS_HOST_OR_IP:9222/json/version succeed?
  3. In the OpenClaw config: does browser.profiles.<name>.cdpUrl use that exact address reachable from WSL2?
  4. In the Control UI: are you opening http://127.0.0.1:18789/ rather than a LAN IP?
  5. Are you attempting to use existing-session across WSL2 and Windows instead of raw remote CDP?

Start by testing the Windows Chrome endpoint locally, then test the same endpoint from WSL2, and only after that debug the OpenClaw config or Control UI authentication.

1,266 words · updated Jul 27, 2026