← Back to Skills Marketplace
swaylq

Browser Playwright Bridge

by Sway Liu · GitHub ↗ · v1.1.0
cross-platform ⚠ suspicious
590
Downloads
0
Stars
2
Active Installs
2
Versions
Install in OpenClaw
/install browser-playwright-bridge
Description
Run Playwright scripts that reuse OpenClaw browser's login state via CDP with automatic lock-based conflict prevention.
README (SKILL.md)

Browser ↔ Playwright Bridge

OpenClaw's browser tool and external Playwright scripts cannot share the same CDP connection simultaneously. This skill provides a lock-based bridge: stop OpenClaw browser → run Playwright with the same Chrome profile (cookies/login intact) → release for OpenClaw to reconnect.

Architecture

Chrome (CDP port)  ←  shared user-data-dir (~/.openclaw/browser/openclaw/user-data)
       ↕ mutually exclusive
┌──────────────┐    ┌──────────────────┐
│ OpenClaw     │ OR │ Playwright script │
│ browser tool │    │ (zero token cost) │
└──────────────┘    └──────────────────┘
       ↕ managed by browser-lock.sh

Setup

  1. Install Playwright in the workspace (once):
cd \x3Cworkspace> && npm install playwright

Note: npx playwright install is NOT needed. Playwright connects to the existing Chrome via CDP — no local browser download required.

  1. Copy scripts/browser-lock.sh to your workspace scripts/ directory:
chmod +x scripts/browser-lock.sh

Discovering the CDP Port

The CDP port is dynamically assigned. Never hardcode it. Use discoverCdpUrl() (see below) or the shell equivalent in browser-lock.sh.

Shell one-liner:

ps aux | grep 'remote-debugging-port=' | grep -v grep | grep -o 'remote-debugging-port=[0-9]*' | head -1 | cut -d= -f2

Verify CDP is responding:

curl -s --max-time 1 http://127.0.0.1:\x3Cport>/json/version

Usage

Run a Playwright script (recommended)

./scripts/browser-lock.sh run scripts/my-task.js [args...]
./scripts/browser-lock.sh run --timeout 120 scripts/my-task.js  # custom timeout

Default timeout: 300s. If the script exceeds it, the watchdog kills it and releases the lock.

This automatically: checks lock → stops OpenClaw browser → starts Chrome with CDP → runs script → cleans up → releases lock.

Manual acquire/release

./scripts/browser-lock.sh acquire    # stop OpenClaw browser, start Chrome
node scripts/my-task.js              # run script(s)
./scripts/browser-lock.sh release    # kill Chrome, release lock

Check status

./scripts/browser-lock.sh status

Writing Playwright Scripts

Use scripts/playwright-template.js as starting point.

CDP Discovery Helper

All scripts should use discoverCdpUrl() instead of hardcoding a port:

const { execSync } = require('child_process');

/**
 * Discover the CDP URL by inspecting Chrome process args.
 * Falls back to CDP_PORT env var, then probes common ports.
 */
function discoverCdpUrl() {
  // Method 1: extract from running Chrome process
  try {
    const ps = execSync(
      "ps aux | grep 'remote-debugging-port=' | grep -v grep",
      { encoding: 'utf8', timeout: 3000 }
    );
    const match = ps.match(/remote-debugging-port=(\d+)/);
    if (match) return `http://127.0.0.1:${match[1]}`;
  } catch {}

  // Method 2: CDP_PORT env var
  if (process.env.CDP_PORT) {
    return `http://127.0.0.1:${process.env.CDP_PORT}`;
  }

  // Method 3: probe common ports
  // 18800 is the typical OpenClaw default; others are common CDP conventions
  const { execSync: probe } = require('child_process');
  for (const port of [18800, 9222, 9229]) {
    try {
      probe(`curl -s --max-time 1 http://127.0.0.1:${port}/json/version`, {
        encoding: 'utf8', timeout: 2000
      });
      return `http://127.0.0.1:${port}`;
    } catch {}
  }

  throw new Error('CDP port not found. Is Chrome running with --remote-debugging-port?');
}

Script Pattern

const { chromium } = require('playwright');

async function main() {
  let browser;
  try {
    browser = await chromium.connectOverCDP(discoverCdpUrl());
  } catch (e) {
    console.error('❌ Cannot connect to Chrome CDP:', e.message);
    console.error('   Ensure browser-lock.sh acquire was called, or Chrome is running with --remote-debugging-port');
    process.exit(1);
  }

  const context = browser.contexts()[0]; // reuse existing context (cookies!)
  const page = await context.newPage();

  try {
    // ====== Your automation here ======
    await page.goto('https://example.com');
    console.log('Title:', await page.title());
    // ==================================
  } catch (e) {
    console.error('❌ Script error:', e.message);
    throw e;
  } finally {
    await page.close();     // close only your tab
    // NEVER call browser.close() — it kills the entire Chrome
  }
}

main().then(() => process.exit(0)).catch(e => {
  console.error('❌', e.message);
  process.exit(1);
});

Critical rules:

  • browser.contexts()[0] — reuse the existing context to inherit cookies/login
  • page.close() only — never browser.close()
  • Always process.exit(0) on success — Playwright keeps event loops alive otherwise
  • Wrap connectOverCDP in try-catch — fail fast with a clear message

Workflow: Explore → Record → Replay

  1. Explore — Use OpenClaw browser tool (snapshot/act) to figure out a new workflow
  2. Record — Ask the agent to convert the steps into a Playwright script
  3. Replay — Run via browser-lock.sh run — zero token cost, deterministic

