feat(browser): give the embedded browser a faithful Chrome user-agent - #1343
Conversation
Strip Electron's `Electron/<ver>` and the app product token from the embedded browser's UA and pin Chrome to the reduced `<major>.0.0.0` form, deriving the major from process.versions.chrome. Set on the persist:pawwork-browser partition so it covers both manual browsing and CDP automation. Client Hints are left at Chromium's correct defaults so manual and automation present one consistent, faithful Chromium identity (app renderer UA untouched).
There was a problem hiding this comment.
Suggested priority: P2 (includes user-path files (packages/desktop-electron/src/main/browser/controller.ts, packages/desktop-electron/src/main/browser/user-agent.test.ts, packages/desktop-electron/src/main/browser/user-agent.ts)).
P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.
📝 WalkthroughWalkthroughA new ChangesElectron Partition User-Agent Normalization
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a mechanism to rewrite the default Electron user-agent string into a clean, standard Chrome user-agent for the embedded browser's shared partition. This is achieved by stripping out Electron-specific and application-specific tokens and pinning the Chrome version to the reduced major.0.0.0 format, reducing the risk of anti-automation detection. Unit tests have been added to verify the parsing and rewriting logic. I have no feedback to provide as there are no review comments.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
…dependency Two review fixes on the parity doc: - The embedded browser rejects file://, so "load the file" was not runnable. Serve the probe over a local HTTP server and open the same http://127.0.0.1 URL in both browsers (same origin, apples to apples). - The parity table records state that assumes #1343 (UA) and #1344 (permissions) are applied; neither is on dev yet. Say so explicitly and note this PR should land after both — on its own it is a forward-looking baseline, not current dev behavior.
…ents Review follow-ups (UA rewrite behavior unchanged): - Add configurePartitionUserAgent(session, chromeVersion) in the pure user-agent.ts (no electron import) as the seam the controller calls on the real partition session before the first view is created. This makes the wiring testable without an Electron runtime — added a test asserting the partition session receives the cleaned Chrome UA (no Electron/app token). - Trim the long stealth rationale from the production comments in user-agent.ts and controller.ts down to the invariant (faithful Chrome UA; configured before the first view/request); the full rationale lives in the PR description.
Summary
Give the embedded browser a faithful Chrome user-agent. Electron's default UA carries an
Electron/<ver>token and the app's own product token (opencode/<ver>afterindex.ts's rewrite,PawWork .../<ver>before it) exactly where a real Chrome UA has nothing — both are obvious "not a normal browser" tells. We strip them and pin the Chrome token to the reducedChrome/<major>.0.0.0form real Chrome reports, deriving the major fromprocess.versions.chromeso it tracks the embedded Chromium and never drifts. The clean UA is set on thepersist:pawwork-browserpartition, so it applies to both manual browsing and CDP-driven automation.This is the first stealth-fidelity change after a real Xiaohongshu "suspected automation" warning. It is legitimate fingerprint fidelity: the view IS real Chromium (Electron), and we present it as the Chromium it actually is — for users operating their own accounts — rather than leaking Electron/app tokens that look like a bot.
Why this shape (Client Hints left at Chromium defaults — deliberate)
Codex consult + Electron/Chromium source confirmed:
embedder_support::GetUserAgentMetadata(). So defaultnavigator.userAgentDatabrands as Chromium (+ a GREASE brand) and does not leak "Electron" or the app name.session.setUserAgentsets only the UA string + Accept-Language. The only way to set Client Hints for manual browsing would be a permanent CDP debugger attach, which is itself a detectable signal and is explicitly not worth it.So the chosen identity is faithful, consistent Chromium, not impersonated Google Chrome:
Chrome/<major>.0.0.0and CH brandChromium— exactly what we now produce. Internally consistent, nothing faked.navigator.userAgentData(onlyEmulation.setDeviceMetricsOverride+Network.enable), so automation inherits the same consistent identity; its stealth script handles the automation-specific JS tells (webdriver,chrome, plugins, languages).Honest ceiling: this fixes the fingerprint layer only. It does not make automation "safe" on a mature behavioral risk-control platform (speed/rhythm/trajectory still matter). It removes the loud UA tell that this browser is not a normal one.
Related Issue
None — follow-up from a maintainer report; no tracking issue yet.
Human Review Status
Pending
Review Focus
toChromeUserAgentinuser-agent.ts: token stripping is robust to both theopencode/(post-rewrite) andPawWork .../(pre-rewrite, app name with a space) forms, preserves the OS platform token (macOS vs Windows), and is idempotent.controller.ts: partition-scoped (app renderer UA untouched), once-guarded, set before the first view's first request.Risk Notes
persist:pawwork-browserpartition only;app.userAgentFallback(app renderer) is intentionally left as-is.How To Verify
Verified by me (CI-checkable):
Runtime check (needs the desktop GUI — your machine), using the fingerprint probe I sent separately:
dev:desktop, open the embedded browser, load the probe HTML.navigator.userAgent=...Chrome/<major>.0.0.0 Safari/537.36with noElectron/opencode/PawWork(probe flags these red).navigator.userAgentData.brandsshowsChromium(+ GREASE), no Electron/app leak.Screenshots or Recordings
N/A — no visible UI change (network-level UA).
Checklist
bug,enhancement,task,documentation.app,ui,platform,harness,ci.P0,P1,P2,P3.Pending.toChromeUserAgentpreserves Electron's frozen per-OS token and is tested for both macOS and Windows shapes.dev, and my PR title and commit messages use Conventional Commits in English.Summary by CodeRabbit
New Features
Tests