> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/nullclaw/nullclaw/llms.txt
> Use this file to discover all available pages before exploring further.

# Browser Tools

> Web browsing, content fetching, and URL opening with security controls

# Browser Tools

NullClaw provides two browser tools for web interaction:

* `browser` — Multi-action browser tool (open, read, screenshot)
* `browser_open` — Allowlist-based URL opener

Both tools enforce HTTPS-only URLs and include security controls to prevent injection attacks.

***

## browser

A flexible browser tool supporting multiple actions:

* **open** — Launch URL in system browser
* **read** — Fetch page content via curl
* **screenshot** — Redirects to dedicated screenshot tool
* **click/type/scroll** — Require CDP (not available)

### Parameters

<ParamField path="action" type="string" required>
  Browser action: `open`, `read`, `screenshot`, `click`, `type`, or `scroll`
</ParamField>

<ParamField path="url" type="string">
  URL to open or read (required for `open` and `read` actions)
</ParamField>

<ParamField path="selector" type="string">
  CSS selector for click/type actions (not available)
</ParamField>

<ParamField path="text" type="string">
  Text to type (not available)
</ParamField>

### Configuration

```zig theme={null}
const bt = try allocator.create(browser.BrowserTool);
bt.* = .{};
```

No configuration required — tool is self-contained.

***

### Action: open

Launch a URL in the system's default browser.

**Usage:**

```json theme={null}
{
  "tool": "browser",
  "action": "open",
  "url": "https://docs.nullclaw.ai"
}
```

**Response:**

```
Opened https://docs.nullclaw.ai in system browser
```

**Platform commands:**

| Platform | Command                |
| -------- | ---------------------- |
| macOS    | `open URL`             |
| Linux    | `xdg-open URL`         |
| Windows  | `cmd.exe /c start URL` |

**Security:**

* Only `https://` URLs accepted (no `http://`)
* On Windows: blocks shell metacharacters (`;`, `|`, `&`, `%`, etc.) to prevent command injection
* On Unix: URL passed as separate argv element (safe from injection)

**Example: Blocked URL**

```json theme={null}
{
  "tool": "browser",
  "action": "open",
  "url": "http://example.com"
}
```

**Response:**

```
Only https:// URLs are supported for security
```

***

### Action: read

Fetch page content via curl and return body text (truncated to 8 KB).

**Usage:**

```json theme={null}
{
  "tool": "browser",
  "action": "read",
  "url": "https://api.example.com/status"
}
```

**Response:**

```json theme={null}
{
  "status": "ok",
  "version": "1.0.0",
  "uptime": 86400
}
```

**Implementation:**

```bash theme={null}
curl -sS -L -m 10 --max-filesize 65536 URL
```

**Flags:**

* `-sS` — Silent but show errors
* `-L` — Follow redirects
* `-m 10` — Timeout after 10 seconds
* `--max-filesize 65536` — Abort if body exceeds 64 KB

**Truncation:**

* Fetches up to 64 KB raw
* Returns up to 8 KB to LLM
* Appends `[Content truncated to 8 KB]` if truncated

**Example: Large page**

```json theme={null}
{
  "tool": "browser",
  "action": "read",
  "url": "https://example.com/large-page.html"
}
```

**Response:**

```html theme={null}
<!DOCTYPE html>
<html>
<head><title>Example</title></head>
<body>
...
[8 KB of content]

[Content truncated to 8 KB]
```

**Requirements:**

* `curl` must be installed and in PATH
* Network access required

***

### Action: screenshot

Redirects to the dedicated `screenshot` tool.

**Usage:**

```json theme={null}
{
  "tool": "browser",
  "action": "screenshot"
}
```

**Response:**

```
Use the screenshot tool instead
```

***

### Actions: click, type, scroll

These actions require Chrome DevTools Protocol (CDP), which is not available in NullClaw.

**Usage:**

```json theme={null}
{
  "tool": "browser",
  "action": "click",
  "selector": "#submit-button"
}
```

**Response:**

```
Browser action 'click' requires CDP (Chrome DevTools Protocol) which is not available. Use 'open' to launch in system browser or 'read' to fetch page content.
```

***

## browser\_open

Open an allowlisted HTTPS URL in the default browser.

Unlike the `browser` tool's `open` action, `browser_open` enforces a **domain allowlist** configured at tool initialization.

### Parameters

<ParamField path="url" type="string" required>
  HTTPS URL to open in browser
</ParamField>

### Configuration

```zig theme={null}
const bot = try allocator.create(browser_open.BrowserOpenTool);
bot.* = .{
    .allowed_domains = &.{
        "docs.nullclaw.ai",
        "github.com",
        "api.example.com",
    },
};
```

### Usage

**Allowed domain:**

```json theme={null}
{
  "tool": "browser_open",
  "url": "https://docs.nullclaw.ai/tools"
}
```

**Response:**

```
Opened in browser: https://docs.nullclaw.ai/tools
```

**Subdomain matching:**

```json theme={null}
{
  "tool": "browser_open",
  "url": "https://api.github.com/repos"
}
```

Matches `github.com` in allowlist → **allowed**

**Blocked domain:**

```json theme={null}
{
  "tool": "browser_open",
  "url": "https://evil.com"
}
```

**Response:**

```
Host is not in browser allowed_domains
```

### Domain Allowlist Rules

**Exact match:**

* `example.com` in allowlist
* `https://example.com` → allowed

**Subdomain match:**

* `example.com` in allowlist
* `https://api.example.com` → allowed
* `https://v2.api.example.com` → allowed

**No partial match:**

* `example.com` in allowlist
* `https://notexample.com` → blocked
* `https://example.com.evil.com` → blocked

### Security Blocklist

The following hosts are **always blocked**, even if in the allowlist:

* `localhost`
* `*.localhost`
* `*.local`
* `127.*.*.*`
* `10.*.*.*`
* `192.168.*.*`
* `169.254.*.*` (link-local)
* `::1` (IPv6 localhost)

**Example: Blocked localhost**

```json theme={null}
{
  "tool": "browser_open",
  "url": "https://localhost:8080"
}
```

**Response:**

```
Blocked local/private host
```

### Empty Allowlist

If `allowed_domains` is empty, all URLs are rejected:

```zig theme={null}
bot.* = .{ .allowed_domains = &.{} };
```

```json theme={null}
{
  "tool": "browser_open",
  "url": "https://example.com"
}
```

**Response:**

```
No allowed_domains configured for browser_open
```

### Platform Support

Supported platforms:

* macOS — `open URL`
* Linux — `xdg-open URL`

Unsupported platforms:

* Windows — Returns error (Windows support not implemented for `browser_open`)

***

## Comparison: browser vs browser\_open

| Feature            | browser (open action) | browser\_open              |
| ------------------ | --------------------- | -------------------------- |
| Domain allowlist   | No                    | Yes (required)             |
| Localhost blocking | No                    | Yes (always)               |
| Configuration      | None                  | `allowed_domains` required |
| Platform support   | macOS, Linux, Windows | macOS, Linux only          |
| Use case           | General browsing      | Restricted browsing        |

**When to use `browser`:**

* Interactive agent browsing
* User-requested URLs
* Trusted environment

**When to use `browser_open`:**

* Production deployments
* Multi-tenant agents
* Restricted URL access

***

## URL Security

### HTTPS-Only

Both tools reject `http://` URLs:

```json theme={null}
{
  "tool": "browser",
  "action": "open",
  "url": "http://example.com"
}
```

**Response:**

```
Only https:// URLs are supported for security
```

### Shell Injection Prevention (Windows)

On Windows, the `browser` tool blocks shell metacharacters in URLs:

**Blocked characters:**

* `&` — Command chaining
* `|` — Piping
* `;` — Command separator
* `"` `'` — Quote injection
* `<` `>` — Redirection
* `` ` `` — Backtick execution
* `(` `)` — Subshell
* `^` — Escape character
* `%` — Variable expansion
* `!` — History expansion
* `\n` `\r` — Newlines

**Example: Blocked injection**

```json theme={null}
{
  "tool": "browser",
  "action": "open",
  "url": "https://example.com&whoami"
}
```

**Response (Windows only):**

```
URL contains shell metacharacters — open manually for safety
```

**Safe on Unix:**\
On Unix systems (macOS, Linux), the URL is passed as a separate argv element to `open`/`xdg-open`, so query parameters like `?a=1&b=2` are safe.

***

## Use Cases

### Open Documentation

```json theme={null}
{
  "tool": "browser",
  "action": "open",
  "url": "https://docs.nullclaw.ai/getting-started"
}
```

### Fetch API Status

```json theme={null}
{
  "tool": "browser",
  "action": "read",
  "url": "https://status.example.com/api/health"
}
```

### Restricted GitHub Access

```zig theme={null}
// Config
bot.* = .{ .allowed_domains = &.{ "github.com", "raw.githubusercontent.com" } };
```

```json theme={null}
{
  "tool": "browser_open",
  "url": "https://github.com/nullclaw/nullclaw"
}
```

### Fetch HTML Content

```json theme={null}
{
  "tool": "browser",
  "action": "read",
  "url": "https://example.com/page.html"
}
```

***

## Source

* `browser` — `src/tools/browser.zig:16-150`
* `browser_open` — `src/tools/browser_open.zig:12-89`

## Testing

Run browser tool tests:

```bash theme={null}
zig build test --summary all
```

Tests cover:

* Open action (test mode skips actual spawn)
* Read action (requires curl)
* URL validation (HTTPS-only)
* Domain allowlist matching
* Localhost blocking
* Shell injection prevention (Windows)
* Error cases
