ScreenshotNeo

BlogHow-to

How to Learn Playwright with Java

Learn Playwright with Java from first Maven script to isolated tests, Codegen, API checks, traces, and CI with runnable examples.

By the ScreenshotNeo team1 October 202612 min read

Direct answer: learn Playwright with Java in stages. Start with a small Maven program that launches a browser, then practice locators and web-first assertions, isolate tests with BrowserContext, add JUnit or TestNG, use Codegen and traces for feedback, and only then add API testing and CI. Playwright’s official Java workflow requires Java, Maven, the Playwright dependency, and browser binaries matched to the Playwright release.

This guide follows the official Playwright Java installation documentation, writing-tests guide, test-runner documentation, Codegen guide, API-testing guide, and browser documentation.

1. Prerequisites and a sensible learning order

You do not need to master every Playwright feature before writing your first test. You need basic Java syntax, classes, exceptions, try-with-resources, Maven dependency management, and enough HTML to recognize buttons, links, forms, and headings.

Stage What to learn Checkpoint
1. Setup Java, Maven, dependency and browser installation A program opens a page and prints its title
2. Browser basics Browser, BrowserContext, Page, navigation, screenshots You can create and close isolated pages
3. Locators Role, text, test-id, CSS and XPath trade-offs A test finds controls by user-visible meaning
4. Assertions Web-first assertions and retry behavior Assertions wait for the expected UI state
5. Test design Fixtures, cleanup, JUnit or TestNG, parallelism Each test has independent browser state
6. Debugging Codegen, headed mode, traces and screenshots You can explain and fix a failing step
7. Expansion APIRequestContext and CI browser installation Tests prepare data through APIs and run unattended

Check the current installation page before setup. The page currently lists Java 8 or later and operating-system versions that can change. It also currently shows Playwright Java version 1.63.0; treat that as a page-specific value and verify the version at publication time.

2. Create a Maven project

Create a directory, add a Maven project, and put the Playwright dependency in pom.xml. Use the version shown by the current official documentation or a deliberately selected version in your project.

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>playwright-java-learning</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.microsoft.playwright</groupId>
      <artifactId>playwright</artifactId>
      <version>1.63.0</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.5.0</version>
        <configuration>
          <mainClass>org.example.App</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Replace the dependency version with the current value on the official page when you publish or start a new project.

3. Install Playwright’s browser binaries

The Java library and browser binaries are version-coupled. Install the browsers after adding the dependency, and repeat the installation after a Playwright upgrade if the required browser revision changes.

mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="install"

You can install one engine when you only need one:

mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="install chromium"

Playwright supports Chromium, Firefox, and WebKit builds. Playwright’s Firefox and WebKit engines are Playwright browser builds, not branded Firefox or Safari. If your test must exercise a branded browser, review the documented Chrome and Edge channel options in the browser guide.

4. Run your first Java program

Create src/main/java/org/example/App.java. The try-with-resources block closes Playwright and the browser even when the program fails.

package org.example;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;

public class App {
  public static void main(String[] args) {
    try (Playwright playwright = Playwright.create()) {
      Browser browser = playwright.chromium().launch(
          new BrowserType.LaunchOptions().setHeadless(true));
      Page page = browser.newPage();
      page.navigate("https://playwright.dev");
      System.out.println(page.title());
      browser.close();
    }
  }
}
mvn compile exec:java

For visual learning, set setHeadless(false). A headed run shows the browser while your Java code executes. A second useful exercise is saving a screenshot:

package org.example;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;

public class ScreenshotExample {
  public static void main(String[] args) {
    try (Playwright playwright = Playwright.create()) {
      try (Browser browser = playwright.webkit().launch()) {
        Page page = browser.newPage();
        page.navigate("https://playwright.dev");
        page.screenshot(new Page.ScreenshotOptions().setPath("playwright.png"));
      }
    }
  }
}

5. Learn locators and web-first assertions

Locators describe how a user identifies an element and provide auto-waiting for actions. Prefer accessible roles and names, then text or test IDs supplied by the application. CSS and XPath are useful when necessary, but long selectors tied to layout or generated classes are harder to maintain.

package org.example;

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;

import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

public class LocatorExample {
  public static void main(String[] args) {
    try (Playwright playwright = Playwright.create()) {
      try (Browser browser = playwright.chromium().launch()) {
        Page page = browser.newPage();
        page.navigate("https://playwright.dev");

        assertThat(page).hasTitle("Playwright");
        var getStarted = page.getByRole(
            com.microsoft.playwright.options.AriaRole.LINK,
            new Page.GetByRoleOptions().setName("Get started"));
        assertThat(getStarted).hasAttribute("href", "/docs/intro");
        getStarted.click();
        assertThat(page.getByRole(
            com.microsoft.playwright.options.AriaRole.HEADING,
            new Page.GetByRoleOptions().setName("Installation"))).isVisible();
      }
    }
  }
}

