| name | web-access-claude-skill |
| description | Give Claude Code full internet access with three-layer channel dispatch, CDP browser automation, and parallel sub-agent task splitting |
| triggers | ["give claude code internet access","install web access skill for claude","browse the web with claude code","automate chrome browser with claude","parallel web research with claude agents","fetch and scrape web pages in claude code","use CDP browser automation in claude","help me search and browse websites with claude"] |
Web Access Skill for Claude Code
Skill by ara.so — Daily 2026 Skills collection.
A skill that gives Claude Code complete internet access using three-layer channel dispatch (WebSearch / WebFetch / CDP), Chrome DevTools Protocol browser automation via a local proxy, parallel sub-agent task splitting, and cross-session site experience accumulation.
What This Project Does
Claude Code ships with WebSearch and WebFetch but lacks:
- Dispatch strategy — knowing when to use which tool
- Browser automation — clicking, scrolling, file upload, dynamic pages
- Accumulated site knowledge — domain-specific patterns reused across sessions
Web Access fills all three gaps with:
| Capability | Detail |
|---|
| Auto tool selection | WebSearch / WebFetch / curl / Jina / CDP chosen per scenario |
| CDP Proxy | Connects directly to your running Chrome, inherits login state |
| Three click modes | /click (JS), /clickAt (real mouse events), /setFiles (upload) |
| Parallel dispatch | Multiple targets → sub-agents share one Proxy, tab-isolated |
| Site experience store | Per-domain URL patterns, quirks, traps — persisted across sessions |
| Media extraction | Pull image/video URLs from DOM, screenshot any video frame |
Installation
Option A — Let Claude install it:
帮我安装这个 skill:https://github.com/eze-is/web-access
or in English:
Install this skill for me: https://github.com/eze-is/web-access
Option B — Manual:
git clone https://github.com/eze-is/web-access ~/.claude/skills/web-access
The skill file is ~/.claude/skills/web-access/SKILL.md. Claude Code loads all SKILL.md files under ~/.claude/skills/ automatically.
Prerequisites
Node.js 22+
node --version
Enable Chrome Remote Debugging
- Open
chrome://inspect/#remote-debugging in your Chrome
- Check Allow remote debugging for this browser instance
- Restart Chrome if prompted
Verify Dependencies
bash ~/.claude/skills/web-access/scripts/check-deps.sh
Expected output:
✅ Node.js 22.x found
✅ Chrome DevTools reachable at localhost:9222
✅ curl available
CDP Proxy — Core Component
The proxy is a lightweight Node.js WebSocket bridge between Claude and your Chrome instance.
Start the Proxy
node ~/.claude/skills/web-access/scripts/cdp-proxy.mjs &
curl -s http://localhost:3456/ping
Full HTTP API Reference
curl -s "http://localhost:3456/new?url=https://example.com"
curl -s "http://localhost:3456/close?target=ABC123"
curl -s -X POST "http://localhost:3456/eval?target=ABC123" \
-d 'document.title'
curl -s -X POST "http://localhost:3456/eval?target=ABC123" \
-d 'document.documentElement.outerHTML'
curl -s -X POST "http://localhost:3456/click?target=ABC123" \
-d 'button.submit'
curl -s -X POST "http://localhost:3456/clickAt?target=ABC123" \
-d '.upload-btn'
curl -s -X POST "http://localhost:3456/setFiles?target=ABC123" \
-H "Content-Type: application/json" \
-d '{"selector":"input[type=file]","files":["/tmp/photo.png"]}'
curl -s "http://localhost:3456/scroll?target=ABC123&direction=bottom"
curl -s "http://localhost:3456/scroll?target=ABC123&direction=top"
curl -s "http://localhost:3456/screenshot?target=ABC123&file=/tmp/shot.png"
curl -s
Three-Layer Channel Dispatch
The skill teaches Claude to pick the right tool automatically:
Task type → Tool choice
─────────────────────────────────────────
General search query → WebSearch
Static page / docs / API → WebFetch or Jina
Login-gated / dynamic page → CDP Proxy
Heavy JS / SPA → CDP Proxy
Video / canvas interaction → CDP Proxy (clickAt)
Bulk text extraction → Jina (token-efficient)
Raw HTTP / custom headers → curl
Jina Usage (Token-Efficient Reads)
curl -s "https://r.jina.ai/https://docs.example.com/api"
Code Examples
Example 1: Open a Page and Extract Data
const tabRes = await fetch('http://localhost:3456/new?url=https://news.ycombinator.com');
const { targetId } = await tabRes.json();
const evalRes = await fetch(`http://localhost:3456/eval?target=${targetId}`, {
method: 'POST',
body: `
Array.from(document.querySelectorAll('.titleline > a'))
.slice(0, 10)
.map(a => ({ title: a.textContent, href: a.href }))
`
});
const { result } = await evalRes.json();
console.log(JSON.parse(result));
await fetch(`http://localhost:3456/close?target=${targetId}`);
Example 2: Login-Gated Page (Uses Existing Chrome Session)
async function scrapeAuthenticatedPage(url) {
const { targetId } = await fetch(`http://localhost:3456/new?url=${url}`)
.then(r => r.json());
await fetch(`http://localhost:3456/eval?target=${targetId}`, {
method: 'POST',
body: `new Promise(r => setTimeout(r, 2000))`
});
const { result } = await fetch(`http://localhost:3456/eval?target=${targetId}`, {
method: 'POST',
body: `document.querySelector('.main-content')?.innerText`
}).then(r => r.json());
await fetch(`http://localhost:3456/close?target=${targetId}`);
return result;
}
Example 3: File Upload Automation
async function uploadFile(pageUrl, filePath) {
const { targetId } = await fetch(`http://localhost:3456/new?url=${pageUrl}`)
.then(r => r.json());
await new Promise(r => setTimeout(r, 1500));
await fetch(`http://localhost:3456/clickAt?target=${targetId}`, {
method: 'POST',
body: '.upload-trigger-button'
});
await new Promise(r => setTimeout(r, 500));
await fetch(`http://localhost:3456/setFiles?target=${targetId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
selector: ,
: [filePath]
})
});
(, {
: ,
:
});
();
();
}
Example 4: Parallel Research with Sub-Agents
const targets = [
'https://product-a.com',
'https://product-b.com',
'https://product-c.com',
'https://product-d.com',
'https://product-e.com'
];
const results = await Promise.all(
targets.map(async (url) => {
const { targetId } = await fetch(`http://localhost:3456/new?url=${url}`)
.then(r => r.json());
await new Promise(r => setTimeout(r, 2000));
const { result } = await fetch(`http://localhost:3456/eval?target=${targetId}`, {
method: 'POST',
body: `({
title: document.title,
description: document.querySelector('meta[name=description]')?.content,
h1: document.querySelector('h1')?.textContent,
pricing: document.querySelector('[class*="pric"]')?.innerText?.slice(0,200)
})`
}).then(r => r.json());
await fetch();
{ url, : .(result) };
})
);
.(results);
Example 5: Video Frame Screenshot
async function screenshotVideoAt(pageUrl, timestampSeconds) {
const { targetId } = await fetch(`http://localhost:3456/new?url=${pageUrl}`)
.then(r => r.json());
await new Promise(r => setTimeout(r, 3000));
await fetch(`http://localhost:3456/eval?target=${targetId}`, {
method: 'POST',
body: `
const v = document.querySelector('video');
v.currentTime = ${timestampSeconds};
v.pause();
`
});
await new Promise(r => setTimeout(r, 500));
await fetch(`http://localhost:3456/screenshot?target=${targetId}&file=/tmp/frame-${timestampSeconds}s.png`);
await fetch(`http://localhost:3456/close?target=${targetId}`);
}
Common Patterns
Pattern: Check Proxy Before CDP Tasks
curl -s http://localhost:3456/ping || \
node ~/.claude/skills/web-access/scripts/cdp-proxy.mjs &
Pattern: Use Jina for Documentation
curl -s "https://r.jina.ai/https://api.anthropic.com/docs"
Pattern: Prefer WebSearch for Discovery, CDP for Execution
1. WebSearch → find the right URLs
2. WebFetch → read static/public content
3. CDP → interact, authenticate, dynamic content
Pattern: Extract All Media URLs
const media = await fetch(`http://localhost:3456/eval?target=${targetId}`, {
method: 'POST',
body: `({
images: Array.from(document.images).map(i => i.src),
videos: Array.from(document.querySelectorAll('video source, video[src]'))
.map(v => v.src || v.getAttribute('src'))
})`
}).then(r => r.json());
Troubleshooting
Proxy won't start
lsof -i :3456
kill $(lsof -ti :3456)
node ~/.claude/skills/web-access/scripts/cdp-proxy.mjs &
Chrome not reachable
curl -s http://localhost:9222/json/version
/clickAt has no effect
- The element may need scrolling into view first:
curl -s -X POST "http://localhost:3456/eval?target=ID" \
-d 'document.querySelector(".btn").scrollIntoView()'
Page content is empty / JS not rendered
curl -s -X POST "http://localhost:3456/eval?target=ID" \
-d 'new Promise(r => setTimeout(r, 3000))'
File upload input not found
Some SPAs render <input type=file> only after the trigger click. Always:
/clickAt the visible upload button first
- Wait 500ms
- Then
/setFiles
Sub-agent tabs interfering
Each sub-agent should store its own targetId and never share it. The Proxy is stateless per-tab.
Proxy Auto-Shutdown
The proxy exits automatically after 20 minutes of no requests. For long-running tasks:
while true; do curl -s http://localhost:3456/ping > /dev/null; sleep 300; done &
Site Experience Store
The skill accumulates domain knowledge in a local JSON store. When Claude visits twitter.com, it reads any saved notes about:
- Known working URL patterns
- Login flow quirks
- Selectors that are stable vs dynamic
- Rate limiting behavior
This persists across Claude sessions. The store lives at:
~/.claude/skills/web-access/data/site-experience.json
You can inspect or edit it manually to add your own domain knowledge.
Project Structure
~/.claude/skills/web-access/
├── SKILL.md ← This skill file (loaded by Claude)
├── scripts/
│ ├── cdp-proxy.mjs ← CDP Proxy server (Node.js 22+)
│ └── check-deps.sh ← Dependency checker
└── data/
└── site-experience.json ← Accumulated domain knowledge
Capability Summary for Task Routing
| User says | Claude should use |
|---|
| "Search for X" | WebSearch |
| "Read this URL" | WebFetch or Jina |
| "Go to my dashboard on X" | CDP (login state) |
| "Click the submit button on X" | CDP /click or /clickAt |
| "Upload this file to X" | CDP /setFiles |
| "Research these 5 products" | Parallel sub-agents via CDP |
| "Extract images from X" | CDP /eval + DOM query |
| "Screenshot X at 1:23 in the video" | CDP /eval seek + /screenshot |