Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Here is a complete Playwright script in JavaScript: install Playwright, open Chromium, navigate to a page, interact through an accessible locator, assert the result, and close the browser. The title does not specify a language, so this guide uses Node.js JavaScript; Playwright also supports TypeScript, Python, Java, and C#.

What a Playwright script does

A script tells a real browser to load a page and perform actions that a user could take, such as clicking a link or filling a form. A useful script does more than execute those actions: it checks that the expected outcome appeared. Without an assertion, a script can finish even when the application did the wrong thing.

Playwright’s official guidance puts the goal plainly: “Automated tests should verify that the application code works for the end users.” (Playwright Best Practices.) The example below follows that principle by checking a visible result rather than merely confirming that a click ran.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install Playwright and its browser

For a standalone JavaScript script, use Node.js and the Playwright library. Install the package and its Chromium browser binary in your project directory:

npm init -y
npm install playwright
npx playwright install chromium

The install command for the browser is important: installing the JavaScript package alone does not guarantee that the browser binary is present. You can install other supported browsers with npx playwright install firefox or npx playwright install webkit. The Node.js library documentation describes launching Chromium, Firefox, and WebKit from a Node script (Playwright Library).

Create a file named playwright-script.js in the project directory. This example opens the Playwright documentation homepage, clicks the link named “Get started,” and checks that the destination heading is visible:

const { chromium } = require('playwright');
const { expect } = require('@playwright/test');

(async () => {
  const browser = await chromium.launch({ headless: true });

  try {
    const page = await browser.newPage();
    await page.goto('https://playwright.dev/');

    await page.getByRole('link', { name: 'Get started' }).click();

    await expect(
      page.getByRole('heading', { name: 'Installation' })
    ).toBeVisible();
  } finally {
    await browser.close();
  }
})().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Install the assertion package used in this example if it is not already in the project:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
npm install -D @playwright/test

Run the script with node playwright-script.js. A successful run exits without an assertion error; if the link or expected heading is absent, Playwright reports a failure and Node exits with a nonzero status. The finally block closes the browser on success or failure, avoiding an orphaned browser process.

Understand the browser flow

Launch and navigate

chromium.launch() starts a browser instance. browser.newPage() creates a page for the interaction, and page.goto() navigates to the target URL. The example sets headless: true, so the browser runs without displaying a window. For local debugging, set it to false to see the browser UI.

Find controls through locators

A locator describes an element Playwright should find when an action or assertion runs. Prefer locators that represent what users perceive: getByRole() for a button, link, or heading; getByLabel() for a labeled form control; and getByText() for visible text. If an application exposes a stable test identifier, use getByTestId(). These choices are usually more resilient than generated CSS class names or long paths through nested DOM elements.

For example, a form flow might use:

await page.getByLabel('Email address').fill('[email protected]');
await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.getByText('Check your inbox')).toBeVisible();

Use the actual label, button name, and expected message in your application. A locator can also be narrowed by chaining or filtering: first identify a list item or component by its text, then find the intended button within it. This avoids accidentally clicking a similarly named control elsewhere on the page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Act, then assert the outcome

Actions such as click() and fill() wait for their target to be actionable. Assertions such as toBeVisible() are web-first: they retry while waiting for the expected condition rather than checking only once at an arbitrary moment. That waiting behavior helps avoid races between an action and a page update (Playwright Assertions).

A fragile pattern is to inspect visibility immediately and compare a boolean:

expect(await locator.isVisible()).toBe(true);

That check can run before the UI has finished changing. Prefer await expect(locator).toBeVisible(), which waits and retries within the assertion timeout. Make the assertion match the behavior that matters: a success message, a changed heading, a navigated URL, or an enabled control.

Write a test with Playwright Test instead

A standalone script is handy for one-off automation or a small task. For a suite of end-to-end tests, Playwright Test supplies a test runner, assertions, and managed browser lifecycle. Install the runner and its browser binaries:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
npm install -D @playwright/test
npx playwright install chromium

Create tests/navigation.spec.js:

const { test, expect } = require('@playwright/test');

test('Get started opens the installation guide', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  await page.getByRole('link', { name: 'Get started' }).click();
  await expect(
    page.getByRole('heading', { name: 'Installation' })
  ).toBeVisible();
});

Run it with:

npx playwright test

The runner provides a fresh page fixture for the test and handles its lifecycle; do not manually launch and close a browser in each test unless you have a specific reason. Independent tests should not rely on cookies, local storage, or mutable state left behind by another test. Each should be runnable on its own with explicit setup and data, which makes failures easier to reproduce.

Use Codegen to draft interactions

Playwright Codegen can record browser interactions and suggest locators. Start it with a URL:

npx playwright codegen playwright.dev

A browser and inspector open; as you navigate and interact, Codegen produces candidate code. It analyzes the rendered page and prioritizes role, text, and test-id locators, and can improve a locator when multiple elements match (Playwright Codegen).

