HomeBrowseUpload
← Back to registry
// Skill profile

Web Access Skill for Claude Code

name: web-access-claude-skill

by adisinghstudent · published 2026-04-01

开发工具图像生成
Total installs
0
Stars
★ 0
Last updated
2026-04
// Install command
$ claw add gh:adisinghstudent/adisinghstudent-web-access-claude-skill
View on GitHub
// Full documentation

---

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](https://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   # must be >= 22

    Enable Chrome Remote Debugging

    1. Open `chrome://inspect/#remote-debugging` in your Chrome

    2. Check **Allow remote debugging for this browser instance**

    3. 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

    # Start in background (auto-exits after 20 min idle)
    node ~/.claude/skills/web-access/scripts/cdp-proxy.mjs &
    
    # Confirm it's running
    curl -s http://localhost:3456/ping
    # → {"status":"ok"}

    Full HTTP API Reference

    # ── Tab management ──────────────────────────────────────────
    # Open new tab, returns tab ID
    curl -s "http://localhost:3456/new?url=https://example.com"
    # → {"targetId":"ABC123","url":"https://example.com"}
    
    # Close a tab
    curl -s "http://localhost:3456/close?target=ABC123"
    # → {"closed":true}
    
    # ── Page content ────────────────────────────────────────────
    # Execute JavaScript, returns result
    curl -s -X POST "http://localhost:3456/eval?target=ABC123" \
      -d 'document.title'
    # → {"result":"Example Domain"}
    
    # Get full page HTML
    curl -s -X POST "http://localhost:3456/eval?target=ABC123" \
      -d 'document.documentElement.outerHTML'
    
    # ── Interaction ─────────────────────────────────────────────
    # JS click (fast, works for most buttons)
    curl -s -X POST "http://localhost:3456/click?target=ABC123" \
      -d 'button.submit'
    
    # Real mouse click via CDP (use for upload triggers, canvas elements)
    curl -s -X POST "http://localhost:3456/clickAt?target=ABC123" \
      -d '.upload-btn'
    
    # File upload via input element
    curl -s -X POST "http://localhost:3456/setFiles?target=ABC123" \
      -H "Content-Type: application/json" \
      -d '{"selector":"input[type=file]","files":["/tmp/photo.png"]}'
    
    # ── Navigation ──────────────────────────────────────────────
    # Scroll to bottom
    curl -s "http://localhost:3456/scroll?target=ABC123&direction=bottom"
    
    # Scroll to top
    curl -s "http://localhost:3456/scroll?target=ABC123&direction=top"
    
    # ── Visual ──────────────────────────────────────────────────
    # Screenshot to file
    curl -s "http://localhost:3456/screenshot?target=ABC123&file=/tmp/shot.png"
    
    # Screenshot returned as base64
    curl -s "http://localhost:3456/screenshot?target=ABC123"
    # → {"base64":"iVBORw0KGgo..."}

    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)

    # Jina converts any URL to clean markdown — great for docs/articles
    curl -s "https://r.jina.ai/https://docs.example.com/api"

    Code Examples

    Example 1: Open a Page and Extract Data

    // Claude runs this flow via CDP Proxy
    
    // 1. Open tab
    const tabRes = await fetch('http://localhost:3456/new?url=https://news.ycombinator.com');
    const { targetId } = await tabRes.json();
    
    // 2. Wait for load, then extract top story titles
    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));
    
    // 3. Clean up
    await fetch(`http://localhost:3456/close?target=${targetId}`);

    Example 2: Login-Gated Page (Uses Existing Chrome Session)

    // Chrome already has the user logged in — CDP inherits cookies automatically
    
    async function scrapeAuthenticatedPage(url) {
      // Open tab in the user's real Chrome — no login needed
      const { targetId } = await fetch(`http://localhost:3456/new?url=${url}`)
        .then(r => r.json());
    
      // Wait for dynamic content
      await fetch(`http://localhost:3456/eval?target=${targetId}`, {
        method: 'POST',
        body: `new Promise(r => setTimeout(r, 2000))`
      });
    
      // Extract content
      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());
    
      // Wait for page
      await new Promise(r => setTimeout(r, 1500));
    
      // Click the upload trigger button (real mouse event — required for some SPAs)
      await fetch(`http://localhost:3456/clickAt?target=${targetId}`, {
        method: 'POST',
        body: '.upload-trigger-button'
      });
    
      await new Promise(r => setTimeout(r, 500));
    
      // Set file on the (possibly hidden) input
      await fetch(`http://localhost:3456/setFiles?target=${targetId}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          selector: 'input[type=file]',
          files: [filePath]
        })
      });
    
      // Submit
      await fetch(`http://localhost:3456/click?target=${targetId}`, {
        method: 'POST',
        body: 'button[type=submit]'
      });
    
      // Screenshot to verify
      await fetch(`http://localhost:3456/screenshot?target=${targetId}&file=/tmp/upload-result.png`);
    
      await fetch(`http://localhost:3456/close?target=${targetId}`);
    }

    Example 4: Parallel Research with Sub-Agents

    // Instruct Claude to dispatch parallel sub-agents like this:
    
    const targets = [
      'https://product-a.com',
      'https://product-b.com',
      'https://product-c.com',
      'https://product-d.com',
      'https://product-e.com'
    ];
    
    // Each sub-agent opens its own tab (tab-isolated, same Proxy)
    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(`http://localhost:3456/close?target=${targetId}`);
        return { url, data: JSON.parse(result) };
      })
    );
    
    console.table(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));
    
      // Seek video to timestamp
      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));
    
      // Capture the frame
      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

    # Always verify proxy is up before a CDP workflow
    curl -s http://localhost:3456/ping || \
      node ~/.claude/skills/web-access/scripts/cdp-proxy.mjs &

    Pattern: Use Jina for Documentation

    # Cheaper and cleaner than WebFetch for text-heavy pages
    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

    // Get all images and videos on current page
    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

    # Check if port 3456 is already in use
    lsof -i :3456
    
    # Kill existing proxy
    kill $(lsof -ti :3456)
    
    # Restart
    node ~/.claude/skills/web-access/scripts/cdp-proxy.mjs &

    Chrome not reachable

    # Verify Chrome remote debugging is on
    curl -s http://localhost:9222/json/version
    # Should return Chrome version JSON
    
    # If empty — go to chrome://inspect/#remote-debugging and enable it

    `/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()'
  • Then retry `/clickAt`
  • Page content is empty / JS not rendered

    # Add a wait after /new before /eval
    curl -s -X POST "http://localhost:3456/eval?target=ID" \
      -d 'new Promise(r => setTimeout(r, 3000))'
    # Then fetch content

    File upload input not found

    Some SPAs render `<input type=file>` only after the trigger click. Always:

    1. `/clickAt` the visible upload button first

    2. Wait 500ms

    3. 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:

    # Keep-alive ping in background
    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` |

    // Comments
    Sign in with GitHub to leave a comment.
    // Related skills

    More tools from the same signal band