assertThat performs a web-first assertion: it retries until the expected condition is met or the assertion timeout expires. This is safer than reading a value once and immediately comparing it while the page is still rendering.

Locator selection checklist

  • Use getByRole with a name for buttons, links, headings, checkboxes and other semantic controls.
  • Use getByText for stable, user-visible text when a role is not the best description.
  • Use getByTestId when your team owns stable test IDs.
  • Use CSS for a stable attribute or component boundary.
  • Use XPath only when the DOM relationship genuinely requires it.
  • Assert the result of an action, not merely that the click call returned.

6. Understand Browser, BrowserContext and Page

A Browser is the running engine. A BrowserContext is an isolated, in-memory browser profile containing cookies, local storage and session state. A Page is a tab inside a context.

Reuse a browser when practical, but create a new context for each test. This prevents authentication, cookies and storage from leaking between tests.

try (Playwright playwright = Playwright.create()) {
  try (Browser browser = playwright.chromium().launch()) {
    try (BrowserContext context = browser.newContext()) {
      Page page = context.newPage();
      page.navigate("https://playwright.dev");
      // Test one
    }

    try (BrowserContext anotherContext = browser.newContext()) {
      Page anotherPage = anotherContext.newPage();
      anotherPage.navigate("https://playwright.dev/docs/intro");
      // Test two with separate cookies and storage
    }
  }
}

Close pages, contexts and browsers deliberately. In a suite, cleanup belongs in the runner lifecycle so failed tests do not leave processes or state behind.

7. Move from a script to JUnit or TestNG

A standalone program is the fastest way to learn. A runner adds discovery, setup and teardown, reporting and parallel execution. Playwright’s Java documentation shows both JUnit and TestNG integrations. Choose the framework your project already uses; the documentation does not establish a universal winner.

JUnit lifecycle example

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.BrowserType;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

class DocsTest {
  static Playwright playwright;
  static Browser browser;
  BrowserContext context;
  Page page;

  @BeforeAll
  static void startBrowser() {
    playwright = Playwright.create();
    browser = playwright.chromium().launch(
        new BrowserType.LaunchOptions().setHeadless(true));
  }

  @org.junit.jupiter.api.BeforeEach
  void startContext() {
    context = browser.newContext();
    page = context.newPage();
  }

  @Test
  void installationPageHasHeading() {
    page.navigate("https://playwright.dev/docs/intro");
    assertThat(page).hasTitle("Installation");
    assertThat(page.getByRole(
        com.microsoft.playwright.options.AriaRole.HEADING,
        new Page.GetByRoleOptions().setName("Installation"))).isVisible();
  }

  @org.junit.jupiter.api.AfterEach
  void closeContext() {
    context.close();
  }

  @AfterAll
  static void stopBrowser() {
    browser.close();
    playwright.close();
  }
}

For parallel execution, do not share Playwright objects across threads without synchronization. The Java guidance recommends a Playwright instance per thread. Keep contexts and pages owned by one test or one worker.

8. Use Codegen to learn faster

Codegen opens a browser and Playwright Inspector, records actions and suggests locators. It can also add visibility, text and value assertions. Start it against a page you control:

mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="codegen https://playwright.dev"

Codegen is a teaching aid, not a finished test strategy. After recording:

  1. Replace incidental clicks with an explicit scenario.
  2. Review each suggested locator and prefer role, text or test ID when appropriate.
  3. Add assertions for the outcome that matters to a user.
  4. Remove generated waits that duplicate Playwright’s automatic waiting.
  5. Extract setup and reusable page behavior only after the test is understandable.

9. Add API testing after browser fundamentals

APIRequestContext lets a Java test call REST endpoints directly. Use it to prepare server state before a UI test or verify a server-side result after a browser action. It is a natural next module after you understand contexts, pages and assertions.

import com.microsoft.playwright.APIRequest;
import com.microsoft.playwright.APIRequestContext;
import com.microsoft.playwright.Playwright;

import java.util.HashMap;
import java.util.Map;

try (Playwright playwright = Playwright.create()) {
  Map<String, String> headers = new HashMap<>();
  headers.put("Accept", "application/json");

  APIRequestContext request = playwright.request().newContext(
      new APIRequest.NewContextOptions()
          .setBaseURL("https://example.test")
          .setExtraHTTPHeaders(headers));

  var response = request.get("/api/health");
  System.out.println(response.status());
  request.dispose();
}

Use the API-testing documentation for authentication, request bodies and response handling. Keep browser and API responsibilities clear: APIs prepare or verify data; the browser test proves the user-visible workflow.

10. Debug failures with headed mode, screenshots and traces

When a test fails, first reproduce it in headed mode. Add a screenshot at the failing point and inspect the locator, URL, console output and network behavior. Playwright’s trace workflow can preserve actions, snapshots and artifacts for later inspection; follow the current trace instructions in the official documentation.

BrowserContext context = browser.newContext(
    new Browser.NewContextOptions()
        .setRecordVideoDir(Paths.get("artifacts/video")));
