Open-source project
chromedp/chromedp avatar
chromedp/chromedp

chromedp: driving Chrome from Go over a pipe, with iterator events and a v0.20 API break

A faster, simpler way to drive browsers supporting the Chrome DevTools Protocol.

13,367 stars892 forksGoMIT

At a glance

What is it?
chromedp is an MIT Go package that controls browsers speaking the Chrome DevTools Protocol with no external driver, using only the standard library and cdproto. Since v0.20 it has a generic, iterator-based API that is cleaner to use but breaks older code, and its JSON layer changes depending on your Go version.
Who is it for?
chromedp fits Go developers who want to script Chrome or Chromium from a single binary, with no separate driver process and almost no dependencies, for scraping, form filling, screenshots, request interception or HAR capture. It fits poorly if you are stuck below Go 1.25, if you need browsers that do not speak the DevTools Protocol, or if you have a large codebase on the pre-v0.20 API and no time to migrate.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • chromedp/chromedp13,367 ★ · +83
Star history
Repository2026-09-222026-11-14
chromedp/chromedp13.3k13.4k

83 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

A pipe to the browser by default, a websocket only through the remote package

chromedp needs no external driver. The module depends on the Go standard library and cdproto, nothing else, and by default it starts a browser itself and talks to it through a pipe rather than over the network. Installation is a single command:

sh
go get -u github.com/chromedp/chromedp

Websocket code lives in a separate package, github.com/chromedp/chromedp/remote, which carries its own WebSocket client. It is part of the same module, so the go get above installs it too, but you only import it in three situations: when you connect to a browser that is already running, when you want the exec allocator to use a websocket instead of a pipe, or when the browser must stay open after your program exits. The consequence for deployment is that the common pattern of attaching to a long-lived browser in another container is not the default path; you have to opt into remote explicitly.

The JSON types change with your Go toolchain

The module requires Go 1.25 or newer, and go.mod declares go 1.25. The JSON types come from github.com/chromedp/cdproto/cdp/jsonv2, and what they alias depends on how you build. On Go 1.27 and later they are aliases of the standard library package encoding/json/v2. On Go 1.25 and 1.26 they alias encoding/json/v2 only when you set GOEXPERIMENT=jsonv2. In every other case they alias github.com/go-json-experiment/json, which go.mod pulls in as an indirect dependency.

This matters when your own code touches those types. A helper that names a type from encoding/json/v2 compiles on Go 1.27 but not on Go 1.25 without the experiment flag. Teams that build with different Go versions across machines or CI images can see code that compiles in one place and fails in another, so pin the toolchain and the GOEXPERIMENT setting along with the module version.

Actions return values: Do for side effects, Run for results

In the current API an action is a func that runs against a browser tab and returns a value. Two entry points split the work. chromedp.Do runs actions that return nothing, such as navigation. chromedp.Run runs one action and hands back its value, such as the page title:

go
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()

if err := chromedp.Do(ctx, chromedp.Navigate(`https://pkg.go.dev/`)); err != nil {
	log.Fatal(err)
}
title, err := chromedp.Run(ctx, chromedp.Title())
if err != nil {
	log.Fatal(err)
}
fmt.Println(title)

Every call takes the context returned by chromedp.NewContext, and the deferred cancel releases it when the function returns. Because Run hands back a typed value with an error, the title above is an ordinary Go string at the call site, and error handling follows the usual if err != nil pattern instead of a framework-specific callback.

Page events are iterators that subscribe the moment they are created

Events use Go range-over-func iterators. chromedp.Events subscribes as soon as it returns, which is what lets a program set up the subscription, trigger the event, and only then read it:

go
loaded := chromedp.Events(ctx, page.LoadEventFired)
if err := chromedp.Do(ctx, chromedp.Navigate(`https://pkg.go.dev/`)); err != nil {
	log.Fatal(err)
}
for ev, err := range loaded {
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(ev.Timestamp)
	break
}

The ordering is the point. If you navigate first and call Events afterwards, the load event can fire before the subscription exists. Each iteration yields an event and an error, so failures arrive inside the loop rather than through a separate channel. The eventsiter example in the examples repository builds on this to wait until the network is idle, and the console example uses events to read console output and uncaught exceptions.

v0.20 replaced the API, and older cdproto versions keep the old one

Version v0.20.0 moved chromedp to the typed cdproto v0.157.8 and introduced the generic and iterator API shown above. The earlier cdproto versions v0.157.0, v0.157.1 and v0.157.2 still have the old API. Code written before v0.20 will not compile unchanged against the new release. Two files exist for the migration: docs/API.md explains the API with 27 examples that put old code and new code side by side, and docs/MIGRATION.md has every renamed and removed name.

