Building a Visual Testing Skill with Browsr Relay
One of the most useful things you can give an AI agent is the ability to see what it just built. With Browsr Relay, you can give Claude Code, Codex, or any other agent a "visual testing skill" — a short document that tells the agent how to navigate to your app, take a screenshot, check for JavaScript errors, and report what it sees. Here's how to build one.
Prerequisites
- Browsr Relay Chrome extension installed
- Your app running locally (or on a preview URL)
- A share URL from Relay (click the extension icon → Share → copy the URL)
The share URL looks like: https://api.browsr.dev/relay/abc123xyz
This URL is your agent's entry point. Everything below flows through it.
Taking a Screenshot
The most basic operation: navigate to a page and capture it.
# Navigate to your app
curl -X POST https://api.browsr.dev/relay/abc123xyz/cdp \
-H "Content-Type: application/json" \
-d '{"method": "Page.navigate", "params": {"url": "http://localhost:3000"}}'
# Wait for load
curl -X POST https://api.browsr.dev/relay/abc123xyz/cdp \
-H "Content-Type: application/json" \
-d '{"method": "Page.captureScreenshot", "params": {"format": "png"}}'
The screenshot response contains a base64-encoded PNG in the data field. Claude can decode and analyze this directly — it will describe layout issues, catch broken images, flag unexpected content.
Checking for JavaScript Errors
Navigation alone isn't enough. A page can load successfully and still be broken. Use Runtime.evaluate to check the console error log:
# Evaluate JavaScript in the page context
curl -X POST https://api.browsr.dev/relay/abc123xyz/cdp \
-H "Content-Type: application/json" \
-d '{
"method": "Runtime.evaluate",
"params": {
"expression": "window.__errors || []",
"returnByValue": true
}
}'
You can also inject an error collector before navigating:
# Inject error collector first
curl -X POST https://api.browsr.dev/relay/abc123xyz/cdp \
-H "Content-Type: application/json" \
-d '{
"method": "Runtime.evaluate",
"params": {
"expression": "window.__errors = []; window.onerror = (msg, src, line) => window.__errors.push({msg, src, line});",
"returnByValue": true
}
}'
Then navigate, interact, and check window.__errors afterwards. Any uncaught exceptions will be captured.
Checking Network Failures
Runtime errors aren't the only thing that can break a page. Failed API calls often appear as blank sections or loading spinners that never resolve. Use Runtime.evaluate to inspect the page for obvious signs, or check the events stream for network failures:
# Listen for events (console logs, network errors)
curl https://api.browsr.dev/relay/abc123xyz/events
The events endpoint streams CDP events as they occur. Network failures, console errors, and page lifecycle events all appear here in real time.
The Full Skill Document
Here's a complete skill document you can drop into Claude Code's skills folder. Claude will read this automatically when the share URL is in context:
# Visual Testing Skill
You have access to a real browser via Browsr Relay at: {RELAY_URL}
## How to test a page
1. Navigate to the target URL:
POST {RELAY_URL}/cdp {"method": "Page.navigate", "params": {"url": "<target>"}}
2. Inject error collector:
POST {RELAY_URL}/cdp {"method": "Runtime.evaluate", "params": {"expression": "window.__errors=[]; window.onerror=(m,s,l)=>window.__errors.push({m,s,l});"}}
3. Take a screenshot:
POST {RELAY_URL}/cdp {"method": "Page.captureScreenshot", "params": {"format": "png"}}
Analyze the returned image for visual issues.
4. Check for errors:
POST {RELAY_URL}/cdp {"method": "Runtime.evaluate", "params": {"expression": "window.__errors", "returnByValue": true}}
Report any entries found.
5. Report: describe what you see, list any errors, suggest fixes.
When you share a Relay URL, the extension can deliver this skill document automatically to agents that support skill injection. You don't need to paste instructions each time.
Practical Usage
Drop this skill into Claude Code and your agent gains the ability to test your app visually without any additional setup. A typical interaction looks like:
"I've updated the dashboard layout. Can you check it at localhost:3000/dashboard and tell me if anything looks off?"
Claude navigates, screenshots, evaluates — and responds with a description of the layout and any errors it found. If you're running the dev server in a shell session alongside the Relay connection, the agent can fix issues it finds and immediately retest.
The key insight is that this isn't a synthetic test environment. The agent is looking at your actual browser, with your actual session. Any bug that's visible to you is visible to the agent.