What the Hook Does
Claude Code's built-in WebFetch pulls a page over plain HTTP, converts it to markdown, and summarizes it with a small model. That works for server-rendered pages. Pages built as client-rendered apps — Swagger UI and ReDoc are everyday examples — return an app shell over plain HTTP, so the agent gets a page title and nothing else.
The bopen-tools plugin ships a PreToolUse hook that intercepts WebFetch and services it with [agent-browser](https://github.com/vercel-labs/agent-browser), a headless Chrome CLI built for AI agents. The hook opens the URL in an isolated browser session, waits for JavaScript to render, extracts the visible text, and delivers it to the model in the same turn. The transcript shows a single line:
WebFetch handled by agent-browser (faster, JS-rendered) — 4,750 bytes of page content delivered in context; no retry needed.
The agent reads the full rendered content immediately and moves on. WebFetch itself never runs, so there is exactly one fetch per request.
Benchmarks
Measured July 2026 with agent-browser 0.29.1, one cold isolated browser session per fetch. "Plain HTTP text" is what any non-browser fetcher can extract from the raw response.
| Page | Plain HTTP text | agent-browser text | Time |
|------|----------------|--------------------|------|
| petstore.swagger.io | 10 B — literally "Swagger UI" | 1,548 B of rendered API docs | 1.4s |
| redocly.github.io/redoc | 22 B — "Redoc Interactive Demo" | 15,968 B of API reference | 1.6s |
| yours-wallet.gitbook.io | 4,795 B | 4,750 B | 2.3s |
| linear.app | 9,796 B | 7,920 B | 1.4s |
| vercel.com/blog | 3,880 B | 1,904 B | 1.3s |
Two results stand out. On client-rendered pages the difference is existence: plain HTTP receives a 10-byte shell where the browser receives the complete documentation, which is the difference between an agent that answers from the actual API reference and one that guesses. On server-rendered pages the two methods see the same content, and the browser's text extraction comes out 20–50% leaner than tag-stripped HTML.
The raw-HTML comparison is the other headline. These same pages weigh 372 KB to 2.4 MB as raw HTML — 90,000 to 600,000 tokens if an agent ever pastes one into context. Extracted text for every page in the table fits in 500 to 4,000 tokens, a reduction of two to three orders of magnitude.
Beyond Fetching
The same CLI gives the agent an interaction surface. agent-browser snapshot -i returns an accessibility tree with stable element refs — the petstore page compresses to a 6 KB interactive map — and the agent can click, fill forms, log in, and screenshot from ordinary Bash calls. A fetch that turns into "now click the next page" continues in the same tool instead of dead-ending.
Safety Design
Fetched web content is attacker-controlled input, so the hook treats delivery carefully:
- Content arrives wrapped in explicit untrusted-data markers, and the fetched text is sanitized so it cannot forge those markers or a system-reminder tag to break out of the quoted block
- Only extracted text is delivered — never raw HTML — capped at 30 KB
- Fetches run in an isolated browser session, so a browser the agent is actively driving is never disturbed
- Below 200 bytes of extracted content (bot walls, edge errors), the hook steps aside and native WebFetch runs with its own network fingerprint
- If agent-browser is missing or the fetch fails, WebFetch proceeds untouched — a degraded hook never costs the agent a turn
Known limit: heavily bot-walled properties like X and Reddit block headless browsers and plain HTTP alike. For those, agent-browser's interactive login flows via Bash are the path, and the hook stays out of the way.
Install
bash/plugin marketplace add b-open-io/prompts /plugin install bopen-tools@b-open-io npm install -g agent-browser && agent-browser install
The hook activates on the next session start. Run a WebFetch on a Swagger or ReDoc page and compare what comes back — the benchmark table above reproduces with any client-rendered docs site you use daily.