oh-my-webbridge Docs
Skip to Content

Actions

The command endpoint, every browser action, selector syntax and error codes.

Developer preview

omw is in developer preview and iterating rapidly. THERE WILL BE COMPATIBILITY-BREAKING CHANGES.

Every browser action goes through POST /command on the daemon at http://127.0.0.1:17373. Requests carry the Bearer token printed by omw connection. The CLI wraps it in omw call, the SDK in call (see CLI and SDK).

Requests

FieldTypeMeaning
sessionstringSession name, 1 to 96 letters (including CJK), digits, _, . or -. Required.
actionstringAction name from the tables below. Required.
argsobjectAction arguments. Defaults to {}.
timeoutMsnumberDeadline in milliseconds, 1 to 120000, default 30000. It covers queueing and execution. Another value, including 0, fails with invalid_request.
browserstringchrome or firefox. Omit to use the browser already bound to the session, or the only connected one, or Chrome.

The body is one JSON object of at most 2 MiB with no unknown fields. A session name that repeats a binding is routed by the rules on Sessions and tabs.

{
  "session": "research",
  "action": "navigate",
  "args": { "url": "https://example.com", "group_title": "Research" },
  "timeoutMs": 30000
}

The body can also carry id, a string that the reply repeats. Without it, the daemon assigns a Snowflake ID in lowercase base 36. A successful call returns the id and the action result:

{
  "id": "uvwoyqsusjk",
  "result": { "success": true, "tabId": 412, "url": "https://example.com/" }
}

A failed call returns the id and a fault instead of a result, with an HTTP status from the Errors table:

{
  "id": "uvwoyqsusjk",
  "error": { "code": "stale_ref", "message": "element reference expired; take a fresh snapshot" }
}

Page actions run in the session's current tab. Pass tabId (or tab) to address another tab the session holds without switching to it.

ActionArgumentsNotes
navigateurl, newTab, group_title, preset fieldsOpens a background task tab unless the session already has a current tab or newTab is set. URLs must be HTTP(S) or about:blank.
find_taburl (exact URL or hostname), activeClaims an existing tab for the session. active: true borrows the browser's active tab. Returns tabId, url, borrowed.
list_tabsnoneLists the tabs this session owns or borrowed, with tabId, url, title, active, borrowed, groupTitle.
switch_tabtabIdMakes the tab current. A discarded tab is reloaded first; the result reports revived.
window_newurl, preset fieldsOpens a separate window, claims its tab, and returns tabId and windowId.
close_tabtabIdCloses a tab the session created. Borrowed tabs are not closed.
close_sessionnoneCloses task tabs, releases borrowed ones and drops the browser binding. Returns the number of closed tabs.
historycmd: list, back, forward, reloadlist returns the navigation entries. Every history call drops the tab's references and frame selection.

A session holds at most 32 tabs across task and borrowed ones.

Reading

ActionArgumentsNotes
snapshotinteractive, maxDepthAccessibility tree with @e references, plus url, title, truncated. Depth is capped at 64. Output stops at 4000 nodes or 192000 characters.
findquery, snapshot fieldsCase-insensitive search over snapshot lines. At most 100 matches.
read_pagenoneurl, title and the first 192000 characters of document.body.innerText.
evaluatecode, contextIdRuns an expression and returns { type: "value", value }. Use an async IIFE for await.
getselector, property, attributetext, html, value, attr, count, box, styles, title, url.
isselector, propertyvisible, enabled, checked, editable. Returns a boolean value.
locateby, value, name, nth, cmd, text, propertyBuilds a selector from by (role, text, label, placeholder, alt, title, testid, css, xpath) and runs cmd, an element action that defaults to get.
dialog_statusnoneReturns the pending JavaScript dialog as dialog, or null.

Input

ActionArgumentsNotes
click, dblclick, mouse_clickselector or x and y, buttonDispatches mouse events at the element center.
hoverselectorMoves the pointer to the element.
fillselector, valueReplaces the content of an input, textarea or contenteditable element. An empty value clears it.
key_typetext, selectorInserts text at the focused element, or focuses selector first.
send_keyskeysOne key or a chord such as Control+A or Meta+A. Named keys include Enter, Tab, Escape, Backspace, Delete, arrows, Home, End, PageUp, PageDown, Space.
keyboardcmd: down, up, insertText; key, textLower-level key control for held modifiers.
mousecmd: move, down, up, wheel; x, y, button, amountRaw pointer control.
scrollselector, or direction, amount, x, yWith a selector, scrolls it to the middle. Otherwise wheels by amount (0 to 100000, default 600) in up, down, left or right.
select_optionselector, valueMatches an option by value or by visible text, then fires input and change.
dragfrom, toPresses at from, moves in ten steps and releases at to.
focus, check, uncheckselectorcheck and uncheck read the current state first and verify the result; repeating them does not toggle. Radios support check only.
dialogaccept, promptTextAnswers the pending dialog. accept defaults to false.

Waiting

wait returns as soon as the condition holds, and checks it again every 75 ms. When the condition has not held 500 ms before the request deadline, wait fails with wait_timeout. It checks at least once, also under a deadline of 500 ms or less. Set the deadline with timeoutMs, or --timeout-ms in omw call. Set one of these fields:

FieldMeaning
selectorThe first match exists, has a box and is not visibility: hidden.
textdocument.body.innerText contains the string.
urlThe current URL matches. * matches any run of characters.
expressionThe JavaScript expression is truthy.
loadload waits for readyState === "complete"; domcontentloaded waits for the document to leave loading.
statevisible (default) or hidden, which inverts the condition.

Frames

Action or argumentMeaning
frame {"cmd": "list"}Lists frames with id, name and url, including cross-process child frames.
frame {"selector": "iframe#panel"}Selects the frame that holds the matching iframe element.
frame {"frameId": "..."}, frame {"name": "..."}, frame {"url": "..."}Selects by id, name or exact URL.
frame {"cmd": "main"}Returns to the main frame and drops the frame's references.

While a frame is selected, page actions run in it. Selecting a frame drops the previous references and requires a new snapshot.

A selection ends when its frame navigates or is removed, or, in Chrome, when the tab's debugger session ends, for example after the user cancels Chrome's debugging bar or the extension's worker restarts. The next action that would run in the frame fails once with frame_unavailable; later actions use the main frame.

Files and capture

ActionArgumentsNotes
screenshotformat (png, jpeg), quality (0 to 100), selector, fullPage, pathReturns path, sizeBytes and mimeType. Without path the file goes under the daemon's artifacts directory. An existing path is rejected.
save_as_pdfpaper_format (default letter; also legal, a4, a3, tabloid), landscape, scale (0.1 to 2), print_background, pathStreams the PDF to disk in chunks and returns path, sizeBytes, mimeType and pageTitle. Chrome only.
uploadselector, filesAbsolute paths on the machine running the browser. Chrome needs "Allow access to file URLs" on for the extension in chrome://extensions. The daemon inlines file contents for Firefox: 16 MiB per command and 64 MiB in flight.
downloadurl (HTTP(S)), filenameReturns path, sizeBytes, mimeType and id on the browser's host. A cancel or timeout interrupts the download.

A screenshot whose encoded result exceeds 32 MiB fails with result_too_large.

Network, console, storage and cookies

ActionArgumentsNotes
networkcmd: start, stop, list, detail; filter, requestIdKeeps the last 500 requests per tab. filter is a URL substring. detail returns the response body. In Chrome, a recording covers the frame selected at start: the main frame with its same-process iframes, or one cross-process iframe. Selecting another frame later does not move it.
consolecmd: start, list, clear, stopStores up to 200 entries per tab, each truncated to 8192 characters.
storagecmd: list, get, set, remove, clear; kind (local, session), name, valueReads and writes the current origin only. Returns origin, kind and either value or the whole store.
cookiescmd: list, set, delete, clear; data, nameScoped to the current URL. set passes data through to the cookie fields.

Emulation

FieldMeaning
width, heightViewport in CSS pixels, 1 to 16384 each. Both are required to change the device metrics.
deviceScaleFactor, mobileDevice pixel ratio and mobile flag for the metrics override.
colorSchemedark or light for prefers-color-scheme.
latitude, longitudeGeolocation. Both are required together.
offlineTakes the page offline or back online.
dataExtra HTTP headers: at most 128 string values and 32 KiB, without CR or LF.

Settings persist for the session and apply to new tabs before they navigate. Chrome drops them when it ends a tab's debugger session, for example after the extension's worker restarts; the next command on a task tab of the session applies them again. Borrowed tabs are excluded.

Batch

batch takes steps, an array of { action, args } objects, 1 to 64 entries. Steps run in order in one request and stop at the first error. The error keeps the code of the failed step, and its message starts with batch step N of M (action):, so steps 1 to N-1 completed. Completed steps are not rolled back. batch, close_session, screenshot, save_as_pdf, artifact_read and artifact_close cannot appear inside a batch.

Presets

FieldMeaning
presetanti-ad (default), zen or none.
environmentInstalls bundled cosmetics and scriptlets. Applies from the next document.
zenimages, fonts, css, javascript. true blocks that resource type.
cmdstatus reads the tab's counters, interception and fallback reasons.

The configuration is stored on the session and applied to task tabs. Borrowed tabs are excluded. navigate accepts the same fields and stores them once the navigation starts. See Page presets.

CDP

cdp sends one Chrome DevTools Protocol command to the tab: method, params, and an optional sessionId for a child target. It returns the protocol result unchanged.

Two methods change the bridge's own state. Runtime.disable ends the frame selection of its session, and Page.disable without a session id invalidates the tab's @e references; the next snapshot or navigation re-enables the events.

The daemon uses cdp_attach, cdp_detach, artifact_read, artifact_close and list_targets internally. Do not send them yourself.

Selectors

Every action that takes selector accepts these forms.

FormExampleMatching
CSSbutton[type=submit], css=.card aSelector query. Also searches open shadow roots.
@e reference@e<generation>.<index>A node from the latest snapshot.
role=role=button[name="Submit"]Accessibility role and optional name. The name is a JSON string and matches exactly.
text=text=Sign in, text="Sign in"Rendered text. Unquoted values match a case-insensitive substring; quoted values match exactly.
label=label=EmailThe associated label text or aria-label.
placeholder=, alt=, title=placeholder=SearchThe matching attribute.
testid=testid=searchThe data-testid attribute.
xpath=xpath=//table//aXPath in the current document only. Shadow roots are not traversed.

Append >>nth=0 to take the first match or >>nth=-1 to take the last. Text, CSS and attribute locators traverse open shadow roots. Closed shadow roots stay invisible to them.

Reference lifetime

@e references belong to one document generation. Each snapshot numbers its references under a new generation, a Snowflake ID in base 36. In Chrome, a new snapshot, a frame selection, a new main document (navigation or reload) or a change of the tab's URL invalidates them. A snapshot taken inside a selected frame also expires when that frame navigates, reloads, is removed, or the selection ends. Other iframes loading or navigating leave it valid. In Firefox, references live in the document that produced them; see Firefox.

Errors

Every fault carries code and message. The HTTP status is shown below; a code not listed here returns 502.

CodeHTTPMeaningWhat to do
invalid_request400The body was rejected: an unknown field, a missing action or session, a session name outside the allowed characters, a bad browser, or timeoutMs outside 1 to 120000.Fix the JSON. The message names the field.
invalid_args400An argument is missing, has the wrong type, or is outside its range, including a selector that does not parse. A screenshot or save_as_pdf path is rejected when it exists, when its directory cannot be created or written, or when its file system cannot make hard links.Read the message; it names the action and argument.
unsupported501The action or one of its arguments does not exist in the target browser.Do not retry. Use another action, or a Chrome session.
busy429A capacity limit is full: command slots, 32 tabs per session, 128 sessions per browser, the Firefox upload budget, or two concurrent artifact jobs. The session also moved to the other browser while the command was routed.Reduce concurrency and retry after earlier commands finish.
browser_offline503The target browser has no extension connection, including a session bound to a browser that is not connected.Check omw doctor and the extension, or continue in a new session.
session_browser409The session is bound to the other browser and the request named this one.Drop browser, or close the session and start a new one.
outcome_unknown504The command may have run: the deadline, a cancellation, a transport write or a disconnect cut off the reply, or the page navigated or the debugger detached during the command. The message names the cause.Observe the page or network state before repeating. Never replay a submit, payment or publish blindly.
wait_timeout408The wait condition did not hold before the deadline. wait does not change the page.Send wait again with a longer deadline, or check the condition.
tab_busy409The tab belongs to another session.Use a tab this session holds, or another session.
stale_ref409An @e reference outlived its document.Take a new snapshot.
no_tab502A page action ran before the session had a tab, or after its current tab closed other than by close_tab.Run navigate or find_tab, or pass the tabId of another session tab.
tab_missing502find_tab matched no tab, or the tab the command addresses was closed.Open the page in this session first, or pass active: true to borrow the browser's active tab. For a closed tab, continue in another tab.
restricted_tab502The tab is not a normal, non-incognito HTTP(S) page.Navigate to an HTTP(S) page. Browser-internal pages are not scriptable.
borrowed_tab502The action needs a tab the session created: closing it, or applying a preset to a borrowed tab.Open a task tab with navigate.
element_missing502The selector matched nothing.Check the selector, or take a new snapshot.
element_hidden502The element has no box, so it has no center to click.Scroll it into view or wait for it to render.
element_action_failed502The page refused the operation, such as filling a non-editable element or selecting an option that does not exist.Inspect with get or is and adjust the action.
state_mismatch502check or uncheck left the control in the wrong state.Re-read it with is, then retry or click it instead.
evaluation_failed502evaluate threw, or an internal page script did. In Firefox, also an evaluate whose result cannot be returned, such as a DOM node, Window or BigInt; the code ran.Fix the expression, or return plain data. The message carries the page exception.
frame_missing502frame found no frame for the given selector, id, name or URL.List frames with frame {"cmd":"list"} and select one.
frame_unavailable502The selected frame was replaced, removed or lost its execution context, or the tab's debugger session ended.Later commands use the main frame; select the frame again if the work continues there.
history_missing502history back or forward has no entry in that direction.Read history {"cmd":"list"} first.
request_missing502No network record exists for the request, or it was evicted.Start recording, reproduce, then read list.
request_pending502The response body is not complete yet.Wait for complete: true in list, then retry detail.
request_failed502The request itself failed.Read the error text on the entry.
body_unavailable502Firefox did not keep the response body: a WebSocket, a body evicted by newer bodies, or an interrupted response.Repeat the request with network recording, or read the data from the page.
download_missing502The browser does not list the download.Retry the download.
download_failed502The browser interrupted the download.Read the message and retry.
file_access_required502upload in Chrome needs the extension's "Allow access to file URLs" switch, which is off by default.In chrome://extensions, open the details of oh-my-webbridge, turn on "Allow access to file URLs" and retry.
window_failed502The new window had no tab.Retry window_new.
result_too_large502A result exceeded 32 MiB on the wire, a saved screenshot or PDF exceeded 100 MiB, or a network body exceeded 2 Mi characters in Chrome or 1 MiB in Firefox.Narrow the result: use selector or jpeg for screenshots, and read smaller pieces.
debugger_unavailable502Chrome refused the debugger attach, for example because DevTools is open or policy blocks it.Close DevTools for that tab and retry.
browser_error502The extension reported an error without a code.Read the message, retry once, then report it.
internal502A daemon-side failure, such as encoding a request.Retry. If it persists, restart the daemon.

Contributors

Page history