How GenericAgent's web_execute_js Achieves Full Browser Control Using JavaScript
GenericAgent's web_execute_js function achieves full browser control by tunneling arbitrary JavaScript through a WebSocket driver to a Chrome extension that executes code directly in the page context and bridges to Chrome's DevTools Protocol (CDP) for privileged operations like reading HttpOnly cookies or manipulating tabs.
The lsdefine/GenericAgent repository implements a complete browser automation stack that lets Python agents execute JavaScript with the same privileges as a user sitting at the DevTools console. This architecture leverages a custom Chrome extension (tmwd_cdp_bridge) to inject scripts into live pages and communicate bidirectionally with the TMWebDriver Python backend.
Architecture Overview
The system consists of three primary layers working in concert:
- Python Driver Layer (
TMWebDriver.py): Manages WebSocket connections, session state, and request/response correlation using unique execution IDs - Browser Extension Bridge (
assets/tmwd_cdp_bridge/): Persists a WebSocket connection tows://127.0.0.1:18765and forwards commands between the driver and page contexts - Page Execution Context (
content.js): Evaluates user JavaScript inside an async IIFE with full access to the DOM, global variables, and browser APIs
When web_execute_js is called, the payload travels through ga.py → simphtml.py → TMWebDriver.execute_js, then across the WebSocket to the extension's background script, which injects it into the active tab's content script for execution.
Step-by-Step Execution Flow
Session Management and Tab Tracking
Each browser tab registers as a unique session within TMWebDriver. When the extension's content script loads, it sends a type: "ready" message that triggers TMWebDriver._register_client to create a Session object tracking that tab's WebSocket client. The driver maintains default_session_id to identify the currently active tab, with automatic fallback to the newest session if the current tab disconnects (lines 190-203 in TMWebDriver.py).
Script Transmission and Correlation
Inside TMWebDriver.execute_js, the driver generates a unique execution ID using uuid.uuid4() and constructs a JSON payload:
exec_id = str(uuid.uuid4())
payload = json.dumps({'id': exec_id, 'code': code})
session.ws_client.send_message(payload)
This payload travels over the persistent WebSocket connection to the extension. The exec_id enables the driver to match asynchronous results with their originating requests, handling ACK receipts and timeout logic (lines 28-36 in TMWebDriver.py).
Extension Bridge and Message Routing
The extension's background.js maintains a persistent WebSocket connection using alarms to survive MV3 service-worker suspension:
ws = new WebSocket('ws://127.0.0.1:18765');
ws.onmessage = e => {
const msg = JSON.parse(e.data);
if (msg.type === 'execute_js') {
// Forward to content script via hidden DOM element #TID
}
};
For commands requiring elevated privileges (cookies, tabs, debugger), the background script intercepts messages and forwards them to Chrome's extension APIs (chrome.debugger, chrome.cookies) or the CDP interface.
Page Context Execution
The content script (assets/tmwd_cdp_bridge/content.js) monitors a hidden DOM element (#TID) for incoming commands. When detected, it invokes buildPageScript to wrap user code in an async IIFE:
- Detects if the last line contains an explicit
returnstatement - Injects automatic return capture if absent using the
_airhelper - Executes via
evalorAsyncFunctionconstructor - Serializes results using
smartProcessResultto handle DOM nodes, NodeLists, and jQuery objects - Writes JSON back to the DOM element for the background script to transmit via WebSocket
Why This Enables Full Browser Control
Page Context Execution: Because scripts run via eval in the page's JavaScript context (not an isolated extension context), they access the same global scope, closures, and JavaScript APIs available to the actual site. This includes fetch, WebSocket, localStorage, and framework internals.
CDP Bridge Integration: The extension's chrome.debugger connection allows scripts to issue CDP commands for operations impossible from page JavaScript alone, such as:
- Reading
HttpOnlycookies - Capturing network traffic
- Inspecting and modifying other tabs
- Accessing browser storage mechanisms
Bidirectional Session Management: The driver tracks tab lifecycle states, handles reconnection, and supports explicit tab switching via driver.default_session_id or switch_tab_id parameters, enabling multi-tab automation workflows.
Practical Implementation Examples
Basic DOM Interaction and Element Clicking
from ga import web_execute_js
script = """
// Click the submit button and return the resulting page title
document.querySelector('button[type="submit"]')?.click();
return document.title;
"""
result = web_execute_js(script)
print(result["js_return"]) # Outputs: "Confirmation Page"
This executes through the full chain: ga.py validates the driver, simphtml.py normalizes the output, and TMWebDriver manages the WebSocket round-trip with ACK/result correlation.
Accessing HttpOnly Cookies via CDP
Page JavaScript cannot read HttpOnly cookies, but the CDP bridge can:
script = """
return await new Promise(resolve => {
chrome.runtime.sendMessage(
{cmd: 'cookies', url: location.href},
resp => resolve(resp)
);
});
"""
result = web_execute_js(script)
cookies = result["js_return"]["data"]
# Contains HttpOnly cookies invisible to document.cookie
The content script forwards the cookies command to background.js, which queries chrome.cookies.getAll() with full permission access.
Cross-Tab Navigation and Session Management
# Open a new tab using the GM_openInTab helper injected by the extension
script = """
GM_openInTab('https://example.com/admin');
return 'tab_opened';
"""
web_execute_js(script)
# Switch to the new tab by URL pattern
driver.set_session('admin')
current_url = web_execute_js("return location.href;")["js_return"]
The TMWebDriver automatically registers the new tab as a session when the extension connects, allowing immediate automation.
Key Source Files
ga.py: Publicweb_execute_jswrapper that agents call; validates driver state and forwards tosimphtml.pysimphtml.py: Normalizes script output, adds optional execution monitoring, and interfaces withTMWebDriverTMWebDriver.py: Core driver implementing session management, WebSocket communication, ACK/result correlation, and timeout logicassets/tmwd_cdp_bridge/content.js: Content script executing user code in page context viabuildPageScriptandsmartProcessResultassets/tmwd_cdp_bridge/background.js: Manages persistent WebSocket connection to the driver, forwards CDP/cookie commands usingchrome.debuggerandchrome.cookiesAPIsassets/tmwd_cdp_bridge/manifest.json: Declares required permissions (debugger,cookies,tabs) and registers background/content scripts
Summary
web_execute_jstunnels JavaScript through a WebSocket driver (TMWebDriver.py) to a Chrome extension that executes code in the page's own JavaScript context- The
tmwd_cdp_bridgeextension provides bidirectional communication and privileged access to Chrome's DevTools Protocol for operations like reading HttpOnly cookies or managing tabs - Unique execution IDs with ACK/result handling ensure reliable delivery confirmation and timeout detection
- Session management tracks individual tabs, enabling multi-tab automation with
default_session_idswitching - This architecture gives GenericAgent the equivalent power of a human user at the browser console, programmable from Python
Frequently Asked Questions
How does web_execute_js handle timeouts and execution errors?
The TMWebDriver.execute_js method implements a two-phase timeout system. If no ACK arrives within the specified timeout, it returns a "no response" error indicating the extension disconnected. If an ACK arrives but no result follows, it reports that the script may still be running. JavaScript exceptions thrown during execution are caught by the content script's try-catch wrapper in buildPageScript, serialized as {ok:false, error:{…}}, and returned to the Python caller through the WebSocket.
Can web_execute_js access browser features unavailable to regular page JavaScript?
Yes. While scripts execute in the page context for DOM access, they can communicate with the extension background script via chrome.runtime.sendMessage to trigger CDP commands. The background script uses chrome.debugger and chrome.cookies APIs with elevated permissions declared in manifest.json, enabling access to HttpOnly cookies, network interception, and cross-tab manipulation impossible from standard page JavaScript.
What is the difference between web_execute_js and standard Selenium WebDriver execute_script?
Unlike Selenium's execute_script which uses WebDriver protocol JSON endpoints, GenericAgent's implementation uses a persistent WebSocket connection to a manifest v3 extension. This enables lower latency bidirectional communication, automatic handling of MV3 service worker suspension via alarms, and direct access to CDP without separate debugging ports. The extension also injects helper functions like GM_openInTab and maintains session state across page navigations.
Is it safe to execute arbitrary JavaScript from untrusted sources using this system?
Caution is required. Because web_execute_js runs in the page context with full access to document, window, and browser storage, malicious scripts could steal cookies, exfiltrate data, or modify page behavior. The system is designed for automation of trusted workflows. When dealing with untrusted input, implement sandboxing at the application level or restrict the extension permissions in manifest.json to specific domains.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →