Skip to content
Back to skills

Browser Playwright Bridge

ASecurity

"Run Playwright scripts that share OpenClaw browser's login state

  • 16 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added June 7, 2026
toolsjavascriptgojavashellbashnodedebugging

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 4 files and shows the line behind each finding

Scanned June 7, 2026

npx -y skills add modbender/skill-library-mcp --skill browser-playwright-bridge --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Browser Playwright Bridge?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Browser Playwright Bridge
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/modbender-browser-playwright-bridge/badge)](https://www.skillsdirectory.com/skills/modbender-browser-playwright-bridge)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: browser-playwright-bridge
description: "Run Playwright scripts that share OpenClaw browser's login state
  via CDP, with automatic conflict avoidance. Use when: (1) recording browser
  tool operations as reusable Playwright scripts, (2) running headless
  automation that needs existing cookies/sessions, (3) scheduling browser tasks
  in cron without CDP conflicts, (4) converting exploratory browser tool
  workflows into zero-token repeatable scripts."
---


# 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):

```bash
cd <workspace> && npm install playwright
```

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

2. Copy `scripts/browser-lock.sh` to your workspace `scripts/` directory:

```bash
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:

```bash
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:

```bash
curl -s --max-time 1 http://127.0.0.1:<port>/json/version
```

## Usage

### Run a Playwright script (recommended)

```bash
./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

```bash
./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

```bash
./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:

```javascript
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

```javascript
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:

```bash
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 |

Files in this skill

  • README.md2.1 KB
  • SKILL.md7.1 KB
  • scripts/browser-lock.sh8.5 KB
  • scripts/playwright-template.js2.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.