From b45abd9d03ed4ff5eeb50e3a1072d7db75f6d3c0 Mon Sep 17 00:00:00 2001 From: Developers Digest <124798203+developersdigest@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:58:53 -0500 Subject: [PATCH 1/3] add persistent session to browser cmd + skill + help --- skills/firecrawl-cli/SKILL.md | 80 ++++++++++++++++++++++++++++------- src/commands/browser.ts | 34 ++++++++++++++- src/index.ts | 38 +++++++++++++++++ 3 files changed, 135 insertions(+), 17 deletions(-) diff --git a/skills/firecrawl-cli/SKILL.md b/skills/firecrawl-cli/SKILL.md index 486a3a8fec..a40e128b1c 100644 --- a/skills/firecrawl-cli/SKILL.md +++ b/skills/firecrawl-cli/SKILL.md @@ -87,11 +87,29 @@ scrape https://docs.example.com/docs/api/auth... → got the content ``` scrape https://example.com/products → only shows first 10 items, no next-page links browser "open https://example.com/products" → open in browser -browser "snapshot" → find the pagination button +browser "snapshot -i" → find the pagination button browser "click @e12" → click "Next Page" browser "scrape" -o .firecrawl/products-p2.md → extract page 2 content ``` +**Example: login then scrape authenticated content** + +``` +browser launch-session --persistent-session my-app → create a named persistent session +browser "open https://app.example.com/login" → navigate to login +browser "snapshot -i" → find form fields +browser "fill @e3 'user@example.com'" → fill email +browser "fill @e5 'password'" → fill password +browser "click @e7" → click Login +browser "wait 2" → wait for redirect +browser close → disconnect, state persisted + +browser launch-session --persistent-session my-app → reconnect, cookies intact +browser "open https://app.example.com/dashboard" → already logged in +browser "scrape" -o .firecrawl/dashboard.md → extract authenticated content +browser close +``` + **Example: research task** ``` @@ -227,7 +245,7 @@ Cloud Chromium sessions in Firecrawl's remote sandboxed environment. Run `firecr ```bash # Typical browser workflow firecrawl browser "open " -firecrawl browser "snapshot" # see the page structure with @ref IDs +firecrawl browser "snapshot -i" # see interactive elements with @ref IDs firecrawl browser "click @e5" # interact with elements firecrawl browser "fill @e3 'search query'" # fill form fields firecrawl browser "scrape" -o .firecrawl/page.md # extract content @@ -238,22 +256,54 @@ Shorthand auto-launches a session if none exists - no setup required. **Core agent-browser commands:** -| Command | Description | -| -------------------- | -------------------------------------- | -| `open ` | Navigate to a URL | -| `snapshot` | Get accessibility tree with `@ref` IDs | -| `screenshot` | Capture a PNG screenshot | -| `click <@ref>` | Click an element by ref | -| `type <@ref> ` | Type into an element | -| `fill <@ref> ` | Fill a form field (clears first) | -| `scrape` | Extract page content as markdown | -| `scroll ` | Scroll up/down/left/right | -| `wait ` | Wait for a duration | -| `eval ` | Evaluate JavaScript on the page | +| Command | Description | +| -------------------- | ---------------------------------------- | +| `open ` | Navigate to a URL | +| `snapshot -i` | Get interactive elements with `@ref` IDs | +| `screenshot` | Capture a PNG screenshot | +| `click <@ref>` | Click an element by ref | +| `type <@ref> ` | Type into an element | +| `fill <@ref> ` | Fill a form field (clears first) | +| `scrape` | Extract page content as markdown | +| `scroll ` | Scroll up/down/left/right | +| `wait ` | Wait for a duration | +| `eval ` | Evaluate JavaScript on the page | Session management: `launch-session --ttl 600`, `list`, `close` -Options: `--ttl `, `--ttl-inactivity `, `--session `, `-o` +Options: `--ttl `, `--ttl-inactivity `, `--session `, `--persistent-session `, `--write-mode `, `-o` + +**Persistent sessions** survive close and can be reconnected by name. Use them when you need to login first, then come back later to do work while already authenticated: + +```bash +# Session 1: Login and save state +firecrawl browser launch-session --persistent-session my-app +firecrawl browser "open https://app.example.com/login" +firecrawl browser "snapshot -i" +firecrawl browser "fill @e3 'user@example.com'" +firecrawl browser "fill @e5 'password123'" +firecrawl browser "click @e7" +firecrawl browser "wait 2" +firecrawl browser close + +# Session 2: Come back authenticated +firecrawl browser launch-session --persistent-session my-app +firecrawl browser "open https://app.example.com/dashboard" +firecrawl browser "scrape" -o .firecrawl/dashboard.md +firecrawl browser close +``` + +Read-only reconnect (no writes to session state): + +```bash +firecrawl browser launch-session --persistent-session my-app --write-mode readonly +``` + +Shorthand with persistent session: + +```bash +firecrawl browser --persistent-session my-app "open https://example.com" +``` ### credit-usage diff --git a/src/commands/browser.ts b/src/commands/browser.ts index 0ef6c95902..325d5dd009 100644 --- a/src/commands/browser.ts +++ b/src/commands/browser.ts @@ -16,6 +16,8 @@ import { writeOutput } from '../utils/output'; export interface BrowserLaunchOptions { ttl?: number; ttlInactivity?: number; + persistentSession?: string; + writeMode?: 'readonly' | 'readwrite'; apiKey?: string; apiUrl?: string; output?: string; @@ -50,6 +52,8 @@ export interface BrowserCloseOptions { export interface BrowserQuickExecuteOptions { code: string; + persistentSession?: string; + writeMode?: 'readonly' | 'readwrite'; apiKey?: string; apiUrl?: string; output?: string; @@ -68,12 +72,22 @@ export async function handleBrowserLaunch( const args: { ttl?: number; activityTtl?: number; + persistentSession?: { + name: string; + writeMode?: 'readonly' | 'readwrite'; + }; } = {}; if (options.ttl !== undefined) args.ttl = options.ttl; if (options.ttlInactivity !== undefined) args.activityTtl = options.ttlInactivity; + if (options.persistentSession) { + args.persistentSession = { + name: options.persistentSession, + writeMode: options.writeMode, + }; + } - const data = await app.browser(args); + const data = await app.browser(args as Parameters[0]); if (!data.success) { console.error('Error:', data.error || 'Unknown error'); @@ -273,7 +287,23 @@ export async function handleBrowserQuickExecute( if (!existing) { try { const app = getClient({ apiKey: options.apiKey, apiUrl: options.apiUrl }); - const data = await app.browser({}); + + const launchArgs: { + persistentSession?: { + name: string; + writeMode?: 'readonly' | 'readwrite'; + }; + } = {}; + if (options.persistentSession) { + launchArgs.persistentSession = { + name: options.persistentSession, + writeMode: options.writeMode, + }; + } + + const data = await app.browser( + launchArgs as Parameters[0] + ); if (!data.success) { console.error('Error:', data.error || 'Failed to launch session'); diff --git a/src/index.ts b/src/index.ts index d262e01aa1..1d01bd287c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -736,12 +736,31 @@ function createBrowserCommand(): Command { 'Firecrawl API key (overrides global --api-key)' ) .option('--api-url ', 'API URL (overrides global --api-url)') + .option( + '--persistent-session ', + 'Name for a persistent session (survives close, reconnect by name later)' + ) + .option( + '--write-mode ', + 'Write mode for persistent session: readonly or readwrite (default: readwrite)' + ) .option('-o, --output ', 'Output file path (default: stdout)') .option('--json', 'Output as JSON format', false) .action(async (code, options) => { if (code) { + if ( + options.writeMode && + !['readonly', 'readwrite'].includes(options.writeMode) + ) { + console.error( + 'Error: --write-mode must be "readonly" or "readwrite"' + ); + process.exit(1); + } await handleBrowserQuickExecute({ code, + persistentSession: options.persistentSession, + writeMode: options.writeMode, apiKey: options.apiKey, apiUrl: options.apiUrl, output: options.output, @@ -785,6 +804,14 @@ Explicit subcommands: parseInt ) .option('--ttl-inactivity ', 'Inactivity TTL in seconds', parseInt) + .option( + '--persistent-session ', + 'Name for a persistent session (survives close, reconnect by name later)' + ) + .option( + '--write-mode ', + 'Write mode for persistent session: readonly or readwrite (default: readwrite)' + ) .option( '-k, --api-key ', 'Firecrawl API key (overrides global --api-key)' @@ -806,13 +833,24 @@ Examples: $ firecrawl browser launch-session $ firecrawl browser launch-session --ttl 600 $ firecrawl browser launch-session --ttl 300 --ttl-inactivity 60 + $ firecrawl browser launch-session --persistent-session my-session + $ firecrawl browser launch-session --persistent-session my-session --write-mode readonly $ firecrawl browser launch-session -o session.json --json ` ) .action(async (options) => { + if ( + options.writeMode && + !['readonly', 'readwrite'].includes(options.writeMode) + ) { + console.error('Error: --write-mode must be "readonly" or "readwrite"'); + process.exit(1); + } await handleBrowserLaunch({ ttl: options.ttl, ttlInactivity: options.ttlInactivity, + persistentSession: options.persistentSession, + writeMode: options.writeMode, apiKey: options.apiKey, apiUrl: options.apiUrl, output: options.output, From 5daaa83816bbbf36193bddf9ea24311ba430aac5 Mon Sep 17 00:00:00 2001 From: Developers Digest <124798203+developersdigest@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:11:05 -0500 Subject: [PATCH 2/3] Rename persistentSession to profile --- src/commands/browser.ts | 20 ++++++++++---------- src/index.ts | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/commands/browser.ts b/src/commands/browser.ts index 325d5dd009..7ced874930 100644 --- a/src/commands/browser.ts +++ b/src/commands/browser.ts @@ -16,7 +16,7 @@ import { writeOutput } from '../utils/output'; export interface BrowserLaunchOptions { ttl?: number; ttlInactivity?: number; - persistentSession?: string; + profile?: string; writeMode?: 'readonly' | 'readwrite'; apiKey?: string; apiUrl?: string; @@ -52,7 +52,7 @@ export interface BrowserCloseOptions { export interface BrowserQuickExecuteOptions { code: string; - persistentSession?: string; + profile?: string; writeMode?: 'readonly' | 'readwrite'; apiKey?: string; apiUrl?: string; @@ -72,7 +72,7 @@ export async function handleBrowserLaunch( const args: { ttl?: number; activityTtl?: number; - persistentSession?: { + profile?: { name: string; writeMode?: 'readonly' | 'readwrite'; }; @@ -80,9 +80,9 @@ export async function handleBrowserLaunch( if (options.ttl !== undefined) args.ttl = options.ttl; if (options.ttlInactivity !== undefined) args.activityTtl = options.ttlInactivity; - if (options.persistentSession) { - args.persistentSession = { - name: options.persistentSession, + if (options.profile) { + args.profile = { + name: options.profile, writeMode: options.writeMode, }; } @@ -289,14 +289,14 @@ export async function handleBrowserQuickExecute( const app = getClient({ apiKey: options.apiKey, apiUrl: options.apiUrl }); const launchArgs: { - persistentSession?: { + profile?: { name: string; writeMode?: 'readonly' | 'readwrite'; }; } = {}; - if (options.persistentSession) { - launchArgs.persistentSession = { - name: options.persistentSession, + if (options.profile) { + launchArgs.profile = { + name: options.profile, writeMode: options.writeMode, }; } diff --git a/src/index.ts b/src/index.ts index 1d01bd287c..7ef8b1a6fe 100644 --- a/src/index.ts +++ b/src/index.ts @@ -737,12 +737,12 @@ function createBrowserCommand(): Command { ) .option('--api-url ', 'API URL (overrides global --api-url)') .option( - '--persistent-session ', - 'Name for a persistent session (survives close, reconnect by name later)' + '--profile ', + 'Name for a profile (survives close, reconnect by name later)' ) .option( '--write-mode ', - 'Write mode for persistent session: readonly or readwrite (default: readwrite)' + 'Write mode for profile: readonly or readwrite (default: readwrite)' ) .option('-o, --output ', 'Output file path (default: stdout)') .option('--json', 'Output as JSON format', false) @@ -759,7 +759,7 @@ function createBrowserCommand(): Command { } await handleBrowserQuickExecute({ code, - persistentSession: options.persistentSession, + profile: options.profile, writeMode: options.writeMode, apiKey: options.apiKey, apiUrl: options.apiUrl, @@ -805,12 +805,12 @@ Explicit subcommands: ) .option('--ttl-inactivity ', 'Inactivity TTL in seconds', parseInt) .option( - '--persistent-session ', - 'Name for a persistent session (survives close, reconnect by name later)' + '--profile ', + 'Name for a profile (survives close, reconnect by name later)' ) .option( '--write-mode ', - 'Write mode for persistent session: readonly or readwrite (default: readwrite)' + 'Write mode for profile: readonly or readwrite (default: readwrite)' ) .option( '-k, --api-key ', @@ -833,8 +833,8 @@ Examples: $ firecrawl browser launch-session $ firecrawl browser launch-session --ttl 600 $ firecrawl browser launch-session --ttl 300 --ttl-inactivity 60 - $ firecrawl browser launch-session --persistent-session my-session - $ firecrawl browser launch-session --persistent-session my-session --write-mode readonly + $ firecrawl browser launch-session --profile my-session + $ firecrawl browser launch-session --profile my-session --write-mode readonly $ firecrawl browser launch-session -o session.json --json ` ) @@ -849,7 +849,7 @@ Examples: await handleBrowserLaunch({ ttl: options.ttl, ttlInactivity: options.ttlInactivity, - persistentSession: options.persistentSession, + profile: options.profile, writeMode: options.writeMode, apiKey: options.apiKey, apiUrl: options.apiUrl, From 7915cf9fdfeb64bbe3b5aa56bc9c6535ff336d8b Mon Sep 17 00:00:00 2001 From: Developers Digest <124798203+developersdigest@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:12:08 -0500 Subject: [PATCH 3/3] Bump to v1.8.0; rename flag to --profile Update package.json version to 1.8.0 and revise documentation (skills/firecrawl-cli/SKILL.md) to replace usages of --persistent-session with --profile. Adjust examples and the options list to reflect the new flag name; no functional code changes. --- package.json | 2 +- skills/firecrawl-cli/SKILL.md | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 1b64f58669..acaf7cba2d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firecrawl-cli", - "version": "1.7.1", + "version": "1.8.0", "description": "Command-line interface for Firecrawl. Scrape, crawl, and extract data from any website directly from your terminal.", "main": "dist/index.js", "bin": { diff --git a/skills/firecrawl-cli/SKILL.md b/skills/firecrawl-cli/SKILL.md index a40e128b1c..308696efb8 100644 --- a/skills/firecrawl-cli/SKILL.md +++ b/skills/firecrawl-cli/SKILL.md @@ -95,7 +95,7 @@ browser "scrape" -o .firecrawl/products-p2.md → extract page 2 content **Example: login then scrape authenticated content** ``` -browser launch-session --persistent-session my-app → create a named persistent session +browser launch-session --profile my-app → create a named persistent session browser "open https://app.example.com/login" → navigate to login browser "snapshot -i" → find form fields browser "fill @e3 'user@example.com'" → fill email @@ -104,7 +104,7 @@ browser "click @e7" → click Login browser "wait 2" → wait for redirect browser close → disconnect, state persisted -browser launch-session --persistent-session my-app → reconnect, cookies intact +browser launch-session --profile my-app → reconnect, cookies intact browser "open https://app.example.com/dashboard" → already logged in browser "scrape" -o .firecrawl/dashboard.md → extract authenticated content browser close @@ -271,13 +271,13 @@ Shorthand auto-launches a session if none exists - no setup required. Session management: `launch-session --ttl 600`, `list`, `close` -Options: `--ttl `, `--ttl-inactivity `, `--session `, `--persistent-session `, `--write-mode `, `-o` +Options: `--ttl `, `--ttl-inactivity `, `--session `, `--profile `, `--write-mode `, `-o` **Persistent sessions** survive close and can be reconnected by name. Use them when you need to login first, then come back later to do work while already authenticated: ```bash # Session 1: Login and save state -firecrawl browser launch-session --persistent-session my-app +firecrawl browser launch-session --profile my-app firecrawl browser "open https://app.example.com/login" firecrawl browser "snapshot -i" firecrawl browser "fill @e3 'user@example.com'" @@ -287,7 +287,7 @@ firecrawl browser "wait 2" firecrawl browser close # Session 2: Come back authenticated -firecrawl browser launch-session --persistent-session my-app +firecrawl browser launch-session --profile my-app firecrawl browser "open https://app.example.com/dashboard" firecrawl browser "scrape" -o .firecrawl/dashboard.md firecrawl browser close @@ -296,13 +296,13 @@ firecrawl browser close Read-only reconnect (no writes to session state): ```bash -firecrawl browser launch-session --persistent-session my-app --write-mode readonly +firecrawl browser launch-session --profile my-app --write-mode readonly ``` Shorthand with persistent session: ```bash -firecrawl browser --persistent-session my-app "open https://example.com" +firecrawl browser --profile my-app "open https://example.com" ``` ### credit-usage