# playwright-go: browser automation for Go teams that already know Playwright

> mxschmitt/playwright-go wraps the Playwright driver behind a Go API for Chromium, Firefox and WebKit. It is the right pick when your automation lives in Go and you want Playwright's locators and tracing, not a Go-native reimplementation.

**mxschmitt/playwright-go** — Playwright for Go a browser automation library to control Chromium, Firefox and WebKit with a single API.

- Repository: https://github.com/mxschmitt/playwright-go
- Website: https://mxschmitt.github.io/playwright-go/
- Stars: 3,513 · Forks: 246
- Language: Go
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/mxschmitt-playwright-go

## What playwright-go solves for Go services

Go has browser automation options, but most of them expose a driver protocol rather than a page model. You get a session, you send commands, and you write your own retry loop around every click. playwright-go takes the opposite route: it is a Go binding over the Playwright driver, so the API you call is the same one Playwright users call in TypeScript, Python or Java. The README describes the library as automating Chromium, Firefox and WebKit with a single API, and the guides and concepts on playwright.dev are shared across all Playwright languages, with only the code samples written in JavaScript.

The intended audience is a Go team that already has a service, a CLI or a test suite and needs a real browser inside it. Scraping a JavaScript-rendered page, rendering a PDF, checking a checkout flow, or capturing a screenshot at a fixed viewport are all things the examples directory covers directly. The project is not a new automation engine, and it does not try to be one. The value is that the semantics you read about on playwright.dev apply to the Go code you write, and the driver underneath is the same one the other language bindings use.

That also defines the boundary. If your team has no Go code and no reason to write any, this library adds a language layer for nothing. If your team has Go code and no browser needs, it adds a browser download for nothing.

## How the Go binding talks to the Playwright driver

The repository layout makes the architecture visible. The root package holds files named after the objects Playwright exposes: browser.go, browser_context.go, page-level files such as frame.go and frame_locator.go, plus event_emitter.go and connection.go for the transport. A large part of the surface is generated: generated-interfaces.go, generated-structs.go and generated-enums.go. That is a strong hint about how the binding is maintained. The Go types are derived from the driver's protocol rather than hand-written per feature, which is why the API tracks upstream Playwright closely.

The dependency list in go.mod is small and tells the same story. The transport uses github.com/coder/websocket, JSON parsing uses github.com/tidwall/gjson, and the remaining entries are ordinary utilities: golang-set, go-stack, filetype, pixelmatch for image comparison, testify for tests, and yaml for configuration. Nothing in that list is a browser engine. The browser is not vendored into the module; it is installed separately and driven over a connection.

That design has a direct consequence for your build. The Go module version and the Playwright driver version are coupled. The README states that each minor version upgrade requires a specific Playwright driver version, and the install instructions tell you to replace 0.xxxx.x with the version used in your current go.mod. So an upgrade is two steps in lockstep: bump the module, then install the matching driver. Treating the driver as a floating dependency will put you out of sync with the generated API.

## Installing playwright-go and running a first scrape

Start by adding the module. The README gives this command:

```bash
go get -u github.com/mxschmitt/playwright-go
```

Then install the driver and browsers. The README notes that you should replace the version number 0.xxxx.x with the version used in your current go.mod, and that adding --with-deps also installs the OS dependencies. The same page warns that installing system dependencies requires privileges, so on a locked-down CI runner you may need to install those packages separately.

```bash
go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.xxxx.x install --with-deps
```

The alternative form installs the CLI once and runs it from your PATH:

```bash
go install github.com/mxschmitt/playwright-go/cmd/playwright@v0.xxxx.x
playwright install --with-deps
```

There is also a programmatic path. The README shows that you can download the driver and browsers from your code with playwright.Install(). Note the caveat that comes with it: if your operating system lacks the browser dependencies, you still install them manually, because installing system dependencies requires privileges.

With the driver in place, the README's Hacker News example is the shortest real program. After playwright.Run(), you launch Chromium, open a page, navigate, and collect elements with a locator:

```go
page, err := browser.NewPage()
if err != nil {
	log.Fatalf("could not create page: %v", err)
}
if _, err = page.Goto("https://news.ycombinator.com"); err != nil {
	log.Fatalf("could not goto: %v", err)
}
entries, err := page.Locator(".athing").All()
if err != nil {
	log.Fatalf("could not get entries: %v", err)
}
```

What you should see is a printed list of the currently top voted items, numbered from 1. The example closes with browser.Close() and pw.Stop(), and keeping that order matters: the driver process outlives the browser, so stopping Playwright is what releases it.

One thing to plan for: the README does not document a rollback path for the driver install, so if an upgrade goes wrong you are re-running the install command with the previous version rather than reverting a package manager transaction.

## Locators, auto-wait and traces are the reason to pick this over a raw driver

The capabilities list is where playwright-go separates itself from a thin DevTools wrapper. Locators are described as finding elements the way a user sees the page, through GetByRole, GetByLabel, GetByPlaceholder, GetByText and GetByTestId, instead of brittle CSS paths. Auto-wait means actions such as Click and Fill wait for the element to be actionable, and assertions created via playwright.NewPlaywrightAssertions() retry until the condition is met, so the README explicitly frames this as removing arbitrary sleeps. Anyone who has maintained a scraping script full of time.Sleep calls knows what that removes.

Isolation is handled by BrowserContext, described as the equivalent of a brand new browser profile at near-zero overhead. Authentication state can be captured once with context.StorageState() and reused. For a scraper that logs in before every run, or a test suite that needs a clean session per case, this is the mechanism that keeps runs independent without paying for a full browser restart each time.

