Skip to content

Embedded browser

The embedded browser pane lets you point an isolated Chromium webview at any URL inside the task detail window, then capture the rendered frame plus annotations and submit it to the active agent as a multi-modal prompt. Useful for visual regression work, “make this match the design” loops, and DOM-level bug hunting where a screenshot beats a paragraph of description.

A task window with the Browser pane open beside the agent's terminal: an address bar on the project's local dev server, the page it serves loaded beneath, zoom and Close browser controls above, and Draw, Inspect, and a note field for the agent below. v0.46.0 The real app on a sample install. The projects and terminals are recordings, connected to nothing, so click anything.

  1. Open a task with an active agent session.
  2. Click the Browser pill in the task detail window’s header (mutually exclusive with Changes).
  3. The first time you open it for a task, an empty-state prompt asks for a URL. Pick a quick-pick (localhost:3000, 5173, 4321, 8080) or type one.

The URL bar supports back, forward, reload, pin to project default, and pin to task override. Per-task URLs persist in .kangentic/browser-urls.json. The project default lives in AppConfig.browser.defaultUrl. Resolution rule: task override > project default > empty state.

Every successful navigation quietly updates that task’s own URL, so reopening a task lands you where you left it. The project default is never set automatically. It changes only when you ask for it, through Save as project default in the pane or Settings > Browser > Default URL. Tasks lease their own dev-server ports, so inheriting a sibling task’s URL would be a collision rather than a convenience.

Since v0.30.0 the Browser pane is also a detachable surface: a pop-out button moves it into its own OS-level window (one per task), which remembers its size, position, and monitor between openings. The same engine detaches the Changes panel, a single file’s diff, the Usage Stats, and the Agent Monitor. An agent can pop the pane out and dock it again too, to check a layout at real screen pixels; see The viewport an agent renders at. A size an agent applies is never saved as your window size, since those bounds are shared by every task’s pop-out.

The pane has two verbs, and the difference is what happens to the page.

The Browser pill only hides. The page stays loaded, so you get it back exactly as you left it - scroll position, form state, and whatever the app kept in memory - and an agent driving the pane is never interrupted by you reclaiming the space. Opening the Changes panel over it, and closing the task’s window while its agent is still running, both keep it the same way.

Close browser is the discard. It ends the page and frees its renderer process, which is real memory: every loaded page is a full Chromium renderer, and a heavy app holds more. Reach it in two places:

  • the red-tinted Close browser button at the far left of the pane’s navigation bar, ahead of Back
  • the Close browser item in the task menu, which is how you close a pane you cannot see because it is hidden

Either way, the task’s URL is remembered, so Show reopens the same address on a fresh page. What does not survive is per-page state: anything the site kept in sessionStorage or in memory is gone, the way it would be if you had closed a browser tab. Cookies and localStorage persist in the task’s cookie jar.

Two indicators say a page is loaded and costing memory, in any state - showing, hidden, or with its window closed:

  • a green dot on the Browser pill in the task detail header
  • a green globe at the right end of the task card’s title row on the board

Neither says whether an agent is driving the page right now; that is the pane’s own accent border and “Agent typing here” marker.

Press Ctrl+D / Cmd+D to enable Draw mode. Free-draw strokes appear on a transparent overlay above the webview. Pointer events route to the canvas while drawing so the page below doesn’t intercept them.

Press Ctrl+I / Cmd+I to enter Inspect mode - a red highlight tracks the element under your cursor. Click an element to capture a structured fingerprint: selector, ARIA role, ARIA name, data-testid, classes, ancestor chain, computed styles, and outerHTML. The picked element then keeps a persistent blue overlay that follows scroll and resize until you re-enter Inspect or press Escape.

The browser pane has Chrome-style zoom controls. Three ways to use them:

  • Toolbar pill - the URL bar has a - / % / + group next to the Pin button. Click - or + to step zoom; the middle pill shows the current percentage.
  • Keyboard - Ctrl+= / Cmd+= to zoom in (the plus key works too), Ctrl+- / Cmd+- to zoom out, Ctrl+0 / Cmd+0 to reset to 100%. Shortcuts are gated on the browser pane being hovered or focused, so they don’t fight other dialogs.
  • Ctrl+Wheel - scroll the wheel with Ctrl held inside the webview (Ctrl on every platform). The percentage pill follows.

Zoom snaps to a fixed ladder from 25% to 500%, matching Chrome’s rungs.

Each pane keeps its own zoom (since v0.44.0). Chromium’s default stores zoom per site, so zooming one task’s pane used to change every pane, pop-out, and agent surface on the same dev server, and a navigation to another site dropped the zoom while the pill still showed it. Now a zoom stays with the pane that set it, across navigations.

While an agent holds a viewport override on the pane, the zoom pill is replaced by the viewport chip, because the fit that puts the whole layout on screen is set from the requested size and a zoom step would move the viewport out from under the number the chip reports. Reset the override and the pill comes back with your own zoom.

Press Enter in the note field, or click Send, to submit. Kangentic:

  1. Composites the webview frame and your strokes into a single PNG written to <projectRoot>/.kangentic/sessions/<sessionId>/captures/capture-<timestamp>.png.
  2. Builds an XML-tagged prompt: a top-level Screenshot: @<path> for bare-token @-parsers (Claude Code, Gemini CLI), then a <browser_context> envelope with <url>, optional <picked_element>, and any selected text.
  3. Submits via the paste engine to the active agent’s PTY.

Captures live under the session directory, so they’re cleaned up automatically when the task moves to To Do, Done, or is deleted.

The pane works in the other direction too: agents can drive it themselves. Every spawned session gets the kangentic_browser_* MCP tools, which control the pane over the Chrome DevTools Protocol: open, close, and list surfaces; navigate and step through history; screenshot, query the DOM, read the console, list network requests, and wait; click, hover, type, press keys, scroll, drag, choose a <select> option, drop files, and answer a JavaScript dialog; set the viewport, pop the pane out, and dock it again; and evaluate JavaScript when that is switched on. An agent can open its own task’s pane rather than asking you to click the Browser pill, and put it away again when it is done. That closes the loop on frontend work without leaving the task: the agent edits code, points the pane at your dev server, and looks at the rendered result - or clicks through the flow it just built to verify it.

An agent targets a surface by handle (sessionId) or by taskId, or omits both, in which case it gets only its own task’s surface. Since v0.38.0 that implicit resolution never falls through to a sibling task’s pane, however many are open in the project: the fall-through was observed navigating another task’s signed-in app to an identity-provider URL, and an agent reaching a page it was never pointed at is a worse outcome than a refusal it can read. Only a caller with no task at all - a human-driven client, or the Command Terminal - uses the project-wide rule. Panes are scoped to the agent’s own project: the family takes no project selector at all, so there is no path to another project’s pane.

The whole family is gated by the Agent Browser settings tab, a per-machine security policy: a master switch (off unregisters the tools entirely), plus sub-gates for interaction (everything that acts on the page, from a click to a viewport change - off means observe-only), navigation (anything that loads or reloads a page, including opening a pane and popping it out), arbitrary JavaScript eval (off by default), and restricting navigation to localhost.

Settings on the Agent Browser tab: one card with the browser automation switch and the actions agents get: interaction, navigation with a localhost restriction under it, and eval. v0.46.0 The real app on a sample install. The projects and terminals are recordings, connected to nothing, so click anything.

An agent can also see, but not change, whether you can watch it work: every surface reports a visibility of showing, hidden, parked, or offscreen. All four are driveable - the field says whether the page is on your screen, not whether the agent may act on it.

See the Tool reference for every tool, Settings for the toggles, and the Configuration reference for the browserAutomation.* keys.

A docked pane is only as wide as the task window’s split leaves it, which in practice sits below every desktop breakpoint. An agent that checks a responsive layout there measures the mobile rendering and reports it as the desktop one, so since v0.43.0 it can choose the viewport instead of inheriting one.

Two mechanisms, and the difference that matters is what each costs the page. Set viewport overrides the size the page lays out against, in place: nothing reloads, so a signed-in flow and everything the page holds in memory survive. Pop out moves the pane into its own OS window, which buys real screen pixels and a window you can drag, and reloads the page to get there. Dock puts it back the same way. An agent midway through a flow uses the first; one that wants true 1:1 pixels uses the second.

