Claude Code Plugins

Community-maintained marketplace

Feedback

Real-time browser debugging and interaction via WebSocket bridge server on localhost:3141

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name BrowserBridge
description Real-time browser debugging and interaction via WebSocket bridge server on localhost:3141

BrowserBridge - Browser Debugging Integration

BrowserBridge enables Claude Code to interact with web browsers in real-time through a C# bridge server and Chrome/Edge extension for debugging, DOM inspection, and JavaScript execution.

Quick Start for Claude

Prerequisites Check:

curl http://localhost:3141/api/browser/health

If successful, you can execute browser commands. If connection refused, bridge server is not running.

Common Commands:

# Execute JavaScript
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.title"}'

# Inspect element
curl -X POST http://localhost:3141/api/browser/inspect -H "Content-Type: application/json" -d '{"selector": "#myElement"}'

# List connections
curl http://localhost:3141/api/browser/connections

Setup Requirements

  1. Bridge Server Running: User must have started the bridge server

    cd bridge-server/ClaudeBrowserBridge
    dotnet run
    
  2. Extension Connected: User must have:

    • Loaded the extension in Chrome/Edge (chrome://extensions/)
    • Clicked "Connect to Claude" in the extension popup
    • Status shows "Connected" (green dot)
  3. Active Webpage: User must be viewing a webpage in the browser

Available API Endpoints

1. Health Check

curl http://localhost:3141/api/browser/health

Response:

{
  "status": "healthy",
  "timestamp": "2025-11-21T10:30:00Z",
  "connections": 1
}

Use this to verify bridge server is running and count connected browsers.

2. List Connections

curl http://localhost:3141/api/browser/connections

Response shows all connected browser tabs with connection IDs and last activity.

3. Execute JavaScript

curl -X POST http://localhost:3141/api/browser/execute \
  -H "Content-Type: application/json" \
  -d '{"script": "YOUR_JAVASCRIPT_HERE"}'

Common Scripts:

Get page title:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.title"}'

Check if element exists:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelector(\"#myId\") !== null"}'

Get element innerHTML:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelector(\"#myId\")?.innerHTML"}'

Get element count:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelectorAll(\".className\").length"}'

Check if function exists:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "typeof window.myFunction"}'

Get computed style:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "window.getComputedStyle(document.querySelector(\"#myId\")).display"}'

Test DOM change live:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelector(\"#test\").style.border = \"2px solid red\""}'

Note: Results are sent via WebSocket. The bridge server writes script results to a file for easy access:

# Read the last script result
cat "C:/RI Services/BrowserBridge/claude_browser_last_result.json"

Example result:

{"type":"script_result","success":true,"result":"2408","timestamp":1764632896201}

For debugging, all messages are logged to:

powershell -Command "Get-Content 'C:\RI Services\BrowserBridge\all_messages.log' -Tail 20"

4. Inspect Element

curl -X POST http://localhost:3141/api/browser/inspect \
  -H "Content-Type: application/json" \
  -d '{"selector": "#myElement"}'

Inspection results appear in bridge server console with:

  • Full HTML (outerHTML and innerHTML)
  • Computed styles (display, position, width, height, colors, fonts)
  • Bounding box (x, y, width, height, position on screen)
  • Element properties (tagName, className, id)

Common Selectors:

  • By ID: #pagination
  • By class: .button-class
  • By attribute: [data-id="123"]
  • Complex: #parent .child:first-of-type

5. Take Screenshot

curl -X POST http://localhost:3141/api/browser/screenshot \
  -H "Content-Type: application/json" \
  -d '{"fullPage": false}'

Screenshot sent as base64 PNG via WebSocket to bridge server logs.

6. Get Connection Details

curl http://localhost:3141/api/browser/connections/{connectionId}

Get detailed info about a specific connection.

7. Get Message History

curl "http://localhost:3141/api/browser/connections/{connectionId}/history?limit=50"

Get recent messages from a connection (console logs, errors, etc).

Automatic Monitoring

The extension automatically captures and sends to bridge server:

  1. Console Logs: All console.log, console.warn, console.error, console.info
  2. JavaScript Errors: Uncaught exceptions with stack traces
  3. Promise Rejections: Unhandled promise rejections
  4. Page Events: Page loads, tab switches, navigation

Check the bridge server console to see these events in real-time.

Usage Patterns

Debugging "Element Not Visible" Issues

  1. Check if element exists:
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelector(\"#myElement\") !== null"}'
  1. If true, inspect it:
curl -X POST http://localhost:3141/api/browser/inspect -H "Content-Type: application/json" -d '{"selector": "#myElement"}'
  1. Check bridge server logs for:
    • Is it hidden? (display: none or visibility: hidden)
    • Is it empty? (no innerHTML)
    • Is it off-screen? (negative position values)

Verifying JavaScript Functions

Check if function exists:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "typeof window.updatePaginationControls"}'

If returns "function", get its source:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "window.updatePaginationControls.toString()"}'

Accessing Module-Scoped Variables

ES6 modules encapsulate their variables, making them inaccessible from the global scope. Instead of repeatedly exposing individual variables, add a generic getValue helper:

