web3-agent-browser
v0.2.3
Published
AI-driven Web3 dApp browser with secure remote signing. Wallet appears as 'Remote Signer' in dApps.
Maintainers
Readme
Web3 Agent Browser
AI-driven Web3 dApp automation with secure remote signing. Wallet appears as "Remote Signer" in dApp wallet lists.
What it does
Gives AI agents (Claude Code) a real Chrome browser with a built-in EIP-1193 wallet. The AI can operate any Web3 dApp — swap tokens, SIWE login, claim airdrops — while private keys stay securely in remote-signer (never in the browser).
Install
From npm (web3-agent-browser):
npm install -g agent-browser
npm install -g web3-agent-browserThe web3-agent-browser CLI is then on your PATH (same commands as below, using web3-agent-browser instead of node bin/web3-agent-browser.mjs).
From this repository (development / pinned version):
npm installQuick Start
# 1. Copy and edit config (from repo clone; skip if you only use global install + ~/.web3-agent-browser/config.yaml)
cp config.example.yaml config.yaml
# Edit: set your signer address, remote-signer URL, certs path
# 2. Start (headed mode — you can watch the browser)
# With global npm install: web3-agent-browser --config config.yaml start "<url>"
DISPLAY=:99 node bin/web3-agent-browser.mjs --config config.yaml \
start "http://account.local.web3gate.xyz/login"
# 3. Interact (in another terminal)
web3-agent-browser snapshot # See the page
web3-agent-browser click @e7 # Click Connect Wallet
web3-agent-browser snapshot # See wallet list
web3-agent-browser click @e11 # Click "Remote Signer"
web3-agent-browser snapshot # Wallet connected
web3-agent-browser click @e9 # Sign In with Ethereum → done!Architecture
web3-agent-browser CLI
├── Signing Proxy (127.0.0.1:9334)
│ └── Transparent HTTP → mTLS + Ed25519 → remote-signer
└── Chrome + Extension (Extension-First Architecture)
├── content-script.js: auto-injects config.js + inpage.js at document_start
│ ├── Executes on EVERY page load (configured in manifest.json)
│ ├── Provider persists across all navigations automatically
│ └── Message relay: forwards fetch requests from inpage.js (bypasses page CSP)
├── inpage.js: EIP-1193 provider (window.ethereum)
│ ├── Signing methods → postMessage → content-script → fetch(proxy) → remote-signer
│ └── Read methods → postMessage → content-script → fetch(proxy) → RPC
└── Chrome guarantees content-script re-executes on every navigation
Data flow: dApp (inpage.js) → Extension (content-script) → Local Proxy → remote-signer
Key: Provider state persists because extension auto-reinjects on every navigation.Running Modes
| Mode | Command | Use Case |
|------|---------|----------|
| Headed (desktop) | DISPLAY=:0 node bin/web3-agent-browser.mjs start <url> | Watch AI operate in real-time |
| Headed (Xvfb) | Xvfb :99 & DISPLAY=:99 node bin/... | Server, no physical display |
| Headless | Chrome flag --headless=new in config extra_flags | Server automation, no display needed |
All three modes verified with SIWE login end-to-end.
Config
# config.yaml (or ~/.web3-agent-browser/config.yaml)
browser:
executable: /usr/bin/google-chrome
# headless: auto-detected based on DISPLAY env
# extra_flags: [] # --no-sandbox is always enabled
signers:
- name: default
# address: "0x..." # OPTIONAL: fallback if remote-signer fetch fails
# Addresses are auto-fetched from remote-signer (all accessible to API key)
remote_signer:
url: https://localhost:8548
api_key_id: agent # API key in remote-signer
certs_dir: /path/to/remote-signer/certs
chains:
- chain_id: 1
rpc: https://eth.llamarpc.com
- chain_id: 137
rpc: https://polygon-rpc.com
- chain_id: 8453
rpc: https://mainnet.base.org
proxy:
port: 9334
bind: "127.0.0.1"Testing
Integration tests verify provider injection, wallet connection, and EIP-1193 compliance across multiple dApps.
# Run all tests
npm test
# Run specific test suites
npm run test:provider # Provider injection & EIP-1193 interface
npm run test:login # Wallet connection flows
# Tests run automatically on git commit via husky pre-commit hook
# Skip with: git commit --no-verifyTest Coverage:
- ✅ Provider injection (DeBa, Polymarket, Uniswap)
- ✅ EIP-1193 interface (request, on, eth_chainId)
- ✅ Provider persistence across navigation
- ✅ EIP-6963 wallet discovery
- ✅ eth_requestAccounts (wallet connection)
- ⏳ personal_sign, eth_sendTransaction (pending relay fix)
See test/README.md for details.
CLI Commands
# Lifecycle
node bin/web3-agent-browser.mjs --config <yaml> start <url>
node bin/web3-agent-browser.mjs stop
# Page interaction (via agent-browser directly)
agent-browser snapshot # Accessibility tree + screenshot
agent-browser click @<ref> # Click element
agent-browser type @<ref> "text" # Type into element
agent-browser scroll_down # Scroll
agent-browser eval "js expression" # Execute JS
agent-browser open <url> # Navigate (provider auto re-injects)EIP Compliance
| Standard | Status | Details |
|----------|--------|---------|
| EIP-1193 | ~95% | request(), ProviderRpcError (4001/4100/4200/4900/4901), connect/disconnect/chainChanged/accountsChanged events, connection state tracking |
| EIP-6963 | ~95% | announceProvider, requestProvider listener, 96x96 icon, rdns xyz.web3gate.agent-browser |
| EIP-1102 | 100% | eth_requestAccounts with address validation |
| JSON-RPC 2.0 | 100% | send/sendAsync with proper error format {code, message, data} |
Features
- Multi-address support: Fetches all addresses accessible to API key from remote-signer (no hardcoded address)
- Auto re-inject: Provider automatically re-injected when you navigate to a new page
- Port conflict detection: CLI checks if proxy port is in use before starting
- Daemon recovery: Watch loop detects agent-browser daemon crashes, auto-restarts
- Multi-chain: wallet_switchEthereumChain updates RPC URL from config overrides
- Transparent proxy: Signing proxy doesn't parse request bodies, just adds mTLS + Ed25519
- EIP-1193 errors: ProviderRpcError with standard codes (4001 rejected, 4900 disconnected, etc.)
Files
| File | Purpose |
|------|---------|
| bin/web3-agent-browser.mjs | CLI wrapper: start proxy + chrome + eval inject + watch loop |
| proxy/server.mjs | Transparent HTTP→mTLS signing proxy (~160 lines) |
| extension/inpage.js | EIP-1193/6963 compliant provider (~200 lines) |
| extension/manifest.json | Chrome Extension MV3 manifest |
| extension/content-script.js | Extension content-script (backup, Chrome 143 doesn't execute it in automation) |
| extension/background.js | Extension service worker |
| skill/SKILL.md | Claude Code skill for AI-driven operation |
| src/inpage-glue.ts | js-client bundle entry (unused — bundle too large for eval) |
| scripts/build-extension.mjs | esbuild script for js-client bundle (unused — see above) |
Verified E2E Flows
| dApp | Connect | Sign | Action | Mode | |------|---------|------|--------|------| | Web3Gate (SIWE) | ✅ | ✅ personal_sign | ✅ Login to dashboard | headed + headless | | Uniswap | ✅ | — | Connect only (swap untested) | headed |
