Back to Skills
    🦞

    stealthy-auto-browse

    Control a stealthy browser that evades bot detection

    By @psyb0t
    View on GitHub
    SKILL.md
    ---
    name: stealthy-auto-browse
    description: Control a stealthy browser that evades bot detection using OS-level input
    homepage: https://github.com/psyb0t/docker-stealthy-auto-browse
    user-invocable: true
    metadata:
      {
        "openclaw":
          {
            "emoji": "🕵️",
            "primaryEnv": "STEALTHY_AUTO_BROWSE_URL",
            "always": true,
          },
      }
    ---
    
    # stealthy-auto-browse
    
    ## Setup Required
    
    This skill requires a running stealthy-auto-browse container. Set the `STEALTHY_AUTO_BROWSE_URL` environment variable to connect.
    
    **1. Run the container:**
    
    ```bash
    docker run -d -p 8080:8080 -p 5900:5900 psyb0t/stealthy-auto-browse
    ```
    
    **2. Configure OpenClaw** (`~/.openclaw/openclaw.json`):
    
    ```json
    {
      "skills": {
        "entries": {
          "stealthy-auto-browse": {
            "env": {
              "STEALTHY_AUTO_BROWSE_URL": "http://localhost:8080"
            }
          }
        }
      }
    }
    ```
    
    Or set the environment variable directly:
    
    ```bash
    export STEALTHY_AUTO_BROWSE_URL=http://localhost:8080
    ```
    
    **3. Verify:** Visit http://localhost:5900 to see the browser via VNC.
    
    ---
    
    Control a headless browser that evades bot detection. Uses Camoufox (custom Firefox) with OS-level mouse/keyboard input via PyAutoGUI - completely undetectable by behavioral analysis.
    
    ## Key Concepts
    
    **Why this exists:** Standard browser automation (Selenium, Playwright, Puppeteer) is detectable via CDP (Chrome DevTools Protocol) fingerprinting and synthetic event detection. This browser:
    
    - Uses Firefox (no CDP exposure)
    - Generates consistent fingerprints via browserforge
    - Executes mouse/keyboard at OS level, not via JavaScript injection
    
    **Two input modes:**
    
    1. **Playwright methods** (`click`, `fill`, `type`) - Uses CSS selectors, faster but detectable
    2. **System methods** (`system_click`, `system_type`, `mouse_move`) - OS-level input, undetectable but needs coordinates
    
    **Workflow for undetectable interaction:**
    
    1. Navigate to page with `goto`
    2. Get elements with `get_interactive_elements`
    3. Find target element's `x`, `y` coordinates
    4. Click using `system_click` with those coordinates
    5. Type using `system_type`
    
    ## Environment
    
    Set `STEALTHY_AUTO_BROWSE_URL` to the browser API endpoint (e.g., `http://localhost:8080`).
    
    ## API Reference
    
    All commands are POST requests to `$STEALTHY_AUTO_BROWSE_URL/` with JSON body `{"action": "<name>", ...params}`.
    
    ### Navigation
    
    **goto** - Navigate to URL
    
    ```json
    {
      "action": "goto",
      "url": "https://example.com",
      "wait_until": "domcontentloaded"
    }
    ```
    
    `wait_until`: `domcontentloaded` (default), `load`, `networkidle`
    
    ### Undetectable Input (Use These!)
    
    **system_click** - Move mouse and click at coordinates (UNDETECTABLE)
    
    ```json
    { "action": "system_click", "x": 500, "y": 300, "duration": 0.3 }
    ```
    
    `duration`: Optional mouse movement duration in seconds
    
    **mouse_move** - Move mouse to coordinates without clicking
    
    ```json
    { "action": "mouse_move", "x": 500, "y": 300, "duration": 0.5 }
    ```
    
    **mouse_click** - Click at current position or specific coordinates
    
    ```json
    {"action": "mouse_click"}
    {"action": "mouse_click", "x": 500, "y": 300}
    ```
    
    **system_type** - Type text using OS keyboard (UNDETECTABLE)
    
    ```json
    { "action": "system_type", "text": "hello world", "interval": 0.08 }
    ```
    
    `interval`: Delay between keystrokes in seconds (default: 0.08)
    
    **send_key** - Send special key (enter, tab, escape, etc.)
    
    ```json
    {"action": "send_key", "key": "enter"}
    {"action": "send_key", "key": "tab"}
    {"action": "send_key", "key": "escape"}
    ```
    
    **scroll** - Scroll page
    
    ```json
    {"action": "scroll", "amount": -3}
    {"action": "scroll", "amount": 5, "x": 500, "y": 300}
    ```
    
    `amount`: Negative = scroll down, positive = scroll up
    
    ### Playwright Input (Detectable - Use Only When Necessary)
    
    **click** - Click element by CSS selector (detectable)
    
    ```json
    {"action": "click", "selector": "#submit-btn"}
    {"action": "click", "selector": "button.login"}
    ```
    
    **fill** - Fill input field (clears first)
    
    ```json
    {
      "action": "fill",
      "selector": "input[name='email']",
      "value": "user@example.com"
    }
    ```
    
    **type** - Type into element character by character
    
    ```json
    { "action": "type", "selector": "#search", "text": "query", "delay": 0.05 }
    ```
    
    ### Page Inspection
    
    **get_interactive_elements** - Get all clickable elements with coordinates (ESSENTIAL!)
    
    ```json
    { "action": "get_interactive_elements", "visible_only": true }
    ```
    
    Returns array of elements:
    
    ```json
    {
      "elements": [
        {
          "i": 0,
          "tag": "button",
          "text": "Sign In",
          "selector": "#login-btn",
          "x": 500,
          "y": 300,
          "w": 100,
          "h": 40,
          "visible": true
        }
      ]
    }
    ```
    
    Use `x` and `y` coordinates with `system_click` for undetectable clicks!
    
    **get_text** - Get page text content
    
    ```json
    { "action": "get_text" }
    ```
    
    **get_html** - Get full page HTML
    
    ```json
    { "action": "get_html" }
    ```
    
    **eval** - Execute JavaScript in page context
    
    ```json
    {"action": "eval", "expression": "document.title"}
    {"action": "eval", "expression": "window.scrollY"}
    ```
    
    ### Screenshots
    
    **GET /screenshot/browser** - Browser viewport PNG
    **GET /screenshot/desktop** - Full desktop PNG
    
    Use curl or fetch:
    
    ```bash
    curl $STEALTHY_AUTO_BROWSE_URL/screenshot/browser -o screenshot.png
    ```
    
    ### State & Utility
    
    **GET /state** - Current browser state (url, title, window_offset)
    
    **GET /health** - Health check (returns "ok")
    
    **ping** - Check connection, returns current URL
    
    ```json
    { "action": "ping" }
    ```
    
    **close** - Shut down the browser and server
    
    ```json
    { "action": "close" }
    ```
    
    **calibrate** - Recalculate window offset for coordinate translation
    
    ```json
    { "action": "calibrate" }
    ```
    
    ### Resolution
    
    **get_resolution** - Get current resolution
    
    ```json
    { "action": "get_resolution" }
    ```
    
    ### Fullscreen
    
    **enter_fullscreen** / **exit_fullscreen**
    
    ```json
    {"action": "enter_fullscreen"}
    {"action": "exit_fullscreen"}
    ```
    
    ## Complete Workflow Example
    
    Here's how to login to a site undetectably:
    
    ```bash
    # 1. Navigate to login page
    curl -X POST $STEALTHY_AUTO_BROWSE_URL -H "Content-Type: application/json" \
      -d '{"action": "goto", "url": "https://example.com/login"}'
    
    # 2. Get all interactive elements
    curl -X POST $STEALTHY_AUTO_BROWSE_URL -H "Content-Type: application/json" \
      -d '{"action": "get_interactive_elements"}'
    # Response shows email input at x:400, y:200 and password at x:400, y:260
    
    # 3. Click email field (undetectable)
    curl -X POST $STEALTHY_AUTO_BROWSE_URL -H "Content-Type: application/json" \
      -d '{"action": "system_click", "x": 400, "y": 200}'
    
    # 4. Type email (undetectable)
    curl -X POST $STEALTHY_AUTO_BROWSE_URL -H "Content-Type: application/json" \
      -d '{"action": "system_type", "text": "user@example.com"}'
    
    # 5. Click password field
    curl -X POST $STEALTHY_AUTO_BROWSE_URL -H "Content-Type: application/json" \
      -d '{"action": "system_click", "x": 400, "y": 260}'
    
    # 6. Type password
    curl -X POST $STEALTHY_AUTO_BROWSE_URL -H "Content-Type: application/json" \
      -d '{"action": "system_type", "text": "secretpassword"}'
    
    # 7. Find and click submit button (from get_interactive_elements, e.g., x:400, y:320)
    curl -X POST $STEALTHY_AUTO_BROWSE_URL -H "Content-Type: application/json" \
      -d '{"action": "system_click", "x": 400, "y": 320}'
    ```
    
    ## Response Format
    
    All POST responses follow this format:
    
    ```json
    {
      "success": true,
      "timestamp": 1234567890.123,
      "data": { ... },
      "error": "message if failed"
    }
    ```
    
    ## Tips
    
    1. **Always use `get_interactive_elements` first** to find coordinates for clicking
    2. **Prefer `system_click` and `system_type`** over Playwright methods for stealth
    3. **Add small delays** between actions to appear more human-like
    4. **Use `calibrate`** if clicks seem offset after page changes
    5. **Check screenshots** to debug what the browser sees
    6. **Match timezone** - The container's TZ must match the IP's location for fingerprint consistency
    
    ## VNC Access
    
    Connect to port 5900 via noVNC web viewer to see the browser in action.