Tracing is the debugging story. You record with context.Tracing() and inspect DOM snapshots, network traffic and console logs afterwards using playwright show-trace. For a Go service that fails on one page out of a thousand, a trace is far more useful than a log line, and it is the feature most likely to justify the driver dependency on its own. Network interception via page.Route() covers the other half: stubbing and mocking requests, or monitoring all traffic of a page.

## Where playwright-go is the wrong tool

The install step is the first real limitation, and it is not a small one. playwright-go does not ship a browser. Every environment that runs it, including every CI job, needs the driver and the browser binaries downloaded, and on Linux potentially the OS dependencies as well. The README is explicit that system dependencies require privileges, which means the --with-deps path may simply not be available to you. If your deployment target is a distroless image, a scratch container, or a build system with no network access at install time, you are working against the design rather than with it. A Go-native driver that speaks the protocol without an external install would fit that constraint better.

The version coupling is the second limitation. Because each minor version upgrade requires a specific Playwright driver version, the module is not something you bump casually in a shared go.mod. A service that pins playwright-go is also pinning a browser build, and the browser build has its own release cadence. Teams that treat browser versions as a security surface will need a process for that, and the README does not describe one.

Finally, consider whether you need Playwright at all. If your target pages are server-rendered and your requests are simple, an HTTP client is faster and has no install step. The README's own example crawls Hacker News, a page that does not require a browser to read. Reaching for playwright-go there buys you nothing but a download.

## How it compares with Selenium and with the other Playwright bindings

The comparison people ask about is Selenium. The difference is architectural rather than cosmetic. Selenium drives a browser through the WebDriver protocol, and each browser supplies its own driver binary; the specification is what keeps the API stable across them. Playwright instead drives browsers through its own protocol and ships the browser builds it supports, which is why the README can list specific versions for Chromium, Firefox and WebKit and state that headless and headed execution works for all three on Linux, macOS and Windows. In practice, auto-waiting and the locator model are Playwright's answer to the explicit waits that Selenium users write by hand.

Compared with the other Playwright bindings, playwright-go is a binding, not a port. The README says the guides, concepts and API semantics are shared across all Playwright languages, and only the code samples on playwright.dev are in JavaScript. So a team moving from the Python or TypeScript binding keeps its mental model and translates syntax, while a team that needs a language the project does not cover has no Go-shaped workaround here. If your automation is already written and maintained in another language, adding playwright-go means maintaining a second binding against the same driver, with the version coupling applied twice.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-14. Recent releases are v0.6201.1 on 2026-08-17, v0.6201.0 on 2026-08-12 and v0.6100.0 on 2026-06-26. The version numbers track the upstream Playwright release they correspond to, which is consistent with the README's warning that a minor upgrade requires a matching driver version. Read that as a maintenance model: your upgrade cadence is set by upstream Playwright, and each step is a module bump plus a driver install.

The licence is MIT, per the repository and the badge in the README. MIT is permissive, so it permits use in closed-source products and places few obligations on how you distribute. That is a statement about the licence text, not legal advice; if your organisation has a policy on third-party dependencies, the licence file in the repository is what your reviewers should read. One practical point that follows from the architecture rather than the licence: the browser binaries you install are separate downloads with their own terms, and the README does not address them. If your legal review covers the whole runtime, the driver and browsers are part of what you are shipping.

## Conclusion

Adopt playwright-go if your scraping, end-to-end tests or PDF rendering already live in a Go codebase and you want Playwright's locator and tracing model rather than a Go-native driver. Do not adopt it if you need a single static binary with no external browser download, or if your project cannot accept a driver version pinned to each minor release of the Go module. Before committing, run the install command with your exact go.mod version and confirm that the driver and browser downloads succeed on your CI image, because that download step, not the Go API, is where most first attempts fail.

## FAQ

### What is playwright-go?

It is a Go library that automates Chromium, Firefox and WebKit through a single API, built as a binding over the Playwright driver. The README states that the guides and API semantics are shared across all Playwright languages, with only the code samples on playwright.dev written in JavaScript.

### What is ms playwright go?

It is the same project: playwright-go is maintained in the mxschmitt/playwright-go repository and published as the Go module github.com/mxschmitt/playwright-go. The README points to pkg.go.dev for the API reference and to playwright.dev for the guides.

### What is playwright-go used for?

It is used to drive a real browser from Go code: scraping pages that need JavaScript, rendering a PDF, taking screenshots, and end-to-end testing. The README's examples directory covers each of those, including parallel scraping, network monitoring and mobile and geolocation emulation.

### Is playwright-go a paid product?

No. The repository is licensed under MIT, and the README links the Playwright documentation and API reference as the sources for guides and semantics. No pricing or account step is described.

### What is the alternative to playwright-go?

Selenium is the usual comparison. Selenium drives browsers through the WebDriver protocol with a driver binary per browser, while playwright-go drives browsers through Playwright's own protocol and ships the browser builds it supports. The other Playwright language bindings share the same semantics, so moving between them is mostly a syntax change.

### Is Playwright going to replace Selenium?

The README does not make that claim. It describes playwright-go as a Go library that automates Chromium, Firefox and WebKit with a single API and lists specific browser versions it supports, which is a statement about the browsers it drives rather than about Selenium's future.

## Sources

- [License: MIT](https://github.com/mxschmitt/playwright-go/blob/main/LICENSE)
- [mxschmitt/playwright-go on GitHub](https://github.com/mxschmitt/playwright-go)
- [Project website](https://mxschmitt.github.io/playwright-go/)
- [README](https://github.com/mxschmitt/playwright-go/blob/main/README.md)
- [Releases](https://github.com/mxschmitt/playwright-go/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mxschmitt-playwright-go