Page page = context.newPage();
page.navigate("https://playwright.dev");
page.screenshot(new Page.ScreenshotOptions()
    .setPath("artifacts/page.png")
    .setFullPage(true));
context.close();

11. Run Playwright Java in CI

CI machines need the Java dependency, Playwright’s browser binaries and, on Linux, the required system dependencies. The official CI guidance documents the install --with-deps option and platform-specific details.

mvn exec:java -e \
  -Dexec.mainClass=com.microsoft.playwright.CLI \
  -Dexec.args="install --with-deps"
mvn test

Pin your Maven dependency, install browsers in the CI image or setup step, publish screenshots and traces as artifacts, and keep each test’s context isolated. Recheck the CI instructions when changing operating systems or Playwright versions.

12. Or skip the browser setup

If your goal is to obtain screenshots rather than learn browser automation, ScreenshotNeo provides a website screenshot API and MCP server. It accepts one GET request and returns PNG, JPEG, WebP or PDF. Before capture it can accept cookie and consent banners and remove more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers report the page verdict and billing status.

See the ScreenshotNeo API documentation for all options.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://playwright.dev \
  -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://playwright.dev"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://playwright.dev'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
require('fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo also supports full-page capture with lazy images loaded, CSS-element capture, dark mode, device presets and custom viewports, retina scale, PDF paper settings and page ranges, custom CSS and JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients.

There is a free allowance of 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account.

13. Common errors and fixes

Error or symptom Likely cause Fix
Executable not found Browser binaries were not installed or no longer match the dependency. Run the Playwright CLI install command again after checking the dependency version.
Page closes unexpectedly Playwright, browser or context was closed before the action completed. Use try-with-resources and keep the owning scope alive until assertions finish.
Timeout waiting for a locator Wrong role/name, unstable selector, navigation failure or an element that never becomes visible. Inspect the page in headed mode, verify the URL and choose a stable role, text or test ID.
Assertion is flaky A one-time value read races the application’s rendering. Use a web-first assertThat assertion and wait for the user-visible state.
Tests affect one another Cookies or local storage are shared. Create and close a new BrowserContext for each test.
Parallel tests interfere Playwright objects are shared across threads. Use a Playwright instance per worker or thread and keep contexts thread-owned.
CI works locally but fails on Linux Missing browser or system dependencies. Install browsers with install --with-deps and follow the current CI page for your image.
Generated Codegen test is brittle Recorded selectors capture incidental DOM details. Review locators, add meaningful assertions and simplify the scenario before committing it.

14. Performance, reliability and cost decisions

  • Reuse the browser, isolate contexts. Launching a browser is heavier than creating a context, while a fresh context protects test state.
  • Keep tests focused. A small user-visible flow is easier to retry and diagnose than a long script containing unrelated features.
  • Prefer deterministic data. Prepare state through APIs where appropriate, then validate the UI through Playwright.
  • Control parallelism. More workers can reduce elapsed time but increase CPU, memory, service load and contention. Measure in your CI environment.
  • Preserve artifacts only when useful. Screenshots, videos and traces aid diagnosis but consume storage and can slow pipelines.
  • Pin and update deliberately. A Playwright upgrade can require new browser binaries and may change supported runtime details.
  • Account for external pages. Third-party scripts, consent banners, bot checks and network latency can make navigation nondeterministic. Use controlled test environments for application tests.

15. A practical learning checklist

  • Install a supported Java version and Maven.
  • Create a Maven project with the Playwright dependency.
  • Install matching browser binaries.
  • Run a headless script and then repeat it headed.
  • Navigate, read a title and save a screenshot.
  • Replace brittle selectors with role, text or test-id locators.
  • Use web-first assertions for visible outcomes.
  • Create one BrowserContext per test and close it.
  • Adopt the JUnit or TestNG framework used by your team.
  • Use Codegen to study actions and locator suggestions, then rewrite the result.
  • Capture screenshots or traces when diagnosing failures.
  • Add APIRequestContext for setup and server-side verification.
  • Install browsers and dependencies in CI before running tests.

Frequently asked questions

Do I need JavaScript to learn Playwright?

No. Playwright has an official Java library. You need Java and Maven; JavaScript knowledge is useful for understanding the pages you automate but is not required for the test code.

Should I start with JUnit or a standalone program?

Start with a standalone program so you can see the browser lifecycle. Move to the runner your project already uses once you need discovery, fixtures, reporting or parallel execution.

Is Playwright WebKit the same as Safari?

No. Playwright ships a WebKit build based on upstream WebKit with Playwright patches. Use the documented branded-browser channels when your compatibility goal requires a branded Chrome or Edge build.

When should I learn APIRequestContext?

After you can write and isolate a browser test. Then use API calls to prepare data or verify server state without forcing every setup step through the UI.

What should I do when a browser update breaks CI?

Check the Playwright dependency version, reinstall the matching browser binaries and system dependencies, then compare your CI image with the current official installation and CI guidance.