chromedp: driving Chrome from Go over the DevTools Protocol, without a Node runtime
A faster, simpler way to drive browsers supporting the Chrome DevTools Protocol.
At a glance
- What is it?
- chromedp talks to Chrome through the DevTools Protocol using pure Go, so browser automation stays inside your existing Go build and test pipeline. The trade-off is that you manage the browser process yourself, and the documentation lives in the Go reference rather than the README.
- Who is it for?
- Adopt chromedp if your automation already lives in Go and you want browser control as a library, not a separate runtime: go get github.com/chromedp/chromedp, build the actions you need, and run them under chromedp.Run. Skip it if you need a recorded visual authoring tool, a cross-browser matrix, or a browser that ships with the dependency.
- 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 78 days 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 September 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What chromedp is for, and who ends up using it
chromedp is a Go package that drives browsers implementing the Chrome DevTools Protocol. The README describes it as "a faster, simpler way to drive browsers supporting the Chrome DevTools Protocol in Go without external dependencies." That last clause is the whole pitch. If your service, CLI or test suite is written in Go, you do not need to ship a Node runtime, install Puppeteer, or shell out to a separate driver process. The browser is still a separate process, but the client is a library you import.
The people who reach for it are usually writing Go tests that need a real DOM: checking that a rendered page contains an element, capturing a screenshot, emulating a device, or scripting a flow that only exists in JavaScript. The repository topics list headless, testing and unit-testing alongside chrome-devtools, which reflects that audience. It is not a general-purpose scraping framework and it is not a visual tool. It is a thin, generated binding to a protocol, plus helpers for the parts everyone writes badly by hand: process allocation, context plumbing, and waiting for the page to settle.
How the DevTools Protocol binding actually works
The architecture is visible in the repository layout. chromedp itself is a small set of files at the root: allocate.go with allocate_linux.go and allocate_other.go for starting the browser, browser.go, conn.go for the connection, target.go for targets, and action files such as nav.go, query.go, input.go, eval.go, screenshot.go and poll.go. The protocol itself is not in this repository. It lives in the separate module github.com/chromedp/cdproto, which go.mod pins to a dated pseudo-version.
That split matters. cdproto is generated, and the README points at github.com/chromedp/pdlgen as the tool used to generate it. So the protocol surface is derived from the DevTools Protocol definition rather than hand-written, which is how chromedp keeps up with Chrome's moving API. When you call something like a domain action, you are going through generated code. The chromedp package wraps that generated layer in Actions, which are the composable units you pass to chromedp.Run.
State flows through a context. The README is explicit that by default a chromedp context has no executor, which is why executing an action without Run produces an invalid context error; an executor can be attached manually if needed. When the connection to the browser is lost, chromedp cancels that context. The README names the symptom directly: "context canceled" errors appear when the browser is closed by hand or the process is killed. That is a design decision, not a bug, and it means your error handling has to distinguish a cancelled context from a genuine action failure. The dependency list is small: cdproto, gobwas/ws for the websocket, a JSON package, a PDF library and pixelmatch. No Node, no Python, no driver binary.
Installing chromedp and running a first action
Installation is the standard Go module flow. The README gives the command:
$ go get -u github.com/chromedp/chromedpAfter that, the module is in your go.mod. Note that go.mod declares go 1.26, so a toolchain at least that new is required.
The README does not carry a full runnable example; it defers to the Go reference and to a separate examples repository. What it does document is the pattern for wrapping an action that returns more than one value, which is a common early stumbling block:
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
chromedp.Run(ctx, chromedp.ActionFunc(func(ctx context.Context) error {
_, err := domain.SomeAction().Do(ctx)
return err
}))The context from NewContext carries the browser session, cancel releases it, and Run executes the actions in order. If you write your own action and call it outside Run, expect the invalid context error described in the README.
For a headless environment, the README recommends running your Go program inside the chromedp/headless-shell image, which it describes as containing headless-shell, "a smaller headless build of Chrome, which chromedp is able to find out of the box." That is the intended path for CI containers. If you instead want to keep a browser alive across program runs, the README says to start Chrome manually and connect with RemoteAllocator, because on Linux chromedp force-kills Chrome child processes it started in order to avoid leaking resources.
Headless by default, and the surprises that follow
The first thing most users hit is that no window appears. That is not a misconfiguration. Chrome runs headless by default, and the README points at DefaultExecAllocatorOptions and an example in the Go reference for overriding those options. If you want to watch the automation happen, you change allocator options rather than adding a flag to a command.
The second surprise is process lifetime. On Linux, chromedp force-kills any Chrome child processes it started when your Go program finishes, deliberately, to avoid leaking resources. A long-running Chrome instance is therefore not something you get by accident; the README directs you to start Chrome yourself and connect with RemoteAllocator instead. That is a reasonable default for tests and a poor fit for a persistent browser service, which is worth knowing before you design around it.
The third is error semantics. A dropped connection cancels the context, so the failure you see may be context canceled rather than a description of what actually went wrong. Code that treats every non-nil error as a test failure will report confusing messages when Chrome dies. This is the clearest case where chromedp is the wrong tool: if you need stable, long-lived browser sessions with independent lifecycle control, the allocator's cleanup behaviour is working against you, and you should connect to an externally managed Chrome instead.
chromedp compared with Rod, Playwright and Selenium
The closest Go alternative people ask about is Rod. Both are pure Go and both speak the DevTools Protocol, so the difference is not the transport but the abstraction. chromedp is built around Actions executed against a context, with the protocol surface generated into cdproto and the README pointing you at the Go reference and a separate examples repository for anything beyond the basics. Rod takes a page-and-element object model, where you hold a reference to a page and chain calls on it. Which one reads better depends on whether you think in terms of queued actions or live objects; chromedp's model composes well when the sequence is fixed, and less well when control flow depends on what the page returns mid-sequence.
Against Playwright and Puppeteer, the difference is the runtime. Those are JavaScript and Python projects with their own driver and browser management, and they cover multiple browser engines. chromedp is Go-only and targets the DevTools Protocol, which in practice means Chromium-based browsers. If your team is a Go shop, that constraint is a feature: one toolchain, one dependency graph, no Node in the container. If you need Firefox or WebKit coverage, chromedp is not the tool and no amount of configuration will make it one.
Selenium sits differently again. It is a cross-language, cross-browser standard built on the WebDriver protocol, with a much larger ecosystem and a heavier operational footprint. chromedp trades that breadth for directness: no driver binary to keep in sync with the browser, because the protocol is the interface.
Maintenance, versions and what the MIT licence means here
The last push to the default branch was on 2026-07-14, and the repository is not archived. The most recent release listed is v0.15.1 from 2026-04-01, following v0.13.2 in March 2025 and v0.13.0 earlier that month. The version numbers stay below 1.0, which is worth reading literally: the maintainers have not declared a stable API, and minor version bumps have historically carried breaking changes between the 0.13 and 0.15 lines. Pin your dependency and read the release notes before upgrading rather than tracking the branch.
Upgrade cost is dominated by cdproto, not by chromedp itself. Because the protocol bindings are generated and pinned as a pseudo-version in go.mod, moving to a newer Chrome can mean moving to a newer cdproto, which can change generated method signatures. Budget for that in any long-lived automation suite.
The licence is MIT. That is permissive: it allows use in closed-source products and modification, with the usual requirement to preserve the copyright notice and licence text. This is a factual description of the licence, not legal advice; if your organisation has specific obligations around bundled dependencies, check them against the LICENSE file in the repository, which is the authoritative text.
Editorial conclusion
Adopt chromedp if your automation already lives in Go and you want browser control as a library, not a separate runtime: go get github.com/chromedp/chromedp, build the actions you need, and run them under chromedp.Run. Skip it if you need a recorded visual authoring tool, a cross-browser matrix, or a browser that ships with the dependency. Before committing, verify three things on your own machine: that the Chrome binary on your target host matches what DefaultExecAllocatorOptions expects, that the force-kill behaviour on Linux does not conflict with a long-running Chrome you intend to keep, and that your test harness handles chromedp cancelling the context when the browser connection drops, which surfaces as a context canceled error rather than a clean failure.
Frequently asked questions
What is chromedp?
chromedp is a Go package that drives browsers supporting the Chrome DevTools Protocol, described in its README as a faster, simpler way to do so without external dependencies. It ships as a library you import, with the protocol bindings generated into the separate github.com/chromedp/cdproto module.
How does chromedp compare with Puppeteer?
The README positions chromedp as a Go package with no external dependencies, whereas Puppeteer is a JavaScript tool with its own runtime and browser management. chromedp targets the Chrome DevTools Protocol, so the practical difference is that browser automation stays inside your Go build rather than requiring Node.
How does chromedp compare with go-rod?
Both are Go libraries that speak the Chrome DevTools Protocol, so the transport is the same. chromedp is organized around Actions executed via chromedp.Run against a context, with the protocol surface generated into cdproto and examples kept in a separate repository, while Rod uses a page-and-element object model.
How does chromedp compare with Selenium?
Selenium is a cross-language, cross-browser standard built on WebDriver with a larger ecosystem and a driver binary to manage. chromedp is Go-only and talks directly to the DevTools Protocol, which removes the driver component but limits you to browsers implementing that protocol.
How does chromedp compare with Playwright for Go?
Playwright is a JavaScript and Python project with its own driver and browser management and coverage of multiple browser engines. chromedp is a Go library that talks to the DevTools Protocol directly, so it stays inside a Go toolchain but in practice targets Chromium-based browsers.
Official sources
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.
[](https://hysenlabs.com/projects/chromedp-chromedp)