ScreenshotNeo

BlogHow-to

Open a Browser in Playwright

Launch Chromium, Firefox, or WebKit in Playwright, choose headed or headless mode, manage contexts, and troubleshoot common browser startup errors.

By the ScreenshotNeo team1 October 20267 min read

To open a browser in Playwright, launch a browser engine, create a page, navigate to a URL, and close the browser when finished. In Node.js, the smallest working example is:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  console.log(await page.title());
  await browser.close();
})();

chromium.launch() starts Playwright’s bundled Chromium. Replace chromium with firefox or webkit to start another supported engine. Browser launch and navigation are asynchronous, so use await. The official references are the BrowserType API and Playwright Library.

1. Install Playwright and its browsers

Install the library in an existing Node.js project:

npm install playwright
npx playwright install

On supported Linux environments, install Chromium and operating-system dependencies together:

npx playwright install --with-deps chromium

Keep Playwright current and install browser binaries through the Playwright CLI. The bundled browser versions are the best-supported route. A custom executable path can work, but Playwright documents executablePath as an option to use with extreme caution.

2. Launch a visible browser window

Playwright runs headless by default, so no window appears. Set headless: false when you need to watch the browser while debugging:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.waitForTimeout(3000);
  await browser.close();
})();

Headed mode needs a graphical display. On a local desktop this normally works directly. In a headless Linux server or container, use a virtual display such as Xvfb or keep headless: true.

3. Use explicit browser contexts in production

browser.newPage() is a convenience method that creates a page in a new browser context. It is suitable for short scripts and one-page examples. Production code and test frameworks should create the context explicitly so they control isolation and cleanup:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext({
    viewport: { width: 1440, height: 900 },
    timezoneId: 'UTC'
  });
  const page = await context.newPage();

  try {
    await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
    console.log(await page.title());
  } finally {
    await context.close();
    await browser.close();
  }
})();

Contexts do not share cookies or cache with other contexts. Close explicitly created contexts before closing the browser so artifacts such as HAR files and videos can be flushed. Closing the browser also closes its pages and remaining contexts.

4. Choose Chromium, Firefox, or WebKit

Playwright exposes three browser types:

Browser type Launch call Use it when
Chromium chromium.launch() You need Chromium-based behavior or the default Playwright path.
Firefox firefox.launch() You need to check Firefox-specific rendering or behavior.
WebKit webkit.launch() You need WebKit coverage, including Safari-like behavior.
const { firefox, webkit } = require('playwright');

(async () => {
  const firefoxBrowser = await firefox.launch();
  const firefoxPage = await firefoxBrowser.newPage();
  await firefoxPage.goto('https://example.com');
  await firefoxBrowser.close();

  const webkitBrowser = await webkit.launch();
  const webkitPage = await webkitBrowser.newPage();
  await webkitPage.goto('https://example.com');
  await webkitBrowser.close();
})();

Branded Chrome and Microsoft Edge channels are available through the channel launch option:

const browser = await chromium.launch({ channel: 'chrome' });

Use the bundled browsers unless a task specifically requires branded-browser behavior. Custom browser arguments can break Playwright functionality, so add them only when you understand their effect.

5. Configure launch and navigation options

Headless and headed mode

const browser = await chromium.launch({ headless: true });
// or
const browser = await chromium.launch({ headless: false });

Browser channel

const browser = await chromium.launch({ channel: 'msedge' });

Channel names depend on the installed branded browser. The bundled browser remains the most predictable option.

await page.goto('https://example.com', {
  waitUntil: 'domcontentloaded',
  timeout: 30000
});

Use domcontentloaded when you need the document structure quickly. Use load when load events matter. Network-idle waits can be unsuitable for pages with long-lived analytics or WebSocket connections; wait for a specific selector when possible.

Context settings

const context = await browser.newContext({
  viewport: { width: 1280, height: 800 },
  locale: 'en-US',
  timezoneId: 'America/New_York',
  colorScheme: 'dark',
  userAgent: 'MyAutomation/1.0'
});

These settings apply to pages in that context and keep sessions isolated from other contexts.

6. Reuse a persistent browser profile

Use launchPersistentContext() when a workflow must retain cookies, local storage, or other profile data between runs:

const { chromium } = require('playwright');

(async () => {
  const context = await chromium.launchPersistentContext('./playwright-profile', {
    headless: false
  });
  const page = context.pages()[0] || await context.newPage();
  await page.goto('https://example.com');
  await context.close();
})();