You can see and undo an override. While one is set, the pane’s toolbar replaces its zoom pill with a viewport chip naming the size the page actually measured, with a reset control beside it, so a page rendering at a width the pane cannot be is never unexplained. Resetting restores your own zoom along with the size. An override otherwise lasts until the agent clears it, its session ends, or the pane closes.

A pane asked for a size larger than it is gets zoomed out to fit, so you see the whole layout rather than its top-left corner. A popped-out window is instead capped by the display it is on, un-maximized first if it has to be, and kept inside that display’s work area. Either way the number the agent gets back is measured from the page rather than echoed from the request.

An agent’s screenshot of a fitted pane shows that whole layout at the pane’s own resolution, not at the size the agent asked for. The limit is Chromium’s. A screenshot of a pane holds no more pixels than the pane has, and before v0.43.1 asking for more came back as the page repeated in tiles. For detail, the agent captures one element at up to 1:1 or pops the pane out. The Tool reference has the numbers.

A task has exactly one browser. Normally that is the pane you can see. When no pane can be mounted, the same one surface comes up offscreen instead, and both forms answer to the same tools and the same handle rules.

Offscreen is a fallback rather than a choice, and there is only one thing that causes it: the board window layer renders only the open project’s tasks, so a task in a project you are not looking at has no window to mount a pane in. An agent working there still gets a driveable browser, and its response says the surface is offscreen so it can tell you that nobody is watching. The task card’s globe and the task detail window’s Browser pill light up for it exactly as they do for a pane, and the task menu’s Close browser destroys it, so it is never a browser you cannot see or reach. Open the Browser pill and the pane mounts at that surface’s current URL and the offscreen one goes away; the page reloads in the move, so per-page state is lost while cookies and localStorage survive.

Drives are serialized per surface. Only one caller drives a given browser at a time, and the rest queue. A drive that cannot get its turn within 30 seconds refuses with an actionable error rather than hanging, and every drive records who made it, so contention is visible instead of mysterious.

Until v0.43.0 an agent could also ask for a private lane of its own, with isolated: true on kangentic_browser_open_pane, and that argument is gone. The case for it was concurrency: several agents under one task resolve to the same browser and would otherwise interleave navigations, clicks, and screenshots while each believed it had exclusive control. That concurrency was never real, because parallel callers already queue behind one guest, so four lanes bought a queue with four heads rather than four workers. The cost was real. An offscreen surface wrote nothing the card globe or the Browser pill read, so nothing on screen said it existed, you could not close it, and none of the supervision the pane carries reached it. It was reported from live use: a user closed the Browser pane, and the agent then ran a whole verification in a lane with no browser anywhere on screen.

Serialization fixes interleaving, not intent. It cannot stop one agent navigating away from the page another is midway through verifying, and there is now deliberately no separate surface to take instead. Concurrent workers on one task share the queue and should coordinate rather than assume exclusive control.

A browser an agent is using belongs to the agent, not to a piece of UI. Closing a task’s detail window used to destroy its browser guest outright, leaving the agent with no pane and no way to reopen one.

Since v0.38.0 that close parks the window instead: when the task has a loaded page and a running agent, closing hides the window in place rather than tearing it down. Reopen the task and it un-parks - the same page, the same tab, nothing reloaded, per-page state intact. The park ends on its own once there is nothing left to keep: the agent’s session stops, or the page goes away. The same holds while a project is backgrounded, so an agent can keep driving its pane without its project being the one on screen.

When a page genuinely does go away - a hard reload, a window that could not be kept, the task leaving the board - and the task still has a live agent session, Kangentic moves it offscreen at the same URL under the same task. The agent that made no assumption about which surface it was on keeps working; one holding the old surface’s handle is told plainly that its tab is gone and which surface replaced it, rather than being silently pointed at a different page. Reopen that task’s Browser pane and the offscreen surface stands down, because the visible pane is the better answer whenever it exists.

Close browser stands nothing back up. You closed the page to get its memory back, so nothing re-spends it behind you; the agent’s next call is told the user closed the browser, and it may open a new one.

While an agent drives the pane you are watching

Section titled “While an agent drives the pane you are watching”

An agent clicking in the pane makes the browser take focus, which would otherwise blur whatever you were typing into mid-sentence. Since v0.36.0 the pane knows exactly when a drive is happening and gives your focus back when it ends.

The pane says so while it happens: a veil over the page, a breathing accent ring on its row, a label, and the pointer taken so a click of yours cannot race the agent’s next one. Since v0.43.0 all four run on the whole piece of work rather than on each call. Measured against a real 27-call verification, a single call holds the browser for about a quarter of a second and the agent then thinks for one to four seconds before the next, so marking each call flashed the cue 27 times across one job, and the pointer was live through every gap a click could still land in. The cue now opens on the first call and stays up until the agent stops, goes idle, or you press Ctrl+C, with one fade in and one fade out.

If you type into the pane while an agent is driving it, your keystrokes are intercepted before the page sees them and routed to the terminal you were typing in, so your sentence continues where you meant it rather than landing in a web form.

The agent’s keystrokes never land in your terminal either. Chromium sends a key to whatever holds keyboard focus, and between an agent’s calls that is usually your terminal, so before v0.43.2 an agent’s Escape meant for a page dialog could interrupt the agent that sent it. Now every key an agent sends is checked first, and one the pane would not receive is refused with an error that tells the agent to pass a selector, which clicks the target and sends the key in the same call.

Mouse back and forward also work over a loaded page now. A page consumes the mouse outright, so those presses were previously invisible to Kangentic: a tap navigates back, and a hold still triggers push-to-talk dictation.

A build error is reported, not screenshotted

Section titled “A build error is reported, not screenshotted”

When a screenshot would capture a dev-server build-error overlay, Kangentic returns the error text instead of the picture. Handing an agent a JPEG of a red rectangle is technically correct and practically useless: it spends a turn working out what it is looking at, and when several agents share one dev server the one that sees the overlay is usually not the one who broke the build.

What the pane does with pop-ups, signed-in sessions, and files, and where that state lives.

A site whose sign-in is a pop-up needs window.open to work, so http(s) pop-ups are allowed, on terms that keep the pane’s hardening intact:

  • The pop-up window is chromed, and Kangentic owns its title, forcing it to the live origin (an http origin is labeled not secure). The OS title bar is the only origin indicator such a window has, and a page free to name itself is exactly the phishing affordance to avoid.
  • Its security preferences restate the guest’s hardening in full: no Node integration, context isolation on, sandboxed, web security on.
  • It shares the guest’s session, so an OAuth cookie lands in the same per-task jar, and window.opener and postMessage keep working, which nearly every OAuth flow depends on.
  • The page’s requested size is honored within limits; its requested position is ignored and the window is centered on its parent.
  • A pop-up may open one more pop-up under the identical policy, so a chained identity-provider hop stays in one cookie jar. A pane is capped at four live pop-ups, and they close with the pane that opened them.

Some identity providers refuse OAuth from an embedded browser on principle. The refusal is specific to the pop-up path: a third-party site’s “Sign in with Google” button opens an OAuth window that Google has answered with disallowed_useragent. Signing in first-party, by pointing the pane at accounts.google.com itself, completes and leaves you with a real authenticated session - which is what the shared login below carries between tasks. When Kangentic recognizes the OAuth bounce it offers to open that sign-in in your own browser instead. Since v0.43.1 the pane no longer sends the Electron/ token in its user agent, for an unrelated reason covered under Security. Nobody has re-tested Google’s pop-up without that token, so the offer stays in place for whatever Google still refuses.

Per-task cookie jars solve one problem and used to create another. Isolating localhost also isolated everything else, so you re-entered your Google, GitHub, or SSO login once per task, for an account the browser next door was already signed into. Since v0.37.0 the split runs by cookie domain instead of by task.

Identity-provider logins are shared across a project. Non-localhost cookies live in a per-project identity jar. A task’s pane syncs from that jar when it opens, and a sign-in in one task mirrors back out to it, so the next task starts signed in. The sharing survives restarts and reaches tasks you create later.

Dev-server logins stay isolated. localhost, 127.0.0.1, and [::1] cookies are never copied in either direction, so two tasks signed into different accounts on their own dev servers behave exactly as before.

Three limits are worth knowing before you lean on it:

  • Sharing is add-only. Signing out in one task does not sign you out anywhere else. Clear browser data is the wipe-everywhere path, and it includes the identity jar.
  • Two different accounts at the same provider, across tasks, at the same time is unsupported - not “last one wins”. A jar can end up holding a mixed set of both accounts’ cookies, which the provider may answer with a “verify it’s you” challenge. Clear browser data is the way out.
  • A fresh task’s pane starts signed in. That is the feature, and it is also the cost: an agent driving a brand-new pane can act with your identity-provider session, the same trade an offscreen surface already makes within a task. For a project where that is not a trade you want, turn the pane off with Browser pane in Settings > Browser.

Propagation happens when a pane opens rather than live, so two panes already open side by side will not see each other’s sign-in until one of them is reopened.

A download started in the pane, by you or by an agent, saves to your OS Downloads folder, dedupes its filename rather than overwriting, shows progress on the host window’s taskbar (an indeterminate bar when the server sends no size, since v0.44.0), and raises a toast when it finishes. Nothing opens a modal save dialog, which would block a pane an agent is mid-way through driving.

Downloads are allowed rather than denied on purpose: the agent driving the pane already has full filesystem write through its own tools, so refusing would only break your use of the pane. The toast is what stops an agent-triggered download from being invisible.

The two settings the pane has, the sandbox it runs in, and the platform differences.

Open Settings > Browser:

SettingDefaultDescription
Browser paneOnWhen off, the Browser pill is hidden in the task detail window header, and an agent trying to open a pane over MCP is refused rather than opening one you have no pill to close
Default URLemptyProject-overridable fallback URL when a task has no per-task override
Clear browser data(action)Destructive button. Clears cookies, localStorage, IndexedDB, cache, and service workers from every browser partition for the project: each task’s own cookie jar, the project’s identity jar, and the legacy shared jar. Per-task and project URL overrides are intentionally left alone - those are workflow state, not browsing identity

Settings on the Browser tab: the Browser pane toggle, the default URL a task opens, and a control to clear the browser's data. v0.46.0 The real app on a sample install. The projects and terminals are recordings, connected to nothing, so click anything.

The webview runs in its own renderer process with nodeIntegration: false, contextIsolation: true, sandbox: true, and webSecurity: true. Non-http(s): URLs are rewritten to about:blank. http(s) pop-ups are allowed under the hardened policy described in Sign-in pop-ups above; anything else is denied. The host renderer can only reach the webview through the inspector’s executeJavaScript and the navigation/capture APIs.

The pane’s user agent is Chromium’s own string with Kangentic/<version> kept and the Electron/<version> token removed. Some web application firewalls reject that token as a bot and answer a stylesheet or script request with a block page, so before v0.43.1 a site loading its assets from such a host rendered unstyled in the pane while Chrome showed it correctly. The pane, the pop-ups it opens, and its offscreen form all send the shorter string. Nothing is added to pass as Chrome, and Kangentic’s own window keeps the full string.

The offscreen form gets the pane’s permission and download policy too, since v0.44.0. Before that, an offscreen surface opened before any pane had used its task’s cookie jar ran with Chromium’s default, which grants every permission request a page makes. It also renders at the display’s own pixel ratio now, so a page’s devicePixelRatio no longer changes when its surface moves between the pane and its offscreen form.

A page in the pane that crashes is reported as a bare warning, without its address or content: see Privacy and analytics.

PlatformBehavior
WindowsWSL-localhost is not reachable from the Windows host. The empty state surfaces a hint with the wsl hostname -I workaround
macOSNativeImage capture includes the alpha channel; composited correctly into the PNG
AllSelf-signed HTTPS dev servers show the standard Chromium interstitial - accept it once or use plain HTTP

Kangentic is free and open source. A star helps other people find it.

Star on GitHub