Treat generated output as a draft, not a finished test. Remove accidental clicks, replace selectors that depend on unstable markup, and add an assertion for the business outcome. Recording “click this control” is not the same as verifying that the user-facing task succeeded.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the right setup and debugging mode

  • Standalone script: useful for a focused browser task or learning the API; you handle browser cleanup and organize assertions yourself.
  • Playwright Test: a better fit for a repeatable test suite, with test structure, fixtures, and runner-managed lifecycle.
  • Hand-written locators: best when you know the user-facing behavior and want deliberate, maintainable checks.
  • Codegen-assisted locators: useful for discovering interactions and selectors, but review the generated sequence and assertions.
  • Headless execution: appropriate for routine automated runs where a visible browser is unnecessary.
  • Headed execution: useful while debugging because you can watch the browser perform the steps.

When a test fails, inspect the actual UI and the exact failed locator or assertion. Playwright’s best-practices guide points to the HTML report, trace viewer, and inspector as debugging tools (Best Practices). Keep authentication and test data explicit; a test that only passes after a previous test has changed shared state is not reliably isolated.

Python option

If your project uses Python, Playwright provides synchronous and asynchronous APIs. The official Python documentation recommends its pytest plugin for end-to-end tests and documents Codegen as a next step (Playwright for Python). Install the package and Chromium, then create a synchronous script:

pip install playwright
playwright install chromium
from playwright.sync_api import sync_playwright, expect

with sync_playwright() as playwright:
    browser = playwright.chromium.launch(headless=True)
    try:
        page = browser.new_page()
        page.goto("https://playwright.dev/")
        page.get_by_role("link", name="Get started").click()
        expect(page.get_by_role("heading", name="Installation")).to_be_visible()
    finally:
        browser.close()

For a Python test suite, install and use the official pytest plugin as documented by Playwright rather than building test lifecycle management around a collection of ad hoc scripts. The same locator and assertion principles apply: prefer user-facing names and verify an outcome that can fail when the application is wrong.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common failures

Browser executable is missing

Symptom: launch fails because the expected browser executable cannot be found. Cause: the Playwright package was installed, but its browser binary was not installed for this environment. Fix: run npx playwright install chromium for the Node.js example, or playwright install chromium for Python.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Locator matches nothing or too many elements

Symptom: an action times out, or Playwright reports that a locator is ambiguous. Cause: the accessible name or text differs from what the script expects, the element is not yet present, or the locator matches several controls. Fix: inspect the rendered page with the inspector, choose the correct role or label, and narrow the locator to a containing component where appropriate. Avoid solving ambiguity with a brittle index unless element order is itself part of the intended behavior.

Assertion fails after an action

Symptom: a click completes but the expected message or heading is not visible. Cause: the application may not have completed the expected transition, the assertion describes the wrong outcome, or the action did not trigger the intended flow. Fix: verify the page’s actual behavior and assert the right visible result with a web-first assertion. Do not replace the assertion with a fixed sleep as a general remedy; a delay can make a script slower without making the condition correct.

The script leaves browser processes behind

Symptom: a process remains after a failed run. Cause: cleanup was skipped when an exception occurred. Fix: put standalone-script cleanup in a finally block, as in the example. With Playwright Test, allow the runner to manage its browser fixtures.

A test passes alone but fails in the suite

Symptom: outcome depends on which test ran earlier. Cause: tests share session state, cookies, storage, or mutable test data. Fix: make setup explicit and each test independently runnable with its own browser context and state. Diagnose with the report, trace viewer, or inspector instead of adding hidden dependencies between tests.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If your goal is to capture a page rather than test an interaction, a screenshot API can return an image or PDF without you installing and managing a browser. ScreenshotNeo provides a one-request screenshot API and an MCP server for AI agents. This call saves a WebP screenshot of the Stripe homepage:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie banners and consent prompts, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, with response headers indicating the page verdict and whether the request was billed. Its MCP server offers take_screenshot, get_page_info, and capture_pdf to 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 shots. Sign up free for 1,000 screenshots a month, with no card required.

Build scripts that test what matters

A dependable Playwright script has a small, explicit flow: launch, navigate, locate a control in a user-centered way, act, assert the visible result, and clean up. Use the test runner for suites, Codegen as a locator aid rather than an unquestioned authority, and reports or traces when failures need investigation.

Frequently Asked Questions

Can Playwright write a test automatically?

Codegen records interactions and proposes locators, but you should review its output and add an assertion for the outcome you intend to test.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should I use JavaScript or Python?

Use the language that fits your application and team’s tooling. This guide’s runnable flow uses Node.js JavaScript; Playwright also documents Python, including sync and async APIs.

Does a Playwright script need an assertion?

For a test, yes: an assertion makes the script fail when the expected user-visible result does not occur.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.