Skip to content

feat(browser-use): add Camoufox noVNC session viewer#921

Open
viper151 wants to merge 78 commits into
mainfrom
camoufox-novnc-browser-use
Open

feat(browser-use): add Camoufox noVNC session viewer#921
viper151 wants to merge 78 commits into
mainfrom
camoufox-novnc-browser-use

Conversation

@viper151

@viper151 viper151 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds a visible Browser session mode for agent-driven browsing. The existing Playwright backend works well for fast automated page interaction, screenshots, and frontend checks, but it is limited when a flow requires human involvement, such as logging in, completing MFA, approving a consent screen, or watching exactly what the agent is doing in real time.

To support those workflows, Browser can now run sessions with Camoufox and expose them through noVNC. Users can choose between the existing Playwright backend and the new visible Camoufox + noVNC backend from Browser settings. Playwright remains the lightweight option for quick automated checks, while Camoufox + noVNC is the better fit when a person may need to observe or take control of the live browser session.

The backend manages the visible runtime, proxies authenticated noVNC traffic through the app, and attaches viewer metadata to Browser sessions. The UI now surfaces the selected engine, profile information, runtime readiness, live screenshots, and take-control links from the Browser panel.

Changes

  • Add configurable Browser backend support for playwright and camoufox-vnc
  • Add persistent Browser settings for backend selection, profile persistence, and default profile name
  • Add visible runtime startup for Camoufox sessions using Xvfb, x11vnc, websockify, and noVNC
  • Add authenticated noVNC viewer URL generation and token validation
  • Proxy noVNC HTTP assets and WebSocket traffic through the existing server
  • Update Browser session models to include backend, profile, viewport, cursor, and viewer metadata
  • Update Browser settings UI with engine selection and runtime readiness details
  • Update Browser panel UI with live screenshots, session selection, profile/backend badges, and take-control actions

Testing Steps

  1. Start the app locally.
  2. Open Settings → Browser.
  3. Enable Browser access.
  4. Select the Playwright backend and verify the status reports the runtime correctly.
  5. Select the Camoufox + noVNC backend and verify missing runtime dependencies are reported clearly if unavailable.
  6. With the visible runtime dependencies installed, create a Browser session through the agent/browser MCP flow.
  7. Confirm the Browser panel lists the new session with backend/profile metadata.
  8. Navigate the session to a website and verify screenshots update in the Browser panel.
  9. Click the take-control action and verify the noVNC viewer opens successfully.
  10. Stop/delete the session and verify the runtime processes are cleaned up and the UI updates.
  11. Confirm existing Playwright Browser sessions still work after switching the backend back to Playwright.

Docs

The Browser Use docs are already published and cover the new visible-session flow:

https://cloudcli.ai/docs/features/browser-use

The page includes Browser engine selection, Playwright, Camoufox + noVNC, saved logins/profiles, runtime requirements, and troubleshooting, so this PR links to the existing docs rather than adding separate setup instructions in the PR body.

Summary by CodeRabbit

  • New Features
    • Added a live per-session browser viewer with token/cookie-based access, generated viewer URLs, and a proxy endpoint for viewer assets.
    • Introduced engine selection (Playwright vs Camoufox + VNC), including visible-backend runtime support and persisted profile selection/logins.
    • Updated the browser panel UI to support per-project engine/profile display and TTL-cached status/sessions.
  • Bug Fixes
    • Hardened viewer authentication and routing for HTTP and WebSockets, added secure path validation, and improved viewer session/error handling.
  • Tests
    • Added tests for profile-name normalization and alias rejection.

viper151 added 30 commits June 14, 2026 20:34
# Conflicts:
#	src/components/main-content/view/subcomponents/MainContentTabSwitcher.tsx
# Conflicts:
#	server/index.js
- Rename Browser Use surfaces to Browser
- Register Browser MCP under the new server name
- Mark CloudCLI-managed MCP servers read-only
- Adjust MCP stdio framing and sidebar footer sizing
# Conflicts:
#	src/i18n/locales/en/settings.json
# Conflicts:
#	package-lock.json
#	package.json
#	server/index.js
#	src/components/main-content/types/types.ts
#	src/components/main-content/view/MainContent.tsx
#	src/components/main-content/view/subcomponents/MainContentHeader.tsx
#	src/components/main-content/view/subcomponents/MainContentTabSwitcher.tsx
#	src/components/main-content/view/subcomponents/MainContentTitle.tsx
#	src/components/settings/hooks/useSettingsController.ts
#	src/components/settings/types/types.ts
#	src/components/settings/view/Settings.tsx
#	src/components/settings/view/SettingsSidebar.tsx
#	src/hooks/useProjectsState.ts
#	src/i18n/locales/de/common.json
#	src/i18n/locales/en/common.json
#	src/i18n/locales/en/settings.json
#	src/i18n/locales/it/common.json
#	src/i18n/locales/ja/common.json
#	src/i18n/locales/ko/common.json
#	src/i18n/locales/ru/common.json
#	src/i18n/locales/tr/common.json
#	src/i18n/locales/zh-CN/common.json
#	src/i18n/locales/zh-TW/common.json
#	src/types/app.ts
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Camoufox VNC browser-use runtime support, viewer proxy/auth wiring, backend and profile settings, and frontend updates for viewer access, engine display, and loading states.

Changes

Camoufox VNC Backend and Viewer

Layer / File(s) Summary
Types, settings, and viewer helpers
server/modules/browser-use/browser-use.types.ts, server/modules/browser-use/browser-use.settings.ts, server/modules/browser-use/browser-use.viewer.ts, server/modules/browser-use/index.ts, server/browser-use-mcp.ts, server/modules/browser-use/tests/browser-use.settings.test.ts
Adds browser-use runtime and session types, settings normalization and persistence helpers, viewer URL and token helpers, module exports, the MCP description update, and settings tests.
Visible backend runtime and session lifecycle
server/modules/browser-use/browser-use.service.ts
Updates browserUseService with Camoufox detection, visible runtime startup and cleanup, backend-aware status and session creation, viewer token lifecycle, and viewer proxy service methods.
Viewer HTTP route and WebSocket auth
server/modules/browser-use/browser-use.routes.ts, server/modules/websocket/services/websocket-server.service.ts, server/index.js
Adds viewer path hardening, secure request detection, query sanitization, the viewer proxy route, WebSocket viewer authentication, and browser-use route and websocket gateway wiring.
BrowserUse panel, settings tab, and session title updates
src/components/browser-use/view/BrowserUsePanel.tsx, src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx, src/components/main-content/view/MainContent.tsx, src/components/main-content/view/subcomponents/MainContentTitle.tsx
Refactors BrowserUsePanel to cache status and sessions, surface viewer actions and backend badges, and add loading states. Passes projectId from MainContent, expands the settings tab with backend and profile controls, and shows the selected session id in the title area.

Possibly related PRs

  • siteboon/claudecodeui#889: Touches the same browser-use MCP and service wiring, with related session creation and service-side integration changes.

Poem

🐇 Hop hop, the viewer lights the way,
Camoufox hums in VNC play.
Profiles tucked and tokens spun,
Fresh sessions bloom for everyone.
My whiskers twitch, the browser sings,
With tiny tabs and shiny things.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding a Camoufox noVNC viewer for browser-use sessions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch camoufox-novnc-browser-use

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread server/index.js Fixed
Comment thread server/modules/browser-use/browser-use.routes.ts Dismissed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/browser-use-mcp.ts`:
- Line 72: The Browser session tool description in the MCP schema is inaccurate
because it implies the configured persistent profile is used by default in all
cases, while resolveSessionProfileName() only falls back to defaultProfileName
when persistSessions is enabled. Update the description on the Browser session
tool definition to match the actual behavior: mention that profileName can
override the profile, and that the persistent profile is only used by default
when session persistence is enabled; otherwise a temporary session is created.

In `@server/index.js`:
- Around line 231-243: The authenticateBrowserUse middleware currently falls
back to authenticateToken(), which lets any logged-in user access viewer routes
without proving ownership of the :sessionId. Update authenticateBrowserUse and
the browserUseService validation path so requests under
/sessions/:sessionId/viewer require a valid viewer token or an ownership-aware
authorization check tied to that session. Make sure the logic in
authenticateBrowserUse and browserUseService.validateViewerToken enforces
per-session access before calling next(), rather than relying on generic
authentication.

In `@server/modules/browser-use/browser-use.service.ts`:
- Around line 258-314: In startVisibleRuntime, readiness is being inferred from
fixed delays after spawnRuntimeProcess, so the visible runtime can be marked
ready even if Xvfb, x11vnc, or websockify never started or exited early. Replace
the sleep-only flow with explicit health checks in the startup path: verify each
spawned process is still alive and confirm the VNC/websockify ports are actually
bound before returning the viewer handle. Use the existing startVisibleRuntime
and spawnRuntimeProcess flow to gate the ready state only after those checks
pass.

In `@server/modules/browser-use/browser-use.settings.ts`:
- Around line 41-55: The profile-name handling in resolveSessionProfileName and
getProfilePath can alias different logical names to the same disk directory
because of case folding and character rewriting. Update the
BrowserUseSettings/profile resolution flow so profileName is canonicalized
before it is stored or echoed back, and add validation to reject any requested
name that would map to an existing normalized on-disk name. Keep the fix
centered around resolveSessionProfileName,
normalizeProfileName/normalizeDefaultProfileName, and getProfilePath so distinct
UI profiles cannot share the same saved session state.

In `@server/modules/browser-use/browser-use.viewer.ts`:
- Around line 8-11: The VIEWER_TOKEN_TTL_MS constant can become NaN or a
non-positive value from the CLOUDCLI_BROWSER_USE_VIEWER_TOKEN_TTL_MS env var, so
clamp it to a finite positive number when initializing browser-use.viewer.ts.
Update the VIEWER_TOKEN_TTL_MS parsing logic to validate the parsed value and
fall back to the default 30 * 60 * 1000 whenever the env value is invalid, zero,
negative, or non-finite, so the token expiry path used by expiresAt and cookie
maxAge remains safe.

In `@server/modules/websocket/services/websocket-server.service.ts`:
- Around line 44-56: The websocket auth path in websocket-server.service.ts is
incorrectly falling back to verifyWebSocketClient() for viewer sockets, which
lets generic app auth accept connections without proving session ownership.
Update the websocket upgrade handling around the viewer route check in the
websocket server service so that
/api/browser-use/sessions/:sessionId/viewer/websockify only succeeds when
getBrowserUseViewerToken() is valid and authenticateBrowserUseViewer() passes,
or otherwise perform an explicit per-session ownership check before returning
true. Keep the generic verifyWebSocketClient() fallback only for non-viewer
websocket paths.

In `@src/components/browser-use/view/BrowserUsePanel.tsx`:
- Around line 274-281: The cache update in BrowserUsePanel’s selection effect
should not bump freshness metadata when only selectedSessionId changes. Update
the useEffect that reads and writes browserUsePanelCache so it only stores the
new selectedSessionId on the existing entry and leaves updatedAt unchanged, and
verify getFreshCacheEntry still relies on the original fetch time rather than
selection-only updates.

In
`@src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx`:
- Around line 125-129: The settings load failure is being treated as if the
feature were disabled because BrowserUseSettingsTab derives browserEnabled
directly from settings being null; keep a separate “settings loaded” flag in
BrowserUseSettingsTab and use it to distinguish unknown state from an actual
disabled setting. Update the rendering around the browserEnabled-dependent UI so
the error banner from loadSettings() is shown independently of browserEnabled,
and make sure the disabled-state UI is only based on loaded settings, not a
failed load, in the affected browser toggle and related sections.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e8a72ac2-f54b-4413-85c5-c57a91b49ac5

📥 Commits

Reviewing files that changed from the base of the PR and between f6326c8 and 8c31ebc.

📒 Files selected for processing (13)
  • server/browser-use-mcp.ts
  • server/index.js
  • server/modules/browser-use/browser-use.routes.ts
  • server/modules/browser-use/browser-use.service.ts
  • server/modules/browser-use/browser-use.settings.ts
  • server/modules/browser-use/browser-use.types.ts
  • server/modules/browser-use/browser-use.viewer.ts
  • server/modules/browser-use/index.ts
  • server/modules/websocket/services/websocket-server.service.ts
  • src/components/browser-use/view/BrowserUsePanel.tsx
  • src/components/main-content/view/MainContent.tsx
  • src/components/main-content/view/subcomponents/MainContentTitle.tsx
  • src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx

Comment thread server/browser-use-mcp.ts Outdated
Comment thread server/index.js
Comment thread server/modules/browser-use/browser-use.service.ts
Comment thread server/modules/browser-use/browser-use.settings.ts Outdated
Comment thread server/modules/browser-use/browser-use.viewer.ts Outdated
Comment thread server/modules/websocket/services/websocket-server.service.ts
Comment thread src/components/browser-use/view/BrowserUsePanel.tsx
Comment thread server/modules/browser-use/browser-use.settings.ts Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
server/modules/browser-use/tests/browser-use.settings.test.ts (1)

31-57: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Tests mutate the real user home directory.

getProfilePath/PROFILE_ROOT resolve under os.homedir()/.cloudcli/browser-use/profiles, so this test creates (and the finally only partially removes) directories in the developer's actual home directory. This couples the test to machine state and risks clobbering a real profile if a name ever collides. Consider redirecting PROFILE_ROOT to an isolated temp dir (e.g. via fs.mkdtempSync(os.tmpdir()) and an env/override) for the duration of the test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/modules/browser-use/tests/browser-use.settings.test.ts` around lines
31 - 57, The browser profile alias test is writing into the real
home-directory-backed profile store, so isolate it from machine state. Update
the test setup around resolveSessionProfileName/getProfilePath to point
PROFILE_ROOT at a temporary directory for the duration of the test, rather than
using os.homedir()-based paths. Ensure the temporary override is restored and
the temp directory is cleaned up in teardown so the test no longer creates or
removes real user profiles.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/modules/browser-use/browser-use.settings.ts`:
- Around line 31-37: The profile name normalization in browser-use.settings.ts
runs the dash-stripping regexes on an unbounded user-controlled string, which
can trigger the CodeQL ReDoS warning. Update the normalization flow in the
profile name handling logic to apply the length cap before the `/^-+|-+$/g`
replacements, so the regex work is limited to MAX_PROFILE_NAME_LENGTH; keep the
existing normalization behavior in the same sequence around the normalized
variable.

---

Nitpick comments:
In `@server/modules/browser-use/tests/browser-use.settings.test.ts`:
- Around line 31-57: The browser profile alias test is writing into the real
home-directory-backed profile store, so isolate it from machine state. Update
the test setup around resolveSessionProfileName/getProfilePath to point
PROFILE_ROOT at a temporary directory for the duration of the test, rather than
using os.homedir()-based paths. Ensure the temporary override is restored and
the temp directory is cleaned up in teardown so the test no longer creates or
removes real user profiles.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7c91751c-0ebe-4ebc-8823-208bbd4cffa3

📥 Commits

Reviewing files that changed from the base of the PR and between 8c31ebc and 9457651.

📒 Files selected for processing (9)
  • server/browser-use-mcp.ts
  • server/index.js
  • server/modules/browser-use/browser-use.service.ts
  • server/modules/browser-use/browser-use.settings.ts
  • server/modules/browser-use/browser-use.viewer.ts
  • server/modules/browser-use/tests/browser-use.settings.test.ts
  • server/modules/websocket/services/websocket-server.service.ts
  • src/components/browser-use/view/BrowserUsePanel.tsx
  • src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx
💤 Files with no reviewable changes (1)
  • src/components/browser-use/view/BrowserUsePanel.tsx
✅ Files skipped from review due to trivial changes (1)
  • server/browser-use-mcp.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • server/modules/browser-use/browser-use.viewer.ts
  • server/modules/websocket/services/websocket-server.service.ts
  • server/index.js
  • src/components/settings/view/tabs/browser-use-settings/BrowserUseSettingsTab.tsx
  • server/modules/browser-use/browser-use.service.ts

Comment thread server/modules/browser-use/browser-use.settings.ts Outdated
Comment thread server/index.js Dismissed
…r-use

# Conflicts:
#	.github/workflows/release.yml
#	electron/desktopWindow.js
#	electron/launcher/launcher.js
#	electron/main.js
#	electron/preload.cjs
#	package.json
#	scripts/release/prepare-desktop-app.js
#	server/modules/websocket/services/websocket-server.service.ts
#	src/components/main-content/view/MainContent.tsx
#	src/components/main-content/view/subcomponents/MainContentTitle.tsx

const shouldShowTasksTab = Boolean(tasksEnabled && isTaskMasterInstalled);
const shouldShowBrowserTab = browserUseEnabled;
const shouldShowComputerTab = COMPUTER_USE_MENUS_ENABLED && computerUseEnabled === true;
const normalizeMainTab = (tab: string): SettingsMainTab => {
// Keep backwards compatibility with older callers that still pass "tools".
if (tab === 'tools') {
if (tab === 'tools' || (tab === 'computer' && !COMPUTER_USE_MENUS_ENABLED)) {
];

const VISIBLE_NAV_ITEMS = NAV_ITEMS.filter((item) => (
COMPUTER_USE_MENUS_ENABLED || item.id !== 'computer'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants