---
title: Embedded Browser
---

# Embedded Browser

## What it is

Omniscio ships a built-in web browser as a sidebar virtual project. Click **Browser** in the Omniscio sidebar group (sky-blue Globe icon, sits alphabetically between **Automations** and **CLI Tools**) and the right pane swaps to a full-width browser surface — no sessions list, no chat composer, just a toolbar and a single page view.

It's intended for quick lookups inside Omniscio without alt-tabbing to Chrome: reading docs, signing into a service whose token you want available for future visits, peeking at a Google Doc or a dashboard, etc. It is **not** a replacement for your real browser — there are no tabs, no bookmarks, no extensions, no DevTools.

## Where to find it

### What you see

A simple Chrome-style toolbar across the top of the panel, then the live web page below:

- **Back** / **Forward** arrows — disabled when there's no history in that direction.
- **Reload** — spins into a **Stop** button while a page is loading.
- **Home** — globe icon, jumps to Google.
- **Address bar** — type a URL (`https://docs.google.com`), a bare host (`example.com`, `localhost:3000`), or any free-form text. Free-form text is sent to Google as a search query. Press **Enter** to navigate; the bar auto-selects on focus so you can just start typing.

While the first page is still loading, a centered "Loading browser…" spinner overlays the pane. It disappears as soon as the webview's DOM is ready.

## How it behaves

### Persistent cookies and storage

The browser uses an Electron partition called `persist:browser`. Everything you'd expect to survive a browser restart in normal Chrome — cookies, `localStorage`, `IndexedDB`, cached resources — survives an Omniscio restart here too, scoped to a directory inside your Omniscio user-data folder.

Practical consequence: sign into a site once and you stay signed in. Open Gmail, sign in, close Omniscio, reopen tomorrow → still signed in. This same `persist:browser` session is also used by the **Gmail email-link viewer** — the in-app page that opens when you click a link inside an email — so signing into Google in the Browser pane also lets a Google Sheet/Doc linked from an email open signed-in (and vice-versa). It is **separate** from the cookies the rest of Omniscio stores (the Gmail inbox itself + Google Auth Gate use their own token-based auth / partitions).

The partition is also **isolated from your real Chrome profile.** Omniscio has no way to import bookmarks, saved passwords, autofill, or sign-in state from external Chrome — you'll start fresh and have to sign back into each site the first time you visit.

### Google sign-in caveat

Google actively detects embedded browsers (Electron webviews, Chromium Embedded Framework, etc.) and blocks sign-in on many flows with a "This browser or app may not be secure" error. Omniscio defeats this at **both** layers Google checks. First, a stock Chrome identity in the request: a User-Agent **pinned to the browser engine Omniscio actually ships** (currently Chrome 148 — a build guard fails if it ever drifts behind the engine) **plus** matching `Sec-CH-UA` Client-Hint headers for Google requests. Second — the piece that actually unblocks the sign-in — a matching **JavaScript identity**: Omniscio injects a real "Google Chrome" `navigator.userAgentData` and a populated `window.chrome` at page-start on Google pages, because Google's sign-in script reads those JS APIs directly and header-spoofing can't touch them. With both in place, signing into Google directly in the Browser pane works.

**Caveat — this is a moving target.** Google's embedded-browser detection keeps evolving and it deliberately discourages webview sign-in, so a future change on their side could re-block it. If sign-in is ever refused again:

1. Sign in once in your **real Chrome** at `accounts.google.com`, or
2. use the saved **Browser Login** fallback — with Browser Logins enabled, the Browser toolbar shows an **"Open signed in"** control (key icon) that reuses a login you captured in real Chrome so the pane opens **already signed in**, with no sign-in step for Google to block (cookies-only + best-effort — some Google surfaces may still ask you to re-log-in), or
3. use the **"Continue in your browser"** hand-off the email-link viewer offers (below).

**Opening a Google doc linked from an email?** The Gmail email-link viewer shares this same `persist:browser` session, so a sign-in done in the Browser pane carries over. If Google still shows its rejection wall (`accounts.google.com/v3/signin/rejected`) for a private doc, the viewer detects it and replaces the dead-end loop with a one-click **"Continue in your browser"** button that opens the **original document link** in your real browser — where Google allows the sign-in — so you're never stuck.

This is a Google-side policy, and the disguise is best-effort against an evolving heuristic, which is why the email-link viewer always keeps the browser hand-off as a fallback. We don't ship cookie-import from system Chrome (security boundary) — the saved **Browser Login** seed is the sanctioned way to reuse a real-Chrome login in-app.

### What's intentionally missing (v1)

- **No tabs.** One page at a time. `target="_blank"` links and `window.open()` are blocked (popups don't open).
- **No bookmarks or history.** The forward/back stack lives only as long as the pane is mounted in the current Omniscio launch; closing the pane resets it.
- **No DevTools.** The webview runs sandboxed; F12 does nothing.
- **No download manager.** Click-to-download will be ignored or no-op; download URLs typed directly into the address bar may navigate to a page-rendering error.
- **No file uploads via the OS picker** in the v1 pass — `<input type="file">` may or may not work depending on the site.
- **No extensions.** Ad blockers, password managers, etc. don't apply.
- **No print / "Save page as".**

These are deliberate v1 simplifications. If you find yourself needing tabs or downloads, fall back to real Chrome — the embedded browser is for casual reading and persistent-login surfaces, not as a daily driver.

> **In development:** an opt-in **AI-Drivable Browser** mode (Settings → Lab → `ai-browser`, off by default) upgrades this pane with real tabs, a bookmarks bar + manager, browsing history, a download shelf, find-in-page, zoom + keyboard shortcuts, and the ability for an Omniscio agent to drive the browser in its own isolated tab. When that flag is off — the default — everything on this page is exactly what you get. See [ai-browser.md](ai-browser.md). A prototype under the same flag also **docks this agent browser inside a session's own panel** — a resizable pane beside the chat, bound to that session's agent (session A never shows session B's browser), so you watch and take over inline; toggled from the session header, desktop-only. See the `docked-session-pane` invariant in [ai-browser-contract.md](/.claude/memory/contracts/ai-browser-contract.md). With both in-development flags on, a saved [Browser Login](browser-logins.md) can also be seeded into the in-app browser (its isolated agent tab, or your own per-login tab) — cookies-only and best-effort; see [Browser Logins](browser-logins.md#using-a-saved-login-in-the-in-app-browser-agent-tab--your-own-tabs).
>
> **In development:** the **"Open signed in" toolbar control** (Pathway B, above) needs only the **`browser-logins`** flag — not `ai-browser` — so it works in this plain single-page pane: with Browser Logins on and a saved login captured, one click opens the pane already signed in on that login's private per-login partition (cookies-only, best-effort), with a "Signed in as <name> · Exit" indicator to return to normal browsing.

### Why an embedded browser at all?

Two narrow reasons:

1. **Persistent context for Claude.** A Claude session running in Omniscio might point you at a doc, a dashboard, or a sign-in URL. Opening it in-pane keeps you inside Omniscio, and the session it belongs to stays one click away in the sidebar.
2. **Login state continuity.** You can sign into a service inside the Browser pane once, then visit the same URLs over and over without re-authing — useful for Google Docs you reference repeatedly, an internal admin panel, a per-team dashboard.

If you don't have either of those needs, you can simply not click the Browser sidebar entry and it stays out of your way.

## For agents

### Where it lives in the code

- Sidebar entry + icon: `src/renderer/src/integrations/ui-registry.ts` (`id: 'browser'`, Globe icon, `panelOwnsLayout: true` to suppress the empty sessions-sidebar fallback).
- Registry metadata + virtual project sentinel: `src/shared/integration-registry.ts` and `BROWSER_PROJECT_ID = '__browser__'` in `src/shared/virtual-project-ids.ts`.
- UI: `src/renderer/src/features/browser/BrowserView.tsx`. Renders an Electron `<webview>` element with `partition="persist:browser"` and a Chrome `useragent=` attribute (the shared `CHROME_USER_AGENT` in `src/renderer/src/lib/webview-session.ts`, pinned to Omniscio's real Chromium major and locked by the `webview-ua-matches-engine` build guard so it never drifts behind the engine). Toolbar buttons call the webview's imperative API (`loadURL`, `goBack`, `goForward`, `reload`, `stop`, `canGoBack`, `canGoForward`) and listen for `did-start-loading` / `did-stop-loading` / `did-navigate` / `did-navigate-in-page` / `dom-ready` events to keep the address bar and nav-state buttons in sync.
- **"Open signed in" control (Pathway B — reuse a saved Browser Login, gated `browser-logins`):** `src/renderer/src/features/browser/BrowserSignInControl.tsx` + `use-browser-logins-list.ts`, wired through `BrowserToolbar.tsx` / `BrowserView.tsx`. When Browser Logins is on AND ≥1 enabled saved login exists, the toolbar shows a key-icon control (`data-ui-anchor="browser-open-signed-in"`) that reuses `BROWSER_LOGIN_USE_IN_APP` (target `human`) to seed the login's cookies into its per-login partition, then opens a HUMAN tab on `persist:browser-login-<id>` — already signed in, landing on the login's own site. One login opens on click; multiple show a picker carrying the cookies-only caveat. A "Signed in as <name> · Exit" `<Pill>` returns to normal (shared-partition) browsing; in this single-page pane the login surface replaces the current one atomically (no orphaned hidden webview). It only ever opens a per-login HUMAN partition — never `persist:ai-browser-agent` — so it adds no agent-reachable surface (browser-logins `in-app-cookie-seed-adapter` / ai-browser `in-app-login-seed-preserves-isolation`).
- Google Client-Hints alignment: `src/main/services/ai-browser/browser-client-hints.ts` (a startup task) rewrites the `Sec-CH-UA` brand hints to a consistent real-Chrome identity for `*.google.com` requests on the `persist:browser` session, so they agree with the spoofed User-Agent. The Gmail email-link viewer's dead-end fallback lives in `src/renderer/src/features/gmail/EmailLinkViewer.tsx` (`isGoogleSignInRejection` detection + the "Continue in your browser" card). Invariants + tests: [webview-oauth-popup-contract.md](/.claude/memory/contracts/webview-oauth-popup-contract.md) (main-frame UA/Client-Hints section).
- Security guard for the webview: `src/main/webview-security.ts`. Restricts the `<webview>` to `http:` / `https:` / `file:` URLs, strips `allowpopups`, and forces `sandbox: true` + `nodeIntegration: false` — the embedded page is treated as untrusted, like any browser tab.
- Sidebar ordering trip-wire: `src/main/services/amc-builtins-order.ts` (the assertion locks the splice index for the lazy-created Daily Digest row).

## Related

The [AI-drivable browser](ai-browser.md) builds on this panel and lets an agent drive a page of its own; driving your own signed-in Chrome instead is a separate system, documented in [My Real Chrome v2](real-chrome-bridge-v2.md).