Cron / Scheduled Tasks

In cron tasks, call browser-lock.sh directly:

cd /path/to/workspace && ./scripts/browser-lock.sh run scripts/publish-task.js

The lock file (/tmp/openclaw-browser.lock) prevents concurrent browser access. If a lock is stale (owner process dead), it auto-recovers.

Troubleshooting

Problem Fix
Lock held by PID xxx ./scripts/browser-lock.sh release to force-release
Playwright connectOverCDP timeout Ensure OpenClaw browser is stopped first (acquire does this)
CDP port not found Chrome isn't running; call browser-lock.sh acquire first
openclaw browser stop doesn't kill Chrome Known issue; browser-lock.sh kills the process directly
Script hangs after completion Add process.exit(0) at the end
Login expired Use OpenClaw browser tool to re-login, then run scripts again

Environment Variables

Var Default Description
CDP_PORT auto-discover Override CDP port (skips process detection)
CHROME_BIN auto-detect Path to Chrome/Chromium binary
HEADLESS auto Set true/1 to force headless; false/0 to force headed. Auto-detects on Linux without DISPLAY
Usage Guidance
This skill appears to do what it claims — manage a mutex and let Playwright reuse OpenClaw's Chrome profile — but it performs intrusive local operations. Before installing or using it: (1) review and understand the scripts (browser-lock.sh will kill processes and start Chrome with your OpenClaw profile); (2) do not run untrusted Playwright scripts under this bridge because they will inherit your browser cookies/sessions and can act as you in logged-in sites; (3) consider making a disposable copy of the user-data directory or using a separate profile for automation to limit exposure; (4) test in a non-production environment first to ensure the CDP discovery/kill logic doesn't terminate unrelated Chrome instances on your machine; (5) if you need stricter isolation, prefer running Playwright with a separate profile or a dedicated browser instance rather than reusing OpenClaw's profile.
Capability Analysis
Type: OpenClaw Skill Name: browser-playwright-bridge Version: 1.1.0 The `scripts/browser-lock.sh` script contains critical shell injection vulnerabilities. The `CDP_PORT` environment variable, if controlled by an attacker, can lead to arbitrary command execution when used in `curl` commands (e.g., `curl ... "http://127.0.0.1:$CDP_PORT/json/version"`). Similarly, the `CHROME_BIN` environment variable, if controlled by an attacker, can lead to arbitrary command execution when the script attempts to execute the Chrome binary (e.g., `"$CHROME_BIN" ...`). These environment variables are explicitly documented as configurable in `SKILL.md`, making them direct attack vectors. While these are severe vulnerabilities allowing RCE, there is no clear evidence of intentional malicious behavior (e.g., data exfiltration, persistence, or stealth) within the provided files, aligning with a 'suspicious' classification rather than 'malicious'.
Capability Assessment
Purpose & Capability
Name/description claim: share OpenClaw browser state with Playwright via CDP and avoid conflicts. Files and instructions implement exactly that: lock file management, CDP discovery, stopping/starting Chrome with the OpenClaw user-data-dir, and a Playwright template that connects over CDP. Required resources and declared metadata are proportionate to the stated purpose.
Instruction Scope
SKILL.md and the scripts instruct the agent/user to stop the OpenClaw browser, start a standalone Chrome with the same user-data-dir, run a Playwright script, and release the lock. These actions are consistent with the purpose but are intrusive: they read/write the OpenClaw user-data directory, probe local CDP ports, and kill Chrome processes matching the CDP port. The instructions do not access remote endpoints beyond localhost; they do run local process/port discovery and process termination which is within scope but has safety implications.
Install Mechanism
No install spec; the skill is instruction + two scripts. That is low-risk from an install perspective (nothing is automatically downloaded or written to the system by the registry). Playwright must be installed by the workspace operator (npm install playwright) — no hidden installers or external download URLs in the skill itself.
Credentials
The skill declares no required environment variables and uses optional envs (CDP_PORT, CHROME_BIN, HEADLESS). That matches its behavior: the scripts honor those env vars but do not require unrelated credentials or secrets. No external tokens/keys are requested.
Persistence & Privilege
The skill does not request always:true and does not persist configuration into other skills. However, it writes lock and PID files to /tmp and starts/kills Chrome processes while pointing Chrome at the user's OpenClaw user-data-dir (~/.openclaw/browser/openclaw/user-data). That grants scripts run under this bridge access to any cookies/session state stored in that profile — an intended feature but a meaningful privilege that warrants caution.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install browser-playwright-bridge
  3. After installation, invoke the skill by name or use /browser-playwright-bridge
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.1.0
Lock PID fix, timeout watchdog, headless support, README
v1.0.0
Initial release: lock-based CDP bridge between OpenClaw browser and Playwright scripts
Metadata
Slug browser-playwright-bridge
Version 1.1.0
License
All-time Installs 2
Active Installs 2
Total Versions 2
Frequently Asked Questions

What is Browser Playwright Bridge?

Run Playwright scripts that reuse OpenClaw browser's login state via CDP with automatic lock-based conflict prevention. It is an AI Agent Skill for Claude Code / OpenClaw, with 590 downloads so far.

How do I install Browser Playwright Bridge?

Run "/install browser-playwright-bridge" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Browser Playwright Bridge free?

Yes, Browser Playwright Bridge is completely free (open-source). You can download, install and use it at no cost.

Which platforms does Browser Playwright Bridge support?

Browser Playwright Bridge is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Browser Playwright Bridge?

It is built and maintained by Sway Liu (@swaylq); the current version is v1.1.0.

💬 Comments