Add this pattern to the module:

// Debug helper - access module values by dot-notation path
window.getValue = (path) => {
    const moduleVars = { state, filterOptions, myFunction, loadData }; // Add all you need
    const parts = path.split('.');
    let val = moduleVars[parts[0]];
    for (let i = 1; i < parts.length && val !== undefined; i++) {
        val = val[parts[i]];
    }
    return val;
};

Usage from Browser Bridge:

# Get nested state value
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "getValue(\"state.filters.lang\")"}'

# Get array length
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "getValue(\"filterOptions.refs\")?.length"}'

# Get complex state as JSON
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "JSON.stringify({filters: getValue(\"state.filters\"), count: getValue(\"state.data.totalCount\")})"}'

Alternative: Expose state to window directly:

// At module start
const state = window.__state = { /* ... */ };

Then access via window.__state.filters.lang without needing getValue.

Testing DOM Changes Live

Before suggesting code changes, test them:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelectorAll(\"button\").forEach(b => b.style.border = \"2px solid red\")"}'

User sees changes immediately. If it works, provide the permanent CSS/JS fix.

Checking for Null/Undefined

Always use optional chaining to avoid errors:

# Good
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelector(\"#myId\")?.innerHTML || \"Element not found\""}'

# Bad (will throw if element doesn't exist)
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelector(\"#myId\").innerHTML"}'

Common Bug: Missing Optional Chaining on Method Calls

When calling functions programmatically that normally run from UI events, event may be undefined:

// BAD - throws "Cannot read properties of undefined (reading 'add')"
event?.target?.classList.add('active');  // classList is undefined when event is undefined

// GOOD - chain all the way through
event?.target?.classList?.add('active');

This applies to any pattern where you use ?. but then call a method on the result.

Error Handling

Connection Refused

curl: (7) Failed to connect to localhost port 3141

Cause: Bridge server not running

Tell User:

The bridge server isn't running. Please start it:

cd bridge-server/ClaudeBrowserBridge
dotnet run

No Connections

{"connections": 0}

Cause: Extension not connected

Tell User:

The extension isn't connected. Please:
1. Click the extension icon in your browser
2. Click "Connect to Claude"
3. Verify status shows "Connected" (green dot)

Script Execution Errors

Results appear in bridge server console. Check logs for:

  • Element doesn't exist → Use optional chaining or check existence first
  • Function undefined → Verify script loaded, check console for errors
  • Permission denied → Site has strict CSP, some operations blocked

Best Practices

  1. Always check health first: Verify server is running before attempting commands
  2. Use specific selectors: Prefer IDs over classes, classes over tags
  3. Check for null: Use optional chaining (?.) or null checks
  4. Watch server logs: Execution results appear in bridge server console
  5. Test before fixing: Execute test commands live before suggesting code changes
  6. Escape quotes: Use \" for quotes inside JSON strings

JSON Escaping

When constructing curl commands with nested quotes:

# Escape double quotes inside JSON
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelector(\"#myId\")"}'

# Or use single quotes in JavaScript
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d "{\"script\": \"document.querySelector('#myId')\"}"

Troubleshooting

Extension Not Working

Tell user to:

  1. Refresh the webpage after connecting extension
  2. Check browser console (F12) for "Claude Browser Bridge content script loaded"
  3. Verify window.__claudeBridge exists in console

Server Not Receiving Messages

  1. Verify WebSocket connection in extension popup (should show "Connected")
  2. Check bridge server console for connection messages
  3. Try disconnect/reconnect in extension popup

Results Not Appearing

Results are sent via WebSocket to bridge server console. User must check the terminal running dotnet run to see:

  • Script execution results
  • Inspection data
  • Console logs from browser
  • Error messages

Security Notes

  • Bridge server only accepts localhost connections (127.0.0.1)
  • No authentication (development tool only)
  • Can execute arbitrary JavaScript (by design)
  • Not for production use
  • Some sites with strict CSP may block functionality

Example Workflow

User says: "The pagination controls aren't showing up"

Claude:

  1. Check connection:
curl http://localhost:3141/api/browser/health
  1. Check if element exists:
curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "document.querySelector(\"#pagination\") !== null"}'
  1. If true, inspect it:
curl -X POST http://localhost:3141/api/browser/inspect -H "Content-Type: application/json" -d '{"selector": "#pagination"}'
  1. Check bridge server logs → See it has display: none or empty innerHTML

  2. Find why:

curl -X POST http://localhost:3141/api/browser/execute -H "Content-Type: application/json" -d '{"script": "typeof updatePaginationControls"}'
  1. Diagnose issue and provide fix to user

Quick Reference

Action Endpoint Method
Health check /api/browser/health GET
List connections /api/browser/connections GET
Execute JavaScript /api/browser/execute POST
Inspect element /api/browser/inspect POST
Screenshot /api/browser/screenshot POST
Connection details /api/browser/connections/{id} GET
Message history /api/browser/connections/{id}/history GET

Related Project Files

  • Bridge Server: bridge-server/ClaudeBrowserBridge/
  • Extension: extension/
  • Setup Guide: SETUP.md