The pace since then has been quick. v0.20.1 was tagged on 2026-10-05, v0.21.0 on 2026-10-11 and v0.21.1 on 2026-11-01, the same day as the last push to main, and go.mod now requires cdproto v0.159.0. The project is still below 1.0. Note that the suggested install command uses go get -u, which pulls the newest version; on an existing project, choose the version deliberately instead of letting -u decide.

Protocol commands without an action need a raw call

Typed actions cover the everyday work, but not every DevTools Protocol command has one. The rawcall example in the examples repository shows how to send protocol commands that have no action, naming timezone, locale, geolocation and throttling as cases. If your job depends on emulating a location or a slow network, expect to work closer to the protocol than the click and text helpers suggest.

The flip side is that the protocol is fully reachable. The intercept example blocks, mocks and changes requests through the Fetch domain. The har example writes a HAR file from a page's network events. exposefunc lets the page call Go functions, dialogs answers alert, confirm, prompt and beforeunload, and popups handles several targets and browser contexts. chromedp only drives browsers that support the Chrome DevTools Protocol, so everything here assumes such a browser on the host or reachable through the remote package.

Forty-four example programs, each one main.go with the same flags

The separate chromedp/examples repository holds 44 programs for larger tasks, each a single main.go that runs directly with go run:

sh
go run github.com/chromedp/examples/tabs@latest

The flags are shared. Every program accepts -v to print the protocol messages, which is the quickest way to see what a high-level action actually sends. Every program except remote accepts -visible to show the browser window. Most accept -visible-on-terminal to draw the page in the terminal through termcast, and termcast itself takes -fps instead. Some take -url to point at another site. All programs except fast and distrust read local content and work without internet access. The catalog spans clicking and reading text, typed selectors, iframes and shadow roots, file upload, drag and drop with both mouse and HTML5 events, cookies, extra headers, proxy sign-in, saving and restoring login sessions, and downloading files from a headless browser.

Platform-specific allocators decide how the browser process starts and stops

How chromedp launches a browser differs per operating system, and the source layout shows it: allocate_darwin.go, allocate_linux.go, allocate_other.go, allocate_pipe.go, and separate allocate_detach_unix.go and allocate_detach_windows.go for detaching the browser process. keepopen.go, with a Linux-specific test, covers the case where the browser should outlive the program, which ties back to the remote package requirement. Device emulation lives in the device/ directory and keyboard definitions in kb/, alongside files for PDF output, emulation, frames, drag, input and evaluation.

For users this means behavior around process lifetime is platform code, not a single generic path. If your program has to leave a browser running or detach it cleanly on Windows, test that on the target OS rather than assuming Linux behavior carries over. The extension example adds another environment detail: it loads uBlock Origin Lite from a folder on disk, so extension loading is tied to a local unpacked directory.

Editorial conclusion

chromedp fits Go developers who want to script Chrome or Chromium from a single binary, with no separate driver process and almost no dependencies, for scraping, form filling, screenshots, request interception or HAR capture. It fits poorly if you are stuck below Go 1.25, if you need browsers that do not speak the DevTools Protocol, or if you have a large codebase on the pre-v0.20 API and no time to migrate. Before upgrading or starting, read docs/MIGRATION.md and confirm which cdproto version your go.mod resolves to.

Frequently asked questions

What is chromedp?

chromedp is an MIT-licensed Go package that drives browsers speaking the Chrome DevTools Protocol. It needs no external driver, depends only on the Go standard library and cdproto, and talks to the browser it starts through a pipe.

Which Go version does chromedp require?

chromedp needs Go 1.25 or newer. On Go 1.27 and later its JSON types alias encoding/json/v2; on 1.25 and 1.26 they do so only with GOEXPERIMENT=jsonv2.

Can chromedp connect to a browser that is already running?

Yes, through the github.com/chromedp/chromedp/remote package, which has its own WebSocket client. You also need it to keep the browser open after the program ends.

How do I migrate chromedp code written before v0.20?

v0.20.0 introduced a generic and iterator API on cdproto v0.157.8. docs/API.md has 27 old-versus-new examples, and docs/MIGRATION.md covers every renamed and removed name.

Official sources

  1. chromedp/chromedp on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/chromedp-chromedp.svg)](https://hysenlabs.com/projects/chromedp-chromedp)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/chromedp-chromedp.svg)](https://hysenlabs.com/projects/chromedp-chromedp)

Was this useful?