#4663: fix: per-profile browser caching to allow parallel connections
Cluster:
Browser Enhancements and Fixes
## Summary
Changes global singleton `cached`/`connecting` variables to per-URL Maps, allowing different browser profiles to connect in parallel instead of blocking each other.
## Problem
When using multiple browser profiles (e.g., `linkedin` on port 18805 and `clawd` on port 18800), operations on one profile blocked operations on the other due to shared global state.
## Solution
- Replace `let cached` and `let connecting` with `Map<string, ...>` keyed by CDP URL
- Each profile now maintains its own connection state
- `closePlaywrightBrowserConnection()` now closes all cached connections
## Testing
- [x] Tested locally with multiple browser profiles
- [x] Linter passes
## AI Assistance 🤖
This PR was AI-assisted (Claude). The fix was identified by analyzing the root cause reported in #4289 and #3605.
Fixes #4289, #3605
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR changes Playwright CDP connection caching from a single global `cached`/`connecting` pair to per-CDP-URL Maps (`cachedByUrl`, `connectingByUrl`), allowing multiple browser profiles (different CDP URLs) to connect concurrently without blocking each other. It also updates `closePlaywrightBrowserConnection()` to close all cached browser connections rather than just the last cached one.
The approach fits the existing `connectBrowser()` pattern (normalize URL → connect with retry → observe browser) while removing cross-profile contention introduced by global singleton state.
<h3>Confidence Score: 4/5</h3>
- This PR is likely safe to merge and addresses the reported cross-profile connection contention.
- The change is localized to connection caching logic and appears consistent with existing connection/retry patterns. Main remaining concern is lifecycle: clearing `connectingByUrl` in `closePlaywrightBrowserConnection()` can leave in-flight connections untracked and potentially open, which could matter if callers rely on close being deterministic during concurrent usage.
- src/browser/pw-session.ts (connection lifecycle during concurrent close/connect)
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#6686: fix: clear Playwright's default colorScheme override on CDP-connect...
by Terwox · 2026-02-01
79.4%
#9020: fix(browser): skip port ownership and WS reachability checks for re...
by yepack · 2026-02-04
79.0%
#14944: fix(browser): prefer openclaw profile in headless/noSandbox environ...
by BenediktSchackenberg · 2026-02-12
78.6%
#19823: fix(browser): stability improvements for headless Chrome
by Milofax · 2026-02-18
78.5%
#15595: fix(browser): avoid local port conflicts for remote cdp
by TsekaLuk · 2026-02-13
75.0%
#13568: Fix browser (OpenClaw-managed) launch fail by binding remote debugg...
by singlag · 2026-02-10
74.9%
#8303: fix(browser): enable downloads via CDP Browser.setDownloadBehavior
by gavinbmoore · 2026-02-03
74.3%
#23363: Browser: fallback to managed profile and improve runtime diagnostics
by isdoho · 2026-02-22
73.8%
#9728: fix(gateway): browser.snapshot ignores profile parameter (#9723)
by divol89 · 2026-02-05
73.1%
#16030: fix(browser): extend single-tab fallback to remote CDP profiles
by lailoo · 2026-02-14
73.1%