Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docs/src/getting-started-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,29 @@ playwright-cli open --browser=webkit
playwright-cli open --browser=msedge
```

### Launch options

Every launch option is available as an `open` flag, so proxies, self-signed dev servers and extensions take one command and no config file:

```bash
playwright-cli open --proxy=http://user:pass@proxy.example.com:3128 --proxy-bypass=.internal.example.com
playwright-cli open --ignore-https-errors https://localhost:8443
playwright-cli open --user-agent="MyAgent/1.0"
playwright-cli open --executable-path=/path/to/chromium
playwright-cli open --init-script=./mock-geolocation.js # runs in every page, repeatable
playwright-cli open --extension=./my-extension # unpacked extension, Chromium only, repeatable, implies --persistent
playwright-cli open --state=auth.json # cookies and storage saved by state-save
playwright-cli open --allowed-origins="https://app.example.com;http://localhost:*"
playwright-cli open --blocked-origins="https://ads.example.com"
```

When `--proxy` is not given, the `HTTPS_PROXY`, `HTTP_PROXY` and `NO_PROXY` environment variables are honored, the same way `curl`, `npm` and `git` honor them. Google Chrome no longer loads unpacked extensions, so `--extension` runs the bundled Chromium unless `--browser` picks another Chromium-based browser.

Each flag has an environment variable counterpart, for example `PLAYWRIGHT_MCP_PROXY_SERVER`, `PLAYWRIGHT_MCP_IGNORE_HTTPS_ERRORS`, `PLAYWRIGHT_MCP_USER_AGENT`, `PLAYWRIGHT_MCP_EXECUTABLE_PATH`, `PLAYWRIGHT_MCP_INIT_SCRIPT`, `PLAYWRIGHT_MCP_LOAD_EXTENSION`, `PLAYWRIGHT_MCP_STORAGE_STATE`, `PLAYWRIGHT_MCP_ALLOWED_ORIGINS` and `PLAYWRIGHT_MCP_BLOCKED_ORIGINS`. Flags win over environment variables, which win over the config file. Run `playwright-cli open --help` for the full list.

### Configuration file

For advanced settings, use a JSON config file:
For settings that have no flag, use a JSON config file:

```bash
playwright-cli --config path/to/config.json open example.com
Expand Down Expand Up @@ -320,6 +340,7 @@ This requires the [Playwright Extension](https://github.com/microsoft/playwright
| **Get page snapshot** | `playwright-cli snapshot` |
| **Run headed** | `playwright-cli open https://example.com --headed` |
| **Use Firefox** | `playwright-cli open --browser=firefox` |
| **Use a proxy** | `playwright-cli open --proxy=http://proxy:3128` |
| **Monitor sessions** | `playwright-cli show` |
| **List page WebMCP tools** | `playwright-cli webmcp-list` |

Expand Down
10 changes: 10 additions & 0 deletions packages/playwright-core/src/tools/cli-client/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ type OpenOptions = {
mobile?: boolean;
persistent?: boolean;
profile?: string;
proxy?: string;
'proxy-bypass'?: string;
'ignore-https-errors'?: boolean;
'user-agent'?: string;
'executable-path'?: string;
'init-script'?: string | string[];
extension?: string | string[];
state?: string;
'allowed-origins'?: string;
'blocked-origins'?: string;
};

const globalOptions: (keyof (GlobalOptions & OpenOptions & AttachOptions))[] = [
Expand Down
39 changes: 36 additions & 3 deletions packages/playwright-core/src/tools/cli-client/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,35 @@ export class Session {
args.push(`--config=${cliArgs.config}`);
if (cliArgs['idle-timeout'] !== undefined)
args.push(`--idle-timeout=${cliArgs['idle-timeout']}`);
if (cliArgs.extension)
if (mode === 'open') {
// `open --extension=<dir>` loads an unpacked extension, unlike `attach --extension` that connects through the Playwright Extension.
for (const dir of flagValues(cliArgs, 'extension'))
args.push(`--load-extension=${dir}`);
for (const script of flagValues(cliArgs, 'init-script'))
args.push(`--init-script=${script}`);
if (cliArgs['ignore-https-errors'])
args.push('--ignore-https-errors');
const singleValueFlags: [flag: string, daemonFlag: string][] = [
['proxy', 'proxy-server'],
['proxy-bypass', 'proxy-bypass'],
['user-agent', 'user-agent'],
['executable-path', 'executable-path'],
['state', 'storage-state'],
['allowed-origins', 'allowed-origins'],
['blocked-origins', 'blocked-origins'],
];
for (const [flag, daemonFlag] of singleValueFlags) {
const value = flagValues(cliArgs, flag).at(-1);
if (value !== undefined)
args.push(`--${daemonFlag}=${value}`);
}
} else if (cliArgs.extension) {
args.push('--extension');
else if (cliArgs.cdp)
} else if (cliArgs.cdp) {
args.push(`--cdp=${cliArgs.cdp}`);
else if (cliArgs.endpoint)
} else if (cliArgs.endpoint) {
args.push(`--endpoint=${cliArgs.endpoint}`);
}

const child = spawn(process.execPath, args, {
detached: true,
Expand Down Expand Up @@ -206,6 +229,16 @@ export class Session {
}
}

// Minimist yields `true` for a flag without a value, a string for one occurrence and an array for a repeated one.
function flagValues(cliArgs: MinimistArgs, flag: string): string[] {
const value = cliArgs[flag];
if (value === undefined || value === false)
return [];
if (value === true)
throw new Error(`error: '--${flag}' option requires a value`);
return Array.isArray(value) ? value.map(String) : [String(value)];
}

class SocketConnectionClient {
private _connection: SocketConnection;
private _nextMessageId = 1;
Expand Down
12 changes: 11 additions & 1 deletion packages/playwright-core/src/tools/cli-daemon/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,24 @@ const open = declareCommand({
url: z.string().optional().describe('The URL to navigate to'),
}),
options: z.object({
browser: z.string().optional().describe('Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.'),
browser: z.string().optional().describe('Browser or chrome channel to use, possible values: chrome, chromium, firefox, webkit, msedge.'),
config: z.string().optional().describe('Path to the configuration file, defaults to .playwright/cli.config.json'),
device: z.string().optional().describe('Emulate a specific device, for example "iPhone 15".'),
headed: z.boolean().optional().describe('Run browser in headed mode'),
['idle-timeout']: numberArg.optional().describe('Shut the session down after this many milliseconds without a command. Defaults to one hour for headless browsers, never for headed ones. Pass 0 to disable.'),
mobile: z.boolean().optional().describe('Emulate a generic mobile device (Pixel 10 for Chromium, iPhone 17 for WebKit). Mobile pages are usually lighter, which saves tokens.'),
persistent: z.boolean().optional().describe('Use persistent browser profile'),
profile: z.string().optional().describe('Path to a persistent user data directory.'),
proxy: z.string().optional().describe('Proxy server, for example "http://myproxy:3128", "http://user:pass@myproxy:3128" or "socks5://myproxy:8080". Defaults to HTTPS_PROXY or HTTP_PROXY from the environment.'),
['proxy-bypass']: z.string().optional().describe('Comma-separated domains to bypass the proxy, for example ".com,chromium.org,.domain.com". Defaults to NO_PROXY from the environment.'),
['ignore-https-errors']: z.boolean().optional().describe('Ignore HTTPS errors, for example from self-signed certificates on a dev server.'),
['user-agent']: z.string().optional().describe('User agent string.'),
['executable-path']: z.string().optional().describe('Path to the browser executable.'),
['init-script']: stringArrayArg.optional().describe('Path to a JavaScript file to evaluate in every page before any of the page\'s scripts (repeatable).'),
extension: stringArrayArg.optional().describe('Path to an unpacked extension directory to load, Chromium only, implies --persistent (repeatable).'),
state: z.string().optional().describe('Path to a storage state file (cookies, localStorage) to start the session with, see state-save.'),
['allowed-origins']: z.string().optional().describe('Semicolon-separated list of origins the browser is allowed to request, everything else is blocked.'),
['blocked-origins']: z.string().optional().describe('Semicolon-separated list of origins the browser is blocked from requesting.'),
}),
toolName: '',
toolParams: () => ({}),
Expand Down
10 changes: 10 additions & 0 deletions packages/playwright-core/src/tools/cli-daemon/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ export function decorateProgram(program: Command) {
.option('--cdp <url>', 'connect to an existing browser via CDP endpoint URL')
.option('--endpoint <endpoint>', 'attach to a running Playwright browser endpoint')
.option('--idle-timeout <timeout>', 'shut the session down after this many milliseconds without a command, defaults to one hour for headless browsers', configUtils.numberParser)
.option('--proxy-server <proxy>', 'proxy server, for example "http://myproxy:3128", "http://user:pass@myproxy:3128" or "socks5://myproxy:8080"')
.option('--proxy-bypass <bypass>', 'comma-separated domains to bypass the proxy, for example ".com,chromium.org,.domain.com"')
.option('--ignore-https-errors', 'ignore HTTPS errors, for example from self-signed certificates')
.option('--user-agent <ua string>', 'user agent string')
.option('--executable-path <path>', 'path to the browser executable')
.option('--init-script <path...>', 'path to a JavaScript file to evaluate in every page before any of the page\'s scripts, can be specified multiple times')
.option('--load-extension <path...>', 'path to an unpacked extension directory to load into the browser, can be specified multiple times')
.option('--storage-state <path>', 'path to a storage state file to start the session with')
.option('--allowed-origins <origins>', 'semicolon-separated list of origins the browser is allowed to request', configUtils.semicolonSeparatedList)
.option('--blocked-origins <origins>', 'semicolon-separated list of origins the browser is blocked from requesting', configUtils.semicolonSeparatedList)
.option('--init-workspace', 'initialize workspace')
.option('--init-skills <value>', 'install skills for the given agent type ("claude" or "agents")')
.option('--init-skills-global <value>', 'install skills for the given agent type ("claude" or "agents") into the home directory')
Expand Down
7 changes: 7 additions & 0 deletions packages/playwright-core/src/tools/mcp/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ export type Config = {
* The scripts will be evaluated in every page before any of the page's scripts.
*/
initScript?: string[];

/**
* Paths to unpacked extension directories to load into the browser. Chromium only.
* Google Chrome no longer loads unpacked extensions, so the bundled Chromium build is used
* unless a browser is picked explicitly.
*/
extensions?: string[];
},

/**
Expand Down
Loading
Loading