External Browser Use Guide
Browser tools that operate the user's external Chrome browser via the TRAE Chrome extension. All tools below are aliases of the standard browseruse tools, automatically routed to the external Chrome browser (native mode).
Most browser operations are executed through the Exec tool (V8 sandbox), but some tools must be called as standalone toolcalls. See Tool Calling Mode Reference for the complete classification.
Tool Calling Mode Reference
Tools callable via Exec (await tools.*)
These tools MUST be called inside Exec using await tools.<name>(args):
| Category | Tools |
|---|---|
| Navigation | external_browser_navigate, external_browser_navigate_back, external_browser_tabs |
| Observation | external_browser_snapshot, external_browser_take_screenshot, external_browser_get_attribute, external_browser_console_messages, external_browser_network_requests |
| Interaction | external_browser_click, external_browser_type, external_browser_hover, external_browser_scroll, external_browser_press_key, external_browser_select_option, external_browser_drag, external_browser_upload_file, external_browser_handle_dialog |
| Advanced | external_browser_evaluate, external_browser_wait_for |
Tools that MUST be called alone (one per turn)
| Tool | Reason |
|---|---|
browser_connect_plugin |
Connectivity check. Must run before any other browser tools in a session. You need its result to decide the next step. |
browser_setup_plugin |
Requires user interaction (confirm/skip). You need its result to decide whether to use external or built-in browser. |
Rule: These tools MUST be the only tool call in that turn. Do NOT combine them with other tool calls in the same response. These tools do NOT use the
external_prefix.
CRITICAL - Tool Naming Convention
When operating the user's external Chrome browser, you MUST always use the external_browser_* prefix for ALL operational browseruse tool calls (e.g., external_browser_navigate, external_browser_click, external_browser_snapshot).
- DO NOT use
browser_navigate,browser_click, or any unprefixedbrowser_*form for operational tools — those may target the built-in browser, NOT the user's external Chrome. - Even if error messages or tool descriptions mention
browser_xxxwithout the prefix, you must still useexternal_browser_xxxfor operational tools to route the call to the external browser. - The
external_prefix is the sole routing signal that distinguishes external Chrome operations from built-in browser operations.
CRITICAL - First-time Connection Check
Before using any external browser tools for the first time in a session, you MUST:
- Call
browser_connect_pluginto verify the Chrome extension is reachable. - If
browser_connect_pluginreturnsconnected: false, immediately callbrowser_setup_pluginto guide the user through setup. - Only proceed with browser operations after
browser_connect_pluginsucceeds orbrowser_setup_plugincompletes.
If browser_setup_plugin returns that the user chose the built-in browser, stop using external_* tools and follow the TRAE-browseruse skill for standard browser usage.
CRITICAL:
browser_connect_pluginandbrowser_setup_pluginMUST each be called alone in a single turn — do NOT combine them with any other tool calls in the same response. Mixing them with other tools causes judgment issues because the AI cannot properly evaluate the connection/initialization result before deciding the next step.
NEVER call
browser_waiting_for_user_interactionwhenconnected: false. That tool is for handing browser control to the user during an active session — it cannot fix a missing extension. The ONLY correct response toconnected: falseisbrowser_setup_plugin.
CRITICAL - Before interacting with any page
- Use
external_browser_tabswith action"list"to see open tabs and their URLs. - Use
external_browser_snapshotto get the page structure and element refs before any interaction (click, type, hover, etc.).
IMPORTANT - Waiting strategy
When waiting for page changes (navigation, content loading, animations, etc.), prefer short incremental waits (1-3 seconds) with external_browser_snapshot checks in between rather than a single long wait. For example, instead of waiting 10 seconds, do: wait 2s → snapshot → check if ready → if not, wait 2s more → snapshot again. This allows you to proceed as soon as the page is ready rather than always waiting the maximum time.
Notes
- If two browser actions need to be performed sequentially, they should not be called in parallel.
- Iframe content is not accessible — only elements outside iframes can be interacted with.
- For nested scroll containers, use
external_browser_scrollwithscrollIntoView: truebefore clicking elements that may be obscured.
Code Execution Tool
You have access to a code execution tool that runs JavaScript in an isolated V8 sandbox.
CRITICAL: Always prefer Exec when the available tools can accomplish the task.
- ANY tool listed below MUST be called via
await tools.<name>(args)inside Exec, NOT as a direct tool call. - Use direct tool calls ONLY for tools that are NOT available inside Exec.
- Even for a single-step task, use Exec if that step involves an available tool.
- For multi-step tasks that share a clear linear flow (e.g., navigate → wait → snapshot → click → type), use a single Exec call.
- However, do NOT pack an entire long-running automation (polling loops, multi-minute waits, conditional branching across many pages) into one giant Exec block. Instead, split into multiple Exec calls so the LLM can inspect intermediate results and decide the next action.
- Exec gives you programmatic control: conditionals, error handling, sequential calls — use it for short, focused sequences (generally ≤ 20 lines). Do NOT use loops for polling or retrying.
Call format
run_mcp(server_name="integrated_code_mode", tool_name="Exec", args={"code": "<your_js_code>"})
argsMUST be a JSON object, not a string. The only accepted field iscode. Using any other field name (e.g.,script,command,program) results in "code is empty" error — all such fields are silently ignored.codeis required and must contain non-empty JavaScript.
Runtime environment
- Pure ECMAScript sandbox. Available globals: standard built-ins (Array, Object, Math, JSON, Promise, RegExp, Date, etc.) plus
tools,text,exit. - Use
text(value)to output results. Useawait tools.<name>(args)to invoke other tools. - Code runs as a top-level script, NOT inside a function.
returnat the top level is a SyntaxError — usetext(value)to output final results. - NOT available:
require,import,module,exports,process,Buffer,__dirname,__filename(no Node.js/CommonJS),document,window,navigator,location,localStorage(no browser DOM),fetch,XMLHttpRequest,WebSocket(no network). Using any of these throwsReferenceError: <name> is not defined.
Instructions
- Use
await tools.<tool_name>(args)to call tools — multiple calls in sequence are encouraged. - Use
Promise.all([tools.a(x), tools.b(y)])for concurrent tool calls. - Use
text(value)to output results to LLM (value will be stringified via JSON.stringify if not a string). - Use
exit()to stop execution early (already-produced text output is preserved).
Error handling
- Tool call errors cause the Promise to reject — use
try/catchto handle them gracefully. - Unhandled exceptions terminate the script and return the error message as the result.
- If the script exceeds the execution time limit, it is forcibly terminated and an error is returned.
text()output produced before an unhandled error is preserved in the response.
Tool response structure
All browser tools return the same structure:
interface BrowserToolResult {
/** Array of content items */
content: Array<{ type: "text"; text: string }>;
/** 0 = success, non-zero = error */
status: number;
}
- Most tools return a single
contentitem withtype: "text"containing the snapshot or result text. - When
status !== 0, thetextfield contains the error message. - Access the text output:
result.content[0].text
PTC Output Boundary
Nested tool results are not automatically visible to the model.
await tools.<name>(...)returns a JavaScript value inside Exec.JSON.stringify(...)only converts a value to a string. It does not display it.- Use
text(...)to expose a result to the model.
const snap = await tools.external_browser_snapshot();
text(snap);
- If the next action depends on reading a snapshot, choosing a ref, or interpreting evaluate output, end the current Exec immediately after
text(...). The model cannot inspecttext(...)output while the same Exec is still running.
Available Browser Functions
Page Navigation
external_browser_navigate — Navigate to a URL and return a snapshot
interface ExternalBrowserNavigateParams {
/** Target URL (MUST be http:// or https:// — about:, file:, chrome:, javascript: URLs are blocked by security policy*/
url: string;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
/** Whether to open in a new tab */
newTab?: boolean;
/** Tab position: "active" (replace current) | "side" (open beside) */
position?: "active" | "side";
/** Custom HTTP headers for all requests in this tab (pass empty {} to clear) */
extraHeaders?: Record<string, string>;
}
** Constraints **
external_browser_navigate will return ERR_ACCESS_DENIED for any non-http(s) URL. file:// is permanently blocked by security policy.
external_browser_navigate_back — Go back in browser history, return a snapshot
interface ExternalBrowserNavigateBackParams {
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_tabs — Manage browser tabs (list/new/close/select/activate)
interface ExternalBrowserTabsParams {
/** Action type: "list" | "new" | "close" | "select" | "activate" */
action: "list" | "new" | "close" | "select" | "activate";
/** Tab index (required for close/select/activate). NOTE: this is the positional index, NOT tabId */
index?: number;
}
activatevsselect:selectswitches to a tab but does NOT steal user focus.activate= select + bring the tab to foreground focus. Some pages only execute certain logic (e.g., timers, animations, event listeners) when they are the focused/active tab. If you notice a page not responding as expected afterselect, tryactivateinstead.
Page Observation (prefer snapshot over screenshot)
external_browser_snapshot — Get page accessibility snapshot
interface ExternalBrowserSnapshotParams {
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
/** Snapshot strategy: "dom" (DOM mode) | "cdp" (Chrome AX Tree mode, default) */
strategy?: "dom" | "cdp";
/** Maximum traversal depth */
maxDepth?: number;
/** Maximum number of nodes */
maxNodes?: number;
/** Whether to include ignored nodes */
includeIgnored?: boolean;
/** Whether to return only interactive elements */
interactive?: boolean;
/** Whether to use compact output format */
compact?: boolean;
/** CSS selector to snapshot only the matching subtree */
selector?: string;
}
external_browser_take_screenshot — Take a screenshot (use only when snapshot is insufficient, e.g. canvas, complex CSS, images)
interface ExternalBrowserTakeScreenshotParams {
/** Output filename */
filename?: string;
/** Whether to capture the full page (not just the viewport) */
fullPage?: boolean;
/** Capture only the element matching this ref */
ref?: string;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_get_attribute — Get an element attribute value
interface ExternalBrowserGetAttributeParams {
/** Element reference ID (from snapshot's [ref=N]) */
ref: string;
/** Attribute name to read (e.g. "href", "src", "class") */
name: string;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_console_messages — Get browser console log messages
interface ExternalBrowserConsoleMessagesParams {
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_network_requests — Get captured network requests
interface ExternalBrowserNetworkRequestsParams {
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
Element Interaction
external_browser_click — Preferred click method. Click an element by ref (supports double-click, mouse buttons, modifiers), returns snapshot
interface ExternalBrowserClickParams {
/** Element reference ID (from snapshot's [ref=N]) */
ref: string;
/** Whether to double-click */
doubleClick?: boolean;
/** Mouse button: "left" (default) | "right" | "middle" */
button?: "left" | "right" | "middle";
/** Modifier keys, e.g. ["Alt", "Control", "Meta", "Shift"] */
modifiers?: string[];
/** Horizontal offset from element's top-left corner in pixels. If omitted, clicks the horizontal center. */
offsetX?: number;
/** Vertical offset from element's top-left corner in pixels. If omitted, clicks the vertical center. */
offsetY?: number;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_type — Type text into an input element by ref, returns snapshot
interface ExternalBrowserTypeParams {
/** Element reference ID */
ref: string;
/** Text to type */
text: string;
/** Whether to clear existing content before typing. Use this to replace the current value instead of appending to it. Defaults to false. */
clear?: boolean;
/** Whether to press Enter after typing (submit form) */
submit?: boolean;
/** Whether to type character-by-character (simulates real typing for per-char event triggers) */
slowly?: boolean;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_hover — Hover over an element (triggers mouseenter/mouseover/mousemove), returns snapshot
interface ExternalBrowserHoverParams {
/** Element reference ID */
ref: string;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_scroll — Scroll the page or a specific element by direction/amount, returns snapshot
interface ExternalBrowserScrollParams {
/** Element reference to scroll (omit to scroll the page) */
ref?: string;
/** Scroll direction: "up" | "down" (default) | "left" | "right" */
direction?: "up" | "down" | "left" | "right";
/** Scroll amount in pixels */
amount?: number;
/** Horizontal scroll delta */
deltaX?: number;
/** Vertical scroll delta */
deltaY?: number;
/** Whether to scroll the ref element into the visible area */
scrollIntoView?: boolean;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_press_key — Dispatch a keyboard event to the currently focused
interface ExternalBrowserPressKeyParams {
/** Key name. Common: "Enter", "Tab", "Escape", "Backspace", "ArrowDown", "ArrowUp", "ArrowLeft", "ArrowRight" */
key: string;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_select_option — Select option(s) in a select dropdown by value, returns snapshot
interface ExternalBrowserSelectOptionParams {
/** Select element reference ID */
ref: string;
/** Option value(s) to select (supports multi-select) */
values: string[];
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_drag — Drag from one element to another element or coordinate
interface ExternalBrowserDragParams {
/** Source element reference ID */
sourceRef: string;
/** Target element reference ID (mutually exclusive with targetX/targetY) */
targetRef?: string;
/** Target absolute X coordinate */
targetX?: number;
/** Target absolute Y coordinate */
targetY?: number;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_upload_file — Upload a file to a file input element
interface ExternalBrowserUploadFileParams {
/** File input element reference ID (REQUIRED — from snapshot [ref=N]) */
ref: string;
/** Element selector (alternative locator) */
element?: string;
/** File path to upload (REQUIRED — must be a valid local path) */
filePath: string;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
external_browser_handle_dialog — Handle a browser dialog (alert/confirm/prompt)
interface ExternalBrowserHandleDialogParams {
/** Action: "accept" | "dismiss" */
action?: "accept" | "dismiss";
/** Text to enter in a prompt dialog */
promptText?: string;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
Advanced
external_browser_evaluate — Execute JavaScript in the page context
interface ExternalBrowserEvaluateParams {
/** JavaScript code to execute (use JSON.stringify for structured data extraction) */
script: string;
/** Target browser tab ID. If omitted, uses the last interacted tab. NOTE: field name is "script", NOT "expression" or "code" */
viewId?: string;
}
** Constraints **
- The
scriptparameter is the ONLY field for code. Any other field name will fail with "missing fieldscript".scriptmust be a string. Passing an object (e.g.,{ script: {...} }) causes "[object Object]" parse errors. - No top-level
return— wrap in IIFE:(function(){ return value; })(). - Guard all DOM access with
?.or explicit null checks — elements may not exist. - Do NOT call
fetch()orXMLHttpRequestinside script — usebrowser_navigatefor API URLs. - Do NOT
JSON.stringifyDOM elements directly — extract needed primitive values first. - Do NOT serialize
document.body.innerHTMLor large subtrees — causes 30s timeout. - Use standard CSS selectors and guard optional elements with
?.or??. - Use
JSON.stringify(...)for structured data (on plain objects only, never on DOM nodes). - Read-Only Only: All page mutations (click, type, submit, navigate) must use native browser tools. Keep
external_browser_evaluatefor data extraction only.
external_browser_wait_for — Wait for a condition (time/text appear/text disappear/selector appear)
interface ExternalBrowserWaitForParams {
/** Seconds (not ms) to sleep. Range: 1–60. For longer waits, use a loop. */
time?: number;
/** Wait for this text to appear on the page */
text?: string;
/** Wait for this text to disappear from the page */
textGone?: string;
/** Wait for a CSS selector to match an element */
selector?: string;
/** Element state: "visible" | "hidden" | "attached" | "detached" */
state?: string;
/** Maximum timeout in milliseconds */
timeout?: number;
/** Target browser tab ID. If omitted, uses the last interacted tab. */
viewId?: string;
}
Usage patterns:
- Sleep 3 seconds:
{ time: 3 } - Wait for text:
{ text: "Loading complete", timeout: 30 } - Wait for element:
{ selector: ".content", timeout: 10 }
Workflow Best Practices
Exec Batching & Interaction Patterns
Rule
Never issue back-to-back single-tool Exec calls if the workflow can be combined into a single Exec block. Pack 2–5 predictable sequential browser operations into ONE Exec call.
- Sizing: 2–5 tools = optimal; 6–10 = acceptable; 10+ = split for readability.
- Split point: If step N's result determines whether/what step N+1 does (branching), end the Exec at step N and decide in the next turn.
- Ref lifetime: Refs invalidate after any page mutation (click, navigate, evaluate that changes DOM). Always re-snapshot before using refs from a prior state.
Proven Patterns (use as default templates)
// Pattern A: click → wait → snapshot (98.6% success, N=423)
await tools.external_browser_click({ ref: "42" });
await tools.external_browser_wait_for({ time: 2 });
const snap = await tools.external_browser_snapshot();
text(snap);
// Pattern B: click → snapshot (100% success, N=107)
// Use when target page is fast / no async loading
await tools.external_browser_click({ ref: "42" });
const snap = await tools.external_browser_snapshot();
text(snap);
// Pattern C: navigate → wait → snapshot (100% success, N=40)
await tools.external_browser_navigate({ url: "https://example.com" });
await tools.external_browser_wait_for({ time: 2 });
const snap = await tools.external_browser_snapshot();
text(snap);
// Pattern E: scroll → wait → snapshot (100% success, N=96)
await tools.external_browser_scroll({ ref: "10", direction: "down", amount: 300 });
await tools.external_browser_wait_for({ time: 2 });
const snap = await tools.external_browser_snapshot();
text(snap);
Anti-Patterns (NEVER use)
| Pattern | Success | Root Cause |
|---|---|---|
click → wait → click (no re-snapshot) |
0% | Refs stale after first click |
navigate → navigate → snapshot |
20% | Race condition between navigations |
Multi-click recovery — re-snapshot after the first page mutation:
await tools.external_browser_click({ ref: "5" });
await tools.external_browser_wait_for({ time: 2 });
const snap = await tools.external_browser_snapshot();
text(snap);
Snapshot-Driven Approach
- Snapshot first: Always call
tools.external_browser_snapshot()to understand the page before acting. - Click by ref: Use
tools.external_browser_click({ ref: N })with the[ref=N]from snapshot output. - Verify after action: Snapshot again after critical actions to confirm the page state changed.
- Use evaluate() for data: When you need structured data, prefer
tools.external_browser_evaluate({ script })over parsing snapshot text.
Cost Hierarchy (prefer top)
| Method | Cost | Use for |
|---|---|---|
browser_snapshot() |
Very low | Page understanding, finding elements |
browser_click/browser_type/browser_press_key |
Low | Interaction |
browser_evaluate() |
Low | Data extraction, DOM queries |
browser_take_screenshot() |
High | Visual-only info, canvas, layouts |
Text Input Pattern
const snap = await tools.external_browser_snapshot();
text(snap);
After reading the snapshot output, use its refs in the next Exec:
await tools.external_browser_click({ ref: "3" });
await tools.external_browser_type({ ref: "3", text: "user@example.com" });
await tools.external_browser_press_key({ key: "Tab" }); // move to next field
await tools.external_browser_type({ ref: "4", text: "password123", submit: true }); // submit: true presses Enter
Image Input Pattern
If you have to use the external_browser_take_screenshot tool, it is recommended to invoke the automatic image‑reading function image() after calling external_browser_take_screenshot.
Bear in mind that image() exclusively accepts the raw tool‑response object carrying the __images property; string inputs are unsupported:
const shot = await tools.external_browser_take_screenshot({});
image(shot);
Debugging White/Blank Pages
If a page appears blank (white screen) after navigation, use tools.external_browser_console_messages() to check for JavaScript errors or failed resource loads that explain why the page didn't render.
After Navigation
Always wait after navigating before interacting:
await tools.external_browser_navigate({ url: "https://example.com" });
await tools.external_browser_wait_for({ time: 2 });
const snap = await tools.external_browser_snapshot();
text(snap);
Multi-Step Orchestration
await tools.external_browser_navigate({ url: "https://example.com" });
await tools.external_browser_wait_for({ time: 2 });
const snap = await tools.external_browser_snapshot();
text(snap);
After reading the snapshot output, continue in the next Exec:
await tools.external_browser_click({ ref: "3" });
await tools.external_browser_type({ ref: "3", text: "search query", submit: true });
await tools.external_browser_wait_for({ time: 2 });
const result = await tools.external_browser_snapshot();
text(result);
Tab Activation Pattern
When a page requires foreground focus to function properly (e.g., timers, animations, event listeners), use activate instead of select:
// 1. List all tabs to find the target
const tabs = await tools.external_browser_tabs({ action: "list" });
// tabs output example:
// [0] https://example.com/dashboard
// [1] https://example.com/settings <-- we want this one
// 2. Activate by index (positional index from the list, NOT tabId)
await tools.external_browser_tabs({ action: "activate", index: 1 });
// 3. Snapshot to verify and get fresh refs
const snap = await tools.external_browser_snapshot();
text(snap);
Data Extraction with external_browser_evaluate()
// Get all links
const links = await tools.external_browser_evaluate({
script: `JSON.stringify(Array.from(document.querySelectorAll('a[href]')).map(a => ({text: a.textContent.trim(), href: a.href})).filter(a => a.text).slice(0, 20))`
});
text(links);
// Get form values
const formData = await tools.external_browser_evaluate({
script: `JSON.stringify({ email: document.querySelector('#email')?.value, name: document.querySelector('#name')?.value })`
});
text(formData);
Multi-Step Orchestration
await tools.external_browser_navigate({ url: "https://example.com" });
await tools.external_browser_wait_for({ time: 2 });
const snap = await tools.external_browser_snapshot();
text(snap);
After reading the snapshot output, continue in the next Exec:
await tools.external_browser_click({ ref: "3" });
await tools.external_browser_type({ ref: "3", text: "search query", submit: true });
await tools.external_browser_wait_for({ time: 2 });
const result = await tools.external_browser_snapshot();
text(result);
Ref Lifecycle & Invalidation
Element refs ([ref=N]) are temporary identifiers generated at snapshot time. They become invalid after any DOM change. The common ref not found in RefMap or DOM error originates from this.
Core Principles
- A ref is only valid between the current snapshot and the next DOM mutation
- Any operation that causes DOM reflow (navigation, AJAX, animations, dialog close) may invalidate refs
Recommended Patterns
Compact mode (preferred) — use a ref selected from the latest model-visible snapshot. No DOM mutation may have occurred since that snapshot:
// This ref was selected from the snapshot output of the previous Exec.
await tools.external_browser_click({ ref: "<ref-from-latest-snapshot>" });
const result = await tools.external_browser_snapshot();
text(result);
Wait-and-refresh pattern:
await tools.external_browser_wait_for({ text: "Loading complete" });
const snap = await tools.external_browser_snapshot();
text(snap);
If refs become stale, re-snapshot and retry with native external browser tools. Do not use external_browser_evaluate to mutate the page.
Avoid successive external_browser_evaluatecalls within‑one execution snippet. Invoke external_browser_snapshot to inspect the current‑page state in‑between operations.
Error Handling
- If a tool call fails, snapshot the page to understand current state before retrying.
- If an element ref is not found, the element may have been removed from DOM — re-snapshot to get fresh refs (see Ref Lifecycle & Invalidation).
- After navigation that takes long, use
external_browser_wait_for({ selector })to confirm page readiness instead of a fixed delay. - If snapshot returns very few elements, the page may still be loading — wait and retry.
Safety Rules
- Never submit forms with sensitive data without user approval.
- Never bypass security prompts (CAPTCHAs, "site not secure" warnings).
- Never delete or modify user data without explicit approval.