cockpit browser
Generated reference for cockpit browser, including its syntax, options, results, and constraints from the canonical cockpit CLI source.
This reference is generated from the same canonical source distributed as cockpit CLI help. See Cockpit CLI for concepts and safe operating guidance.
Usage: cockpit browser <command> [options]
Real web browsing with task-scoped in-app browser sessions: navigation, DOM inspection, screenshots, and showing the browser in the right side panel. The browser is driveable, not just viewable — use it to check a live page or verify a web UI change end-to-end even when you have no browser tool of your own.
Within a Cockpit task, this is the first-choice browser route. Use it before generic Browser plugin or IAB routes for local web app verification, visual checks, DOM inspection, screenshots, and side-panel display. Fall back to generic Browser plugin routes only when the user explicitly asks for them or cockpit browser is unavailable after a direct attempt.
cockpit browser identity list --json
cockpit browser identity list --in-use --json
cockpit browser identity get work --json
cockpit browser identity usages work --json
cockpit browser identity create --name work --color "#3B82F6" --json
cockpit browser identity update work --name client-a --color "#8B5CF6" --json
cockpit browser identity clear client-a --cookies --confirm --json
cockpit browser identity remove client-a --replace-with default --confirm --json
cockpit browser identity delete client-a --replace-with default --confirm --json
cockpit browser session list --json
cockpit browser session list --browser-identity work --json
cockpit browser session create --task-id <taskId> --name "Browser" --json
cockpit browser session create --browser-identity work --name "Browser" --json
cockpit browser open <url> --json
cockpit browser open <url> --new-tab --json
cockpit browser open <url> --browser-identity work --json
cockpit browser tabs --session <sessionId> --json
cockpit browser tabs --session <sessionId> --summary --json
cockpit browser tab close <tabId> --json
cockpit browser tab close <tabId> --others --json
cockpit browser tab close --others --session <sessionId> --json
cockpit browser tab recreate <tabId> --json
cockpit browser goto <tabId> <url> --json
cockpit browser reload <tabId> --json
cockpit browser import-session --session <sessionId> --json
cockpit browser import-session --session <sessionId> --profile "Profile 2" --json
cockpit browser import-session --browser-identity work --profile "Profile 2" --json
cockpit browser import-cookies --session <sessionId> --json
cockpit browser import-cookies --session <sessionId> --profile "Profile 2" --json
cockpit browser scroll <tabId> --delta-y 600 --json
cockpit browser scroll-into-view <tabId> --selector "#submit" --json
cockpit browser scroll-into-view <tabId> --role button --name "Submit" --json
cockpit browser snapshot <tabId> --json
cockpit browser snapshot <tabId> --wait-for-selector ".loaded" --timeout 10000 --json
cockpit browser snapshot <tabId> --wait-for-text "Ready" --timeout 10000 --json
cockpit browser evaluate <tabId> --expression "document.title"
cockpit browser evaluate <tabId> --expression "JSON.parse(localStorage.getItem('draft')).body" --json
cockpit browser screenshot <tabId> --output <path> --json
cockpit browser screenshot <tabId> --full-page --output <path> --json
cockpit browser click <tabId> --selector "<selector>" --json
cockpit browser click <tabId> --text "<visible text or accessible name>" --json
cockpit browser click <tabId> --role button --name "公開設定" --json
cockpit browser click <tabId> --role link --name "Docs" --name-match prefix --json
cockpit browser click <tabId> --selector "app-shell >>> #save" --json
cockpit browser click <tabId> --x 320 --y 240 --json
cockpit browser click <tabId> --selector "#save" --wait-for-url "*/complete" --json
cockpit browser click <tabId> --selector "#save" --wait-for-text "Saved" --timeout 10000 --json
cockpit browser click <tabId> --selector "#save" --wait-for-selector-state ".modal:hidden" --json
cockpit browser click <tabId> --selector "#save" --wait-for-response-url "*/api/orders*" --wait-for-response-status "200-299" --json
cockpit browser click <tabId> --selector ".message" --wait-for-new-tab --json
cockpit browser click <tabId> --selector ".message" --double --json
cockpit browser type <tabId> --selector "<selector>" --text "<text>" --json
cockpit browser type <tabId> --role textbox --name "Email" --text "<text>" --json
cockpit browser select <tabId> --selector "#tax-type" --value "102" --json
cockpit browser select <tabId> --selector "#tax-type" --option-text "Corporate tax" --json
cockpit browser dismiss-dialog <tabId> --json
cockpit browser dismiss-dialog <tabId> --button-text "OK" --json
cockpit browser dismiss-dialog <tabId> --reject --json
cockpit browser upload <tabId> --selector "input[type=file]" --path ./build.zip --json
cockpit browser upload <tabId> --selector ".dropzone" --path ./cover.png --path ./trailer.mp4 --json
cockpit browser upload <tabId> --selector "#folder-input" --path ./game-build --json
cockpit browser upload <tabId> --role button --name "Attach a file" --path ./build.zip --json
cockpit browser upload <tabId> --click-selector "button.add-image" --path ./cover.png --json
cockpit browser upload <tabId> --click-role button --click-name "画像を追加" --path ./cover.png --timeout 15000 --json
cockpit browser upload <tabId> --await-chooser --path ./cover.png --json
cockpit browser click <tabId> --selector "button.add-image" --json && cockpit browser upload <tabId> --await-chooser --path ./cover.png --json
cockpit browser paste <tabId> --json
cockpit browser paste <tabId> --selector "<selector>" --json
cockpit browser paste <tabId> --selector "<selector>" --text "<text>" --json
cockpit browser press <tabId> --key Enter --json
cockpit browser press <tabId> --key A --mod Meta --json
cockpit browser press <tabId> --selector "<selector>" --key Enter --json
cockpit browser keydown <tabId> --key Escape --json
cockpit browser keydown <tabId> --selector "<selector>" --key Escape --json
cockpit browser show --session <sessionId> --json
cockpit browser hide --session <sessionId> --json
cockpit browser client --json
cockpit browser diagnostics --json
Typical flow:
- Create or reuse a task-scoped browser session.
- Open the target URL with
cockpit browser open. - Use
scrollfor pages below the first viewport. - Use
snapshotto inspect DOM text, element roles, and accessible names. - Use
screenshotwhen the user wants a visual check. - Use
showto display the browser in Cockpit's right side panel so the user can watch.
Inside a Cockpit task, open, tabs, show, hide, and session commands use the calling task automatically when neither --task-id nor --session is supplied. open reuses that task's most recently used session and selected tab. Each task has one assigned Browser Identity. Sessions in that Identity share its persistent Electron partition, while cookies, cache, localStorage, permissions, proxy authentication, and other browser state are isolated from every other Identity. Tasks without an explicit assignment use the Default Identity, which preserves the legacy persist:in-app-browser profile and existing sign-ins.
Use --browser-identity <name|id|default> to assert the assigned Identity when resolving or creating a session. It does not change a task's assignment. A task-scoped command rejects another Identity, even when a session or tab ID from that Identity is supplied, and the error points to the assignment command. Change an existing task with cockpit task browser-identity <taskId> <name|id|default>, or change the calling task with cockpit task browser-identity <name|id|default>.
cockpit browser identity manages Identities from the CLI. list returns usage counts and accepts --filter all|in-use|unused, --in-use, or --unused; both get and usages include Identity metadata, usage counts, and the referencing tasks, Autoruns, and browser sessions. create accepts --name and optional --color; update accepts a name or id plus --name and/or --color.
Clearing persistent browser data and removing an Identity both require --confirm. clear accepts exactly one of --all, --cookies, --cache, or --scope all|cookies|cache, and closes that Identity's live sessions before clearing the selected data. remove and its delete alias always clear all persistent data. The Default Identity cannot be removed. An Identity assigned to active tasks or Autoruns cannot be removed unless --replace-with <name|id|default> is supplied; replacement reassigns every referencing task and Autorun before removal and rolls those assignments back if removal fails. Without a replacement, references held only by completed tasks return to Default.
Each tab has one canonical page instance shared by the user and agent. Switching tasks, tabs, or right-side panels detaches that page from the window without reloading it, preserving unsaved form input, scroll position, SPA state, and popup/OAuth context in memory. Popup and OAuth windows inherit the parent Identity partition. tab close <tabId> closes one tab; add --others to keep that tab and close every other tab in its session. Omit the tab ID with --others to keep the selected tab. A page-side window.close() also removes its Cockpit tab. tabs --summary adds selected and a whitespace-normalized preview of the first 300 body-text characters to each tab. Every tab also includes health: loaded (whether the tab currently has a page renderer), loading, loadingDurationMs (elapsed milliseconds while Chromium still reports loading, otherwise null), rendererResponsive (whether the page renderer answered a short JavaScript ping), and lastNavigationError (the last main-frame load failure, or null). After app restart, unopened tabs stay unloaded: loaded is false and rendererResponsive is false because there is no renderer yet. That is not a stuck renderer and is not a tab recreate signal. The tab is loaded on first use — when it becomes the selected tab, when show displays it, or when any command targets its tab ID. Use health on a loaded tab (loaded: true) to tell a slow site, a navigation error, and a stuck renderer apart. snapshot --wait-for-selector / --wait-for-text and click postcondition timeouts return ok:false with the same health object in details instead of only DOM wait timed out. tab recreate <tabId> destroys a loaded tab's renderer and creates a new one in the same session and Browser Identity, keeping the tab ID and current URL. Browser sessions and navigation history survive task completion, resume, and app restart; Chromium page state such as form values and scroll position is restored on a best-effort basis after restart and is encrypted at rest when the operating system credential store is available. Closing a browser session or removing its task discards only its saved session and tab metadata, not the Identity's persistent browser data.
When the right-side browser has been shown, navigation, click, type, select, upload, paste, press, keydown, scroll, snapshot, reload, and screenshot commands keep operating on that page instance while the panel is visible or hidden. This preserves in-memory SPA state and makes CLI changes visible when the panel is shown again. open reuses the selected tab by default; add --new-tab when the current page contains unsaved input or other state that must be preserved. click sends trusted pointer input (see the synthetic fallback below for the one exception) and can target a selector, visible text, an accessible name with --role / --name, or viewport coordinates. Selector and text clicks wait for the target to be enabled and positionally stable after scrolling, exclude disabled, aria-disabled="true", and inert targets, and reject points covered by another element. click, type, fill, select, press, and keydown scroll their target into view on both axes — through every scrollable ancestor and the window — before hit testing, so a horizontal scroll position carried over from the previous page does not leave a left-edge or right-edge control unreachable. When a selector resolves to a child such as span or p, the click keeps that child's hit point but reports and activates its nearest clickable anchor, button, role, label, summary, or onclick ancestor. When the element under the chosen point does not belong to the target or that ancestor — a large card link whose centre is a <p>, or a transparent region — the click retries at the padding-box top-left, centre-left, centre-right, and first text-node points, preferring a point that lands inside the target itself and otherwise accepting one inside its clickable ancestor. The clickable ancestor is never body or html, so a page-level delegated onclick handler does not make every element count as a hit. If no point reaches the target and every candidate point lands on a transparent, text-free, non-interactive layer, the click is dispatched to the resolved clickable ancestor with untrusted DOM events; the response then reports dispatch: "synthetic" and hit is the element that was dispatched to, whereas a normal trusted pointer click reports dispatch: "trusted". A target covered by an unrelated opaque or interactive element — a modal, a consent banner, a loading veil — is still rejected rather than clicked. Rejection fails the command with browser_click_target_unreachable and details carrying the hit element (selector, tag, id, class, text), the resolved clickable ancestor, every candidatePoints entry (kind, x, y, matches, hit), the scroll state (windowScrollX, windowScrollY, and the nearest scrollable ancestor's scroller, scrollerScrollLeft, scrollerScrollTop), and syntheticEligible. Text clicks resolve in a fixed priority order and stop at the first tier that matches: exact visible text, exact accessible name, partial visible text, partial accessible name. The response returns matchCount plus textMatch (exact, name-exact, partial, or name-partial) so ambiguous targets and the tier that matched are both detectable. The accessible-name tiers make an icon-only button with aria-label clickable by its label even though its visible text is only the icon. Add --double to dispatch two trusted clicks and a browser dblclick sequence.
evaluate runs JavaScript in the tab's main frame only; subframes are never reached. Use it to read values that are not rendered in the DOM, such as window.__NEXT_DATA__, a framework store, a property other than input.value, or localStorage. The source is injected as the body of an async function rather than evaluated from a string, so it also runs on pages whose Content Security Policy forbids eval, and await works at the top level. A single expression returns its value; a multi-line script returns its last expression, or whatever it returns explicitly. A script that ends in neither — a trailing declaration or loop — fails with evaluation_error asking for an explicit return instead of reporting an empty result as success, as does a trailing expression spread over more than 200 lines or statements; add an explicit return for those. The evaluation carries no user gesture, a returned Promise is awaited, and the result must be JSON-serializable. Pass the source with --expression, --expression-file <path>, or --stdin, so a multi-line script never passes through shell quoting. A successful call returns {"ok":true,"value":<result>}, with undefined reported as null, so a side-effect expression such as localStorage.setItem(...) succeeds; --json prints only the value to stdout for piping, exactly as the page serialized it, so numbers, dates, and deep objects are never re-serialized on the way out and read the same on every platform; PowerShell adds a trailing line terminator. Without --json, the result is wrapped in the local envelope {"ok":true,"instance":"<instance>","data":{...}} — every browser envelope, ok:true and ok:false alike, carries instance in both the sh and PowerShell launchers; only the raw --json value does not. An expression that throws returns {"ok":false,"error":"evaluation_error","name":...,"message":...} without a stack, a DOM node, function, symbol, or cyclic object returns {"ok":false,"error":"not_serializable","type":...}, and exceeding the timeout returns {"ok":false,"error":"timeout"}; each of those exits with status 1. --timeout defaults to 10000 milliseconds and is capped at 60000. A result whose JSON exceeds 1 MB is cut at that many bytes and returned as valueText with truncated:true; because that text is no longer valid JSON, --json refuses it with result_truncated and exits 1, so read the envelope instead.
Every DOM locator — snapshot, click, type, fill, select, upload, paste, press, keydown, scroll-into-view, and the --wait-for-selector / --wait-for-selector-state conditions — traverses open shadow roots. A plain CSS selector is matched in the top-level document first and then in every open shadow root, in document order, so existing selectors keep resolving to the same element. Write host >>> inner to pin a path explicitly across a shadow boundary; each >>> step searches inside the previous step's shadow root. Selectors reported back by snapshot and by click results use the same >>> form, so they can be passed straight back to any command. Closed shadow roots are not reachable: the page holds the only reference to them, and Cockpit does not patch attachShadow to capture it, because that would change page behavior. Use coordinate clicks for content inside a closed root.
--role and --name select an element by its implicit or explicit ARIA role and its accessible name instead of a CSS path. The accessible name is computed from aria-labelledby, aria-label, the associated or wrapping <label>, alt, the button value, the element's text content, and title, in that order. Text content follows the flat tree: an element's own open shadow root replaces its light children, <slot> contributes its assigned nodes or its fallback content, and aria-hidden subtrees are skipped, so slotted text is counted once. --name-match chooses exact (default), prefix, or contains; matching is whitespace-normalized and case-insensitive. Add --selector alongside them to restrict the search to the descendants of that selector. Elements nested inside another match are preferred, and only visible elements are eligible. When nothing matches, the command fails with browser_target_not_found; when more than one element matches, it fails with browser_target_ambiguous; when every match is hidden, it fails with browser_target_not_visible. Each of those errors returns the candidate role, name, and selector values in details.candidates so the next attempt can be narrowed.
Each subcommand accepts a fixed set of options, and nested commands are checked against their own action rather than the union of their siblings, so browser tab recreate --others, browser session list --name, and browser identity list --confirm are rejected too. An option that a command does not implement — snapshot --deep, click --force, a misspelling, or an option that belongs to another command — fails with invalid_arguments and lists the unknown and allowed options in details, instead of being silently ignored.
Click postconditions are optional. --wait-for-url and --wait-for-response-url match a URL substring, or the entire URL when the pattern contains *. --wait-for-text waits for visible body text. --wait-for-selector-state accepts <selector>:attached, <selector>:detached, <selector>:visible, or <selector>:hidden; the state suffix is parsed from the final colon, so selectors may contain colons. --wait-for-new-tab waits for a popup or new tab in the same session. Every click response includes newTabId when a new tab is observed, even without the wait flag. --wait-for-response-status accepts one status such as 204 or an inclusive range such as 200-299, defaults to 200-299, and requires --wait-for-response-url. --timeout defaults to 5000 milliseconds and is capped at 30000 milliseconds. Multiple postconditions are ANDed, and an unmet condition, timeout, or status mismatch returns ok:false. Response monitoring starts before the trusted mousePressed event. A successful matched response returns only its masked url, method, and status; query values and the hash are replaced with ***. Request and response bodies, headers, and payloads are never returned. Every click observes the resulting click event and URL, DOM, and form-value changes. DOM observation, form-value collection, and --wait-for-text cover open shadow roots as well as the light DOM, so a component that only re-renders its own shadow content still reports changed:true with a dom signal. Shadow text is read as rendered text: display:none, visibility:hidden, hidden, <style>, and <script> content never satisfies a text wait, whether it sits inside the component or on the host or one of its ancestors, so a pre-rendered hidden status node only matches once it is shown. <slot> contributes the nodes assigned to it, or its fallback content only while it is empty, so text a component receives from its parent is matched and the fallback of a filled slot is not. Shadow roots attached after the command started are not observed. The response includes changed and changeSignals; a focus-only change leaves changed:false, so a no-op submission is not reported as a verified effect. When the top-level document can observe the target, the response also includes eventDispatched and inputDelivered. When no pointer event reaches the page at all, the command returns ok:false with code browser_event_not_dispatched instead of reporting success. When pointer events reached the page but no click event was observed — for example a capture listener stopped propagation, or the target was disabled or detached mid-click — the command returns ok:true with eventDispatched:false, inputDelivered:true, and a warning; the click may already have taken effect, so verify the page state instead of retrying to avoid a duplicate click. Embedded-frame targets and pages where observation cannot start omit both fields rather than reporting a false delivery failure. Treat changed:false as unverified and inspect the intended outcome or repeat with an explicit postcondition.
click, type, fill, select, upload, paste, press, keydown, and scroll-into-view all accept the same locator: --selector, or --role and --name, or both together. click, type, select, upload, paste, press, keydown, and the HTML fallback of dismiss-dialog automatically select the specified tab before dispatching input, including when the tab was in the background. When an input command fails, the previously selected tab is restored; the selection stays on the target tab only after success. Parked tabs (not shown in the side panel) receive click, type, fill, press, and the HTML fallback of dismiss-dialog through CDP Input.dispatchMouseEvent / keyboard input, with focus emulation for the duration of the command, without showing a window, switching macOS Spaces, or focusing WebContents. Visible side-panel tabs still receive pointer focus for click and the HTML dismiss-dialog fallback; other input commands do not focus the owner window. type replaces the selected field's value using trusted keyboard input, falls back to the native value setter when trusted clearing is intercepted, and verifies the final value. select requires exactly one of --value or --option-text, uses the native select setter, and dispatches bubbling input and change events before verifying the selected option so dependent selects can update. scroll reports the actual movement and falls back to a trusted mouse wheel event when JavaScript scrolling has no effect. scroll-into-view centers a selector through its scrollable ancestors and returns its final bounds. dismiss-dialog first accepts a pending JavaScript dialog, then falls back to a visible HTML dialog, role=dialog, aria-modal, Bootstrap modal, or jQuery UI dialog. It chooses a conventional confirmation button by default; use --button-text for an exact label or --reject for a negative action. The HTML fallback dispatches its button click with the same delivery verification as click and reports eventDispatched, inputDelivered, and warning the same way. upload sets files through Chrome DevTools Protocol without opening the operating system file picker. Its selector can target an input[type=file] or a containing dropzone; containing elements are searched for a file input. Repeat --path for a multiple input. For a webkitdirectory input, pass one directory path and its files are uploaded recursively with relative paths. Every upload response identifies the input that actually received the files in target — its shadow-aware selector, id, name, accept, multiple, directory, attached, visible, and the nearest label (accessible name or the text of the surrounding button or label) — so a wrong input is visible before the page is submitted. Visibility here means the input is connected and has a layout box; an input hidden only by opacity:0 or moved off-screen, the usual pattern under a custom upload button, still counts as visible. When the selector matches no file input the command fails with browser_file_input_not_found, and the message notes that the page may open a native file chooser instead of rendering an input. When it matches exactly one file input, that input receives the files even when it is hidden or detached — display:none inputs behind a custom button are the common case — and a hidden match adds a warning naming the input, so a leftover picker from another upload flow (such as a thumbnail input that stays in the DOM after the body editor removed its own) is visible in the response rather than silently assumed to be right. When more than one file input matches and either none or several are visible, it fails with browser_file_input_ambiguous. Both errors list every matched input in details.candidates. When exactly one of several matches is visible, that input is used and the response carries candidates plus a warning. Pages such as note.com's body editor create a transient <input type=file> inside the click handler, open the native chooser, and remove the input again, so no selector can reach it. For those, --click-selector, --click-text, --click-role / --click-name / --click-name-match, or --click-x / --click-y — the same locator forms as click — clicks the control that opens the chooser while the chooser dialog is intercepted through CDP, then sets the files on the input that requested it, so no operating system dialog appears. --await-chooser instead accepts the chooser opened by the preceding click command on the same tab: every click intercepts a file chooser its target opens (no operating system dialog appears) and remembers it for up to 60 seconds — only the most recent click's chooser is kept, and a navigation or a click that opens no chooser discards it — so click followed by upload --await-chooser delivers the files to the input that requested them. When no chooser is remembered, --await-chooser arms the interception and waits for the next chooser the page opens, for cases where the trigger is dispatched by other means. Both wait --timeout milliseconds (default 10000, capped at 120000) and fail with browser_file_chooser_timeout when no chooser opens; details carries timeoutMs and the click locator. A chooser that is not backed by an input element — a page calling showOpenFilePicker — fails immediately with browser_file_chooser_unsupported and its mode in details, because CDP cannot deliver files to it. Chooser modes are mutually exclusive with each other and with --selector, --role, and --name; a chooser opened in selectSingle mode rejects more than one --path. The response then adds chooser (intercepted:true, mode, and trigger of click or await), the full click result when a click was dispatched, and target describing the intercepted input, whose selector is omitted when the input was already removed from the document. type also accepts a contenteditable host or any element inside one, including CodeMirror and ProseMirror editors; it inserts text through the same trusted input path, falls back to a beforeinput/input insertion for editors that intercept trusted clearing, and verifies the resulting text so an undelivered edit returns ok:false instead of a false success. A contenteditable fill always replaces the whole editing host: a selector pointing at a descendant such as one paragraph clears and rewrites the entire editor, and the response reports the resolved host plus hostReplaced:true so that widening is visible. Target a narrower editing host when only part of a document should change. paste performs a real clipboard paste: the page receives a genuine paste event with clipboardData, so rich-text editors handle it themselves. It pastes the current system clipboard by default; --text pastes explicit content, then restores every previous representation — text, HTML, RTF, image, or, when the clipboard held none of them, by clearing it — and leaves anything copied during the paste untouched. --selector resolves the same targets as type, including an element inside a contenteditable host, and focuses it before dispatch; otherwise the focused element receives the paste. The response reports pasteEventDispatched, changed, changeSignals, verified, textLength, and clipboardKind. When the system clipboard holds no text representation but does hold an image — a screenshot, or a PNG or TIFF copied from another app — clipboardKind is image, the page receives the image in clipboardData.files and clipboardData.items, and the response adds imageBytes (the PNG size) and imageReceived (whether a paste listener in the page saw an image item). Editors such as note.com then insert the image themselves. An image paste that no paste listener received (imageReceived:false) falls back from the trusted keyboard paste to the native paste command and then to a synthetic paste event carrying the PNG, which counts as received only when the page handled it (called preventDefault); when no attempt reached a handler the command returns ok:false. Image pastes are verified by the dom signal only, and only an inserted img, picture, canvas, svg, or video element (or one containing such an element, or an image src change) counts; unrelated attribute or text mutations do not. The observer waits up to 2 seconds for that element, returning as soon as it appears. When the page received the image but no image element appeared in that window — an editor that uploads first and inserts later — the response is ok:true with verified:false and a warning; inspect the page before repeating the paste. Text, HTML, and RTF clipboards behave exactly as before, and --text still pastes text even when an image is also on the clipboard. Success requires an observed change: target when the focused field's own text changed, or dom when a paste event was followed by the pasted text appearing in the document — the shape editors such as Monaco, Ace, and CodeMirror take, where a hidden textarea keeps focus and the content is rendered elsewhere. The dom signal matches the clipboard content itself — its head, its tail, or its longest line, and by counting occurrences so text already present on the page is still detected — so a virtualized editor that renders only the visible tail of a long paste counts as delivered, while a page that rejects the paste and merely renders something else, such as a blocked-paste notice or an unrelated live update, does not. A paste event that changes nothing, delivery of clipboard content other than the requested --text, or no delivery at all all return ok:false. When the target cannot be observed from the top document — a focused frame such as an editor's input iframe — the response is ok:true with verified:false and a warning, and the paste is never re-dispatched; check the page state instead of repeating it. press --key v --mod Meta (or --mod Control) runs the same verified paste path. press sends a trusted keydown and keyup pair; keydown sends only the keydown event. Both accept --selector to focus and verify a target before dispatch, support Enter, Tab, Escape, navigation keys, function keys, printable keys, and shortcuts through --mod Alt|Control|Meta|Shift. Combine modifiers with + or ,, such as --mod Meta+Shift.Shortcuts for a, c, and x with the platform accelerator (Meta on macOS, Control elsewhere) are dispatched as the browser's selectAll, copy, and cut editing commands so they take effect instead of only firing a keydown; the other modifier keeps its native meaning. keydown --key v stays a plain key event, so use paste or press for clipboard content. Successful action responses include verification metadata such as the fill value, click hit element, scroll delta, or active element. snapshot can wait for a selector or visible text before reading a client-rendered page. Its links, buttons, and inputs entries include the element role and accessibleName next to the shadow-aware selector, and cover elements inside open shadow roots; shadowRoots reports how many open shadow roots the page has. text stays the rendered text of the document body, so use the element entries to read shadow content field by field. screenshot --full-page captures the document beyond the current viewport; --width and --height set the hidden browser viewport when no visible browser is attached. A window-scrolling page is captured without scrolling, in clips of at most 4096 CSS px stitched top to bottom, so tall pages no longer wrap back to the top past the renderer's 16384-px limit. When the document itself does not scroll (its scroll height is within 16 px of the viewport) but an inner container does — an editor such as note.com's whose body lives in a fixed-height overflow:auto element, or a page whose html is overflow:hidden and whose body scrolls — the largest scrollable element (the one with the greatest scrollHeight above its clientHeight; body counts when the root element does not delegate scrolling to it) is scrolled step by step and its frames are stitched instead. Each frame is the part of the container's padding box (borders excluded) that lies inside the viewport, so a container taller than the viewport is captured in viewport-sized slices, and the container is scrolled into view first when it starts off-screen. Afterwards the container's scroll position, and that of every ancestor moved to bring it into view, is restored. When the document does scroll, the window capture is used even if an inner element is taller; the response then carries a warning naming that container and its scrollHeight, since its hidden rows are not in the image. A frame identical to the previous one is never stitched twice: the capture stops there and reports it. The response adds documentHeight (the CSS height of the scrolled range), capturedHeight (how much of it the image covers), scrolledElement (window or the selector of the stitched container), and a warning whenever capturedHeight is below documentHeight — the 20000-px size cap, a repeated frame, an exhausted scroll range (rows at the bottom of a container that can never enter the viewport, for example under a border that overflows the page), or a container that left the viewport. width and height stay the image dimensions in device pixels; a stitched container image is as wide as its padding box. Remaining limits: only the single largest container is stitched, so a page whose long content is split across several inner scrollers, or nested inside another scroller, is captured only for that one element; sticky or fixed elements inside a stitched container repeat in every frame; and a uniform region taller than one frame counts as a repeated frame and stops the capture with a warning. --timeout on snapshot and click bounds that DOM or postcondition wait only; it does not abort an in-flight page load.
On macOS, prefer import-session to transfer the selected tab's sign-in state from Chrome. It imports cookies for the tab's registrable domain and merges localStorage entries for the tab's exact origin into the selected Browser Identity partition, then reloads the page. It never imports data for unrelated domains, origins, or Identities. --browser-identity selects the AGI Cockpit destination Identity. The separate --profile option selects the source Chrome profile directory; it does not select a Browser Identity. By default Chrome's last-used profile is the source. The first import can show a macOS Keychain permission dialog for Chrome Safe Storage. The structured result identifies the selected Chrome profile, origin, cookie and localStorage counts, unsupported storage types, warning, and next step.
To verify a public result without changing the signed-in browser state, create a logged-out Identity and assign it to the calling task before opening a separate session:
cockpit browser identity create --name logged-out-check
cockpit task browser-identity logged-out-check
cockpit browser session create --browser-identity logged-out-check --name "Public check" --json
cockpit browser open <url> --browser-identity logged-out-check --json
import-session does not transfer sessionStorage, IndexedDB, browser-extension state, or device-bound authentication such as DBSC. sessionStorage is tied to a Chrome tab's browsing context and cannot be safely restored as origin-wide state. If the site remains signed out, sign in once inside the in-app browser; the selected Browser Identity keeps that login for later assigned tasks and app restarts.
import-cookies remains available for backward compatibility and imports only Chrome cookies for the selected tab's registrable domain. It does not transfer localStorage, sessionStorage, or IndexedDB, so cookie import alone may leave an SPA signed out even when server-side redirects succeed. Use import-session when the goal is to reuse an existing Chrome login.
Passkey and WebAuthn sign-in uses the platform authenticator of the operating system. On macOS, packaged builds signed with the WebAuthn keychain entitlement show the Touch ID prompt for the tab the user is looking at; development builds and builds without that entitlement have no platform authenticator. Cockpit's Touch ID authenticator can use only passkeys registered from the in-app browser. It cannot use passkeys previously registered in Safari, Chrome, or iCloud Keychain. Register a new passkey while using the in-app browser, sign in with a password, or finish signing in with Chrome and run cockpit browser import-session. On Windows, Windows Hello is provided by the operating system. On Linux there is no platform authenticator, so use a roaming security key or a password; cockpit browser import-session reads Chrome on macOS only, so a sign-in finished in the system browser cannot be carried back there. When more than one passkey matches, Cockpit asks which account to use instead of cancelling the request.
cockpit browser diagnostics reports why a passkey prompt did not appear. platformAuthenticator gives the authenticator kind, its state, whether it is available, whether a sign-in finished in the system browser can be imported back (systemBrowserImportSupported, macOS only), and a human-readable reason. webAuthn lists the recent WebAuthn attempts of the calling task's Browser Identity with the operation, relying party, outcome, and the notice shown for it, including attempts that never received an answer. Attempts made under another Identity are not returned. A get request that fails with NotAllowedError in under 500 ms without authenticator account selection is reported with notice code no-matching-credential when Cockpit's Touch ID authenticator has no matching passkey. A page that requests a platform passkey while no platform authenticator is available no longer waits silently: the browser panel shows the reason, and the same reason is returned here. Passkey autofill (mediation: "conditional") stays unreported, because such a request legitimately waits for the user. A request that a roaming security key could still answer is reported as information rather than as a failure, and a request that explicitly targets a security key is not reported at all.
Do not use HTML Mode for browser navigation. HTML Mode is for agent-generated HTML surfaces.