This method returns the browser’s only context, so there is no separate browser.close() call. Use a dedicated user-data directory for automation. Playwright warns that automating the default Chrome profile is unsupported and can cause pages to fail or the browser to exit.

7. Attach to an existing browser

Playwright connection

If another process launched a Playwright browser server, connect with its WebSocket endpoint:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.connect('ws://localhost:3000/');
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await browser.close();
})();

The connecting and launching sides must use matching major and minor Playwright versions.

Chrome DevTools Protocol

const browser = await chromium.connectOverCDP('http://localhost:9222');

connectOverCDP() works only with Chromium-based browsers and has significantly lower fidelity than Playwright’s own connection protocol. Prefer the Playwright protocol when advanced functionality matters.

8. Open a browser with the Playwright CLI

The official CLI provides a separate workflow from the JavaScript API:

npx playwright-cli open https://example.com
npx playwright-cli close

Use the CLI when you want a quick interactive session. Use browserType.launch() in application code, tests, and repeatable automation.

9. A reliable complete script

This example creates an isolated context, waits for a meaningful page condition, captures a screenshot, and always closes resources:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext({ viewport: { width: 1440, height: 900 } });
  const page = await context.newPage();

  try {
    await page.goto('https://example.com', {
      waitUntil: 'domcontentloaded',
      timeout: 30000
    });
    await page.locator('h1').waitFor({ state: 'visible', timeout: 10000 });
    await page.screenshot({ path: 'example.png', fullPage: true });
  } finally {
    await context.close();
    await browser.close();
  }
})();

10. Troubleshooting browser startup

Error or symptom Likely cause Fix
Executable doesn't exist Browser binaries were not installed. Run npx playwright install, or install a specific browser such as npx playwright install chromium.
Linux missing shared libraries Operating-system dependencies are absent. Run npx playwright install --with-deps chromium on a supported Linux environment.
No visible window Headless mode is the default. Launch with { headless: false } and ensure a graphical display is available.
Browser exits immediately The script reached the end or cleanup ran early. Await navigation and interactions, then close in a final cleanup block.
Navigation timeout The page is slow, blocked, or waiting on resources that never finish. Set a suitable timeout, use domcontentloaded, and wait for a specific selector instead of indefinite network idle.
Connection version error Client and browser server have different major or minor Playwright versions. Install and run matching Playwright versions on both sides.
Persistent profile is locked Another browser process is using the same user-data directory. Give each concurrent run its own dedicated directory and close the previous process.
Pages fail with a default Chrome profile Playwright does not support automating the default Chrome profile. Use a separate automation profile with launchPersistentContext().
Automation behaves differently over CDP CDP attachment has lower fidelity than Playwright’s protocol. Use connect() to a Playwright browser server when possible.

11. Performance, reliability, and cost considerations

  • Launch one browser and create multiple isolated contexts when runs can share the browser process. Close each context after its work.
  • Use a specific readiness locator rather than a long fixed delay. This reduces idle time while avoiding screenshots of incomplete pages.
  • Keep browser and Playwright versions aligned, especially when connecting to a remote browser.
  • Use headless mode for unattended jobs and headed mode for local diagnosis.
  • Persistent contexts preserve state but reduce isolation; separate profile directories are required for parallel jobs.
  • Browser automation consumes CPU, memory, and download storage on the machine running it. Playwright itself has no per-screenshot service charge in this local workflow; infrastructure cost depends on your runtime.

12. Or skip the browser setup

If your goal is a dependable website screenshot rather than browser orchestration, ScreenshotNeo provides a single HTTP request. It handles the browser setup for you and returns PNG, JPEG, WebP, or PDF output.

curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'}, timeout=90)
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API documentation for the full option list. Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing result. ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.

Create a free ScreenshotNeo account and start with 1,000 screenshots each month at no charge.

13. FAQ

Does Playwright open a real browser?

Yes. It launches Playwright-managed Chromium, Firefox, or WebKit binaries. The browser is headless unless you set headless: false.

What is the simplest launch call?

const browser = await chromium.launch(); starts Chromium. Create a page, call page.goto(), then close the browser.

Should I use newPage() or newContext()?

Use newPage() for short snippets. Use an explicit context for production code, isolation, and predictable cleanup.

Can Playwright control installed Chrome?

Yes, through a supported channel such as channel: 'chrome'. The bundled browsers are the best-supported option, and custom executable paths are used at your own risk.

Can I open an existing browser?

Yes. Use connect() for a Playwright browser endpoint or connectOverCDP() for a Chromium DevTools endpoint. CDP has lower fidelity and is Chromium-only.