Skip to content

Commit 666baf1

Browse files
shrey150claude
andauthored
[STG-1741] feat(cli): add global flags for Browserbase session parameters (browserbase#1935)
## Summary - Add global CLI flags for commonly used Browserbase session parameters to the `browse` CLI - Users no longer need external tools or workarounds to configure `advancedStealth`, `proxies`, `solveCaptchas`, etc. - Flags are remote-mode only and trigger daemon restart when changed ### New flags | Flag | Description | |------|-------------| | `--proxies` | Enable Browserbase proxy | | `--advanced-stealth` | Enable advanced stealth mode | | `--solve-captchas` / `--no-solve-captchas` | Toggle CAPTCHA solving | | `--region <region>` | Session region | | `--keep-alive` | Keep session alive after disconnection | | `--session-timeout <seconds>` | Session timeout | | `--block-ads` | Enable ad blocking | ### Examples ```bash browse --proxies --advanced-stealth open https://example.com browse --region us-east-1 --solve-captchas open https://example.com ``` Session flags are validated to only work in remote mode and will error with a helpful message if used in local mode. Linear: https://linear.app/browserbase/issue/STG-1741/featcli-add-global-flags-for-browserbase-session-parameters ## Test plan - [ ] `browse --help` shows new flags with "(remote only)" descriptions - [ ] `browse --proxies open https://example.com` (in remote mode) creates session with proxy enabled - [ ] `browse --advanced-stealth --solve-captchas open https://example.com` configures both settings - [ ] `browse --proxies open https://example.com` (in local mode) errors with helpful message - [ ] Changing flags restarts the daemon automatically - [ ] `browse status` shows active session params - [ ] Build succeeds 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Add global flags to `browse` to configure Browserbase session settings in remote mode (proxies, stealth, CAPTCHA solving, region, keep-alive, timeouts) without JSON. Settings persist per session, trigger a daemon restart when changed, and appear as `sessionParams` in `browse status` JSON; also fixes lint errors. Addresses Linear STG-1741. - **New Features** - Flags: `--proxies`, `--advanced-stealth`, `--solve-captchas`/`--no-solve-captchas`, `--block-ads`, `--region <region>`, `--keep-alive`, `--session-timeout <seconds>`; remote-only with a clear error in local mode <sup>Written for commit 064c0e4. Summary will update on new commits. <a href="https://cubic.dev/pr/browserbase/stagehand/pull/1935">Review in cubic</a></sup> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2888856 commit 666baf1

2 files changed

Lines changed: 129 additions & 10 deletions

File tree

.changeset/session-params-flags.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@browserbasehq/browse-cli": minor
3+
---
4+
5+
Add global flags for commonly used Browserbase session parameters (--proxies, --advanced-stealth, --solve-captchas, --region, --keep-alive, --session-timeout, --block-ads). These flags configure the Browserbase session in remote mode.

packages/cli/src/index.ts

Lines changed: 124 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ function getLocalInfoPath(session: string): string {
178178
return path.join(SOCKET_DIR, `browse-${session}.local-info`);
179179
}
180180

181+
function getSessionParamsPath(session: string): string {
182+
return path.join(SOCKET_DIR, `browse-${session}.session-params`);
183+
}
184+
181185
// ==================== LOCAL STRATEGY CONFIG ====================
182186

183187
async function readLocalConfig(session: string): Promise<LocalConfig> {
@@ -544,6 +548,7 @@ async function cleanupStaleFiles(session: string): Promise<void> {
544548
getContextPath(session),
545549
getConnectPath(session),
546550
getLocalConfigPath(session),
551+
getSessionParamsPath(session),
547552
];
548553

549554
for (const file of files) {
@@ -663,6 +668,15 @@ async function runDaemon(session: string, headless: boolean): Promise<void> {
663668
).trim();
664669
} catch {}
665670

671+
// Read session params if present (written by --proxies, --advanced-stealth, etc.)
672+
let sessionParams: Record<string, unknown> = {};
673+
try {
674+
const raw = await fs.readFile(getSessionParamsPath(session), "utf-8");
675+
sessionParams = JSON.parse(raw);
676+
} catch {
677+
// No session params file
678+
}
679+
666680
// Resolve local browser launch options based on strategy
667681
let localLaunchOptions: LocalBrowserLaunchOptions | undefined;
668682
let localInfo: LocalInfo | undefined;
@@ -694,16 +708,24 @@ async function runDaemon(session: string, headless: boolean): Promise<void> {
694708
: {}),
695709
...(!connectSessionId
696710
? {
697-
browserbaseSessionCreateParams: {
698-
userMetadata: { browse_cli: "true" },
699-
...(contextConfig
700-
? {
701-
browserSettings: {
702-
context: contextConfig,
703-
},
704-
}
705-
: {}),
706-
},
711+
browserbaseSessionCreateParams: (() => {
712+
const sessionBrowserSettings =
713+
(sessionParams.browserSettings as Record<
714+
string,
715+
unknown
716+
>) || {};
717+
const { browserSettings: _, ...sessionParamsWithoutBS } =
718+
sessionParams;
719+
void _;
720+
return {
721+
userMetadata: { browse_cli: "true" },
722+
...sessionParamsWithoutBS,
723+
browserSettings: {
724+
...sessionBrowserSettings,
725+
...(contextConfig ? { context: contextConfig } : {}),
726+
},
727+
};
728+
})(),
707729
}
708730
: {}),
709731
}
@@ -1804,6 +1826,14 @@ interface GlobalOpts {
18041826
json?: boolean;
18051827
session?: string;
18061828
connect?: string;
1829+
// Session creation flags (remote only)
1830+
proxies?: boolean;
1831+
advancedStealth?: boolean;
1832+
solveCaptchas?: boolean;
1833+
region?: string;
1834+
keepAlive?: boolean;
1835+
sessionTimeout?: number;
1836+
blockAds?: boolean;
18071837
}
18081838

18091839
function getSession(opts: GlobalOpts): string {
@@ -1814,6 +1844,31 @@ function isHeadless(opts: GlobalOpts): boolean {
18141844
return opts.headless === true && opts.headed !== true;
18151845
}
18161846

1847+
function buildSessionParamsFromOpts(
1848+
opts: GlobalOpts,
1849+
): Record<string, unknown> | null {
1850+
const params: Record<string, unknown> = {};
1851+
const browserSettings: Record<string, unknown> = {};
1852+
1853+
if (opts.proxies) params.proxies = true;
1854+
if (opts.region) params.region = opts.region;
1855+
if (opts.keepAlive) params.keepAlive = true;
1856+
if (opts.sessionTimeout !== undefined) params.timeout = opts.sessionTimeout;
1857+
1858+
if (opts.advancedStealth) browserSettings.advancedStealth = true;
1859+
if (opts.blockAds) browserSettings.blockAds = true;
1860+
if (opts.solveCaptchas !== undefined) {
1861+
browserSettings.solveCaptchas = opts.solveCaptchas;
1862+
}
1863+
1864+
if (Object.keys(browserSettings).length > 0) {
1865+
params.browserSettings = browserSettings;
1866+
}
1867+
1868+
if (Object.keys(params).length === 0) return null;
1869+
return params;
1870+
}
1871+
18171872
function output(data: unknown, json: boolean): void {
18181873
if (json) {
18191874
console.log(JSON.stringify(data, null, 2));
@@ -1875,6 +1930,38 @@ async function runCommand(command: string, args: unknown[]): Promise<unknown> {
18751930
} catch {}
18761931
}
18771932

1933+
// Handle session params flags (--proxies, --advanced-stealth, etc.)
1934+
const sessionParams = buildSessionParamsFromOpts(opts);
1935+
if (sessionParams) {
1936+
const desiredMode = await getDesiredMode(session);
1937+
if (desiredMode !== "browserbase") {
1938+
console.error(
1939+
JSON.stringify({
1940+
error:
1941+
"Session flags (--proxies, --advanced-stealth, etc.) are only supported in remote mode. Run 'browse env remote' first.",
1942+
}),
1943+
);
1944+
process.exit(1);
1945+
}
1946+
1947+
const paramsPath = getSessionParamsPath(session);
1948+
const newParamsJson = JSON.stringify(sessionParams);
1949+
1950+
let currentParamsJson = "";
1951+
try {
1952+
currentParamsJson = await fs.readFile(paramsPath, "utf-8");
1953+
} catch {}
1954+
1955+
await fs.writeFile(paramsPath, newParamsJson);
1956+
1957+
if (
1958+
currentParamsJson !== newParamsJson &&
1959+
(await isDaemonRunning(session))
1960+
) {
1961+
await stopDaemonAndCleanup(session);
1962+
}
1963+
}
1964+
18781965
await ensureDaemon(session, headless);
18791966
return sendCommand(session, command, args, headless);
18801967
}
@@ -1897,6 +1984,27 @@ program
18971984
.option(
18981985
"--connect <session-id>",
18991986
"Connect to an existing Browserbase session by ID",
1987+
)
1988+
.option("--proxies", "Enable Browserbase proxy (remote only)")
1989+
.option("--advanced-stealth", "Enable advanced stealth mode (remote only)")
1990+
.option("--solve-captchas", "Enable automatic CAPTCHA solving (remote only)")
1991+
.option(
1992+
"--no-solve-captchas",
1993+
"Disable automatic CAPTCHA solving (remote only)",
1994+
)
1995+
.option("--block-ads", "Enable ad blocking (remote only)")
1996+
.option(
1997+
"--region <region>",
1998+
"Session region: us-west-2, us-east-1, eu-central-1, ap-southeast-1 (remote only)",
1999+
)
2000+
.option(
2001+
"--keep-alive",
2002+
"Keep session alive after disconnection (remote only)",
2003+
)
2004+
.option(
2005+
"--session-timeout <seconds>",
2006+
"Session timeout in seconds (remote only)",
2007+
parseInt,
19002008
);
19012009

19022010
// ==================== DAEMON COMMANDS ====================
@@ -1972,6 +2080,11 @@ program
19722080
};
19732081
}
19742082
}
2083+
let sessionParams: Record<string, unknown> | null = null;
2084+
try {
2085+
const raw = await fs.readFile(getSessionParamsPath(session), "utf-8");
2086+
sessionParams = JSON.parse(raw);
2087+
} catch {}
19752088
console.log(
19762089
JSON.stringify({
19772090
running,
@@ -1980,6 +2093,7 @@ program
19802093
mode,
19812094
browserbaseSessionId,
19822095
...localDetails,
2096+
...(sessionParams ? { sessionParams } : {}),
19832097
}),
19842098
);
19852099
});

0 commit comments

Comments
 (0)