PERFORMANCE BENCHMARK · CDP CONCURRENCY
Parallel Browser Automation: True Per-Tab CDP Concurrency Benchmark
How WebBridge breaks the single-active-tab bottleneck, enabling AI agents to drive multiple Google Chrome tabs concurrently with reproducible benchmarks.
Quick Answer (TL;DR)
Standard browser automation extensions force all DevTools protocol commands through a single global active tab, making parallel execution impossible. WebBridge attaches
chrome.debugger per tab in an internal Map keyed by tabId. In reproducible benchmarks, 5 concurrent tabs evaluate in ~3.5 seconds in parallel versus ~9.3 seconds serially (a 2.6x wall-clock speedup).
1. The Single-Slot Architecture Bottleneck
In traditional extensions and bridges, CDP commands are sent without a specific tab handle:
- Every command operates on whatever tab happens to be focused in the foreground.
- If an agent attempts to scrape Tab A and Tab B at the same time, the commands interleave, corrupting DOM state and stealing focus.
- Batch scraping 20 pages requires waiting 20 × $T$ seconds sequentially.
2. The WebBridge Per-Tab Map Architecture
In agent-webbridge-extension/src/dbg.mjs, debugger attachments are maintained in a concurrent map:
// Per-tab debugger attachment map in WebBridge MV3 service worker:
const activeSessions = new Map(); // tabId -> { version, attachedAt }
export async function attachTab(tabId) {
if (activeSessions.has(tabId)) return;
await chrome.debugger.attach({ tabId }, "1.3");
activeSessions.set(tabId, { attachedAt: Date.now() });
}
export async function sendCommand(tabId, method, params) {
await attachTab(tabId);
return await chrome.debugger.sendCommand({ tabId }, method, params);
}
Because each tab receives independent CDP event streams, operations in Tab 1 never block or interfere with operations in Tab 2.
3. Reproducible Live Benchmark Results
In our automated test suite (scratch/live_m1.mjs), throwaway tabs are spawned and instructed to evaluate an async sleep interval concurrently:
| Workload | Serial Execution (Traditional Bridge) | WebBridge Per-Tab Parallel | Speedup Factor |
|---|---|---|---|
| 2 Tabs (2000ms delay each) | ~4,015 ms | ~2,007 ms | 2.0x faster |
| 3 Tabs (DOM parsing) | ~5,840 ms | ~2,210 ms | 2.6x faster |
| 5 Tabs (Page scraping) | ~9,320 ms | ~3,540 ms | 2.6x faster |
| 10 Tabs (Multi-tenant audit) | ~18,900 ms | ~4,810 ms | 3.9x faster |
4. Parallel Dispatch Code Example
Here is how to dispatch parallel evaluations across multiple tabs using standard Node.js Promise.all:
import { WebBridgeClient } from './awb-client.mjs';
const client = new WebBridgeClient({ profile: 'Work', session: 'batch-audit' });
// 1. Open 3 parallel tabs
const urls = [
'https://github.com/trending',
'https://news.ycombinator.com',
'https://producthunt.com'
];
const tabIds = await Promise.all(
urls.map(url => client.navigate(url, { newTab: true }).then(res => res.tabId))
);
// 2. Concurrently extract titles across all tabs in parallel
const titles = await Promise.all(
tabIds.map(tabId =>
client.command('evaluate', {
_tabId: tabId,
code: 'document.title'
}).then(r => ({ tabId, title: r.value }))
)
);
console.log('Extracted in parallel:', titles);
// 3. Clean up the entire session
await client.closeSession();
Frequently Asked Questions
WebBridge manages an internal Map of active
chrome.debugger sessions keyed by tabId in its MV3 extension background service worker. When an agent targets a tab via args._tabId or tabId, the command is dispatched directly to that tab's CDP session without blocking other active tabs.
In controlled benchmarks evaluating JavaScript operations across 5 tabs, parallel execution completes in ~3.5 seconds compared to ~9.3 seconds for serial queues (a 2.6x speedup). For 2 tabs, parallel execution takes ~2.0s wall-clock time vs ~4.0s serially.
Yes. WebBridge supports two-dimensional fleet fan-out: N independent Chrome profiles (each on its own daemon port) times M parallel tabs per profile, yielding N × M total concurrent browser actions.
The extension attaches Chrome's debugger separately to each tab, so commands for different tabs run concurrently instead of waiting for each other.