Skip to content
Package cdp provides type-safe bindings for the Chrome DevTools Protocol (CDP), written in the Go programming language.
Branch: master
Clone or download
mafredri rpcc: Fix stream sync deadlock (#91)
* rpcc: Reproduce Sync/notify deadlock from #90

* rpcc: Fix Sync/notify deadlock

* rpcc: Disallow passing same stream twice in Sync

This prevents another deadlock where if the same Stream is passed
multiple times to Sync, Sync would try to acquire the mutex lock a
second time while the first one was still active.

* rpcc: Handle edge case during close in syncMessageStore

Becase (*Conn).notify now calls stream.write outside the streamMu lock,
it's now possible for a write to happen after the syncMessageStore has
closed, in which case there would be no handler for the write and it
could panic. At least theoretically, might need to test this assumption

* rpcc: Ensure continued delivery when closing synced Streams

Fixes #90.
Latest commit a32ee05 Mar 16, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
devtool devtool: Fix JSON tag in Version.WebSocketDebuggerURL (#84) Feb 5, 2019
example/screencast Update documentation, tests and examples Jul 18, 2017
internal session: Move test utils to cdp/internal/testutil Feb 27, 2018
rpcc rpcc: Fix stream sync deadlock (#91) Mar 16, 2019
.codecov.yml codecov: Decrease spamminess Jul 18, 2017
.editorconfig Add .editorconfig and use spaces in README Mar 28, 2017
LICENSE Rename LICENCE -> LICENSE Mar 22, 2017
cdp_client.go Update to latest protocol definitions Mar 14, 2019
example_advanced_test.go Update all mentions of Debugging to DevTools Protocol Sep 5, 2018
example_incognito_test.go Add incognito example (uses targets, contexts and session) Sep 23, 2018
example_logging_test.go Fix output race in logging example Mar 26, 2017
example_test.go Update all mentions of Debugging to DevTools Protocol Sep 5, 2018


Build Status Coverage Status Go Report Card GoDoc

Package cdp provides type-safe bindings for the Chrome DevTools Protocol (CDP), written in the Go programming language. The bindings are generated (by cdpgen) from the latest tip-of-tree (tot) protocol definitions and are mainly intended for use with Google Chrome or Chromium, however, they can be used with any debug target (Node.js, Edge DevTools Protocol, Safari, etc.) that implement the protocol.

This package can be used for any kind of browser automation, scripting or debugging via the Chrome DevTools Protocol.

A big motivation for cdp is to expose the full functionality of the Chrome DevTools Protocol and provide it in a discoverable and self-documenting manner.

Providing high-level browser automation is a non-goal for this project. That being said, cdp hopes to improve the ergonomics of working with the protocol by providing primitives better suited for Go and automating repetitive tasks.


  • Discoverable API for the Chrome DevTools Protocol (GoDoc, autocomplete friendly)
  • Contexts as a first-class citizen (for timeouts and cancellation)
  • Simple and synchronous event handling (no callbacks)
  • Concurrently safe
  • No silent or hidden errors
  • Do what the user expects
  • Match CDP types to Go types wherever possible
  • Separation of concerns (avoid mixing CDP and RPC)


$ go get -u


See API documentation for package, API descriptions and examples. Examples can also be found in this repository, see the simple, advanced, logging and incognito examples.


The main packages are cdp and rpcc, the former provides the CDP bindings and the latter handles the RPC communication with the debugging target.

To connect to a debug target, a WebSocket debugger URL is needed. For example, if Chrome is running with --remote-debugging-port=9222 the debugger URL can be found at localhost:9222/json. The devtool package can also be used to query the DevTools JSON API (see example below).

Here is an example of using cdp:

package main

import (


func main() {
	err := run(5 * time.Second)
	if err != nil {

func run(timeout time.Duration) error {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	// Use the DevTools HTTP/JSON API to manage targets (e.g. pages, webworkers).
	devt := devtool.New("")
	pt, err := devt.Get(ctx, devtool.Page)
	if err != nil {
		pt, err = devt.Create(ctx)
		if err != nil {
			return err

	// Initiate a new RPC connection to the Chrome DevTools Protocol target.
	conn, err := rpcc.DialContext(ctx, pt.WebSocketDebuggerURL)
	if err != nil {
		return err
	defer conn.Close() // Leaving connections open will leak memory.

	c := cdp.NewClient(conn)

	// Open a DOMContentEventFired client to buffer this event.
	domContent, err := c.Page.DOMContentEventFired(ctx)
	if err != nil {
		return err
	defer domContent.Close()

	// Enable events on the Page domain, it's often preferrable to create
	// event clients before enabling events so that we don't miss any.
	if err = c.Page.Enable(ctx); err != nil {
		return err

	// Create the Navigate arguments with the optional Referrer field set.
	navArgs := page.NewNavigateArgs("").
	nav, err := c.Page.Navigate(ctx, navArgs)
	if err != nil {
		return err

	// Wait until we have a DOMContentEventFired event.
	if _, err = domContent.Recv(); err != nil {
		return err

	fmt.Printf("Page loaded with frame ID: %s\n", nav.FrameID)

	// Fetch the document root node. We can pass nil here
	// since this method only takes optional arguments.
	doc, err := c.DOM.GetDocument(ctx, nil)
	if err != nil {
		return err

	// Get the outer HTML for the page.
	result, err := c.DOM.GetOuterHTML(ctx, &dom.GetOuterHTMLArgs{
		NodeID: &doc.Root.NodeID,
	if err != nil {
		return err

	fmt.Printf("HTML: %s\n", result.OuterHTML)

	// Capture a screenshot of the current page.
	screenshotName := "screenshot.jpg"
	screenshotArgs := page.NewCaptureScreenshotArgs().
	screenshot, err := c.Page.CaptureScreenshot(ctx, screenshotArgs)
	if err != nil {
		return err
	if err = ioutil.WriteFile(screenshotName, screenshot.Data, 0644); err != nil {
		return err

	fmt.Printf("Saved screenshot: %s\n", screenshotName)

	return nil

For more information, consult the documentation.


The Go implementation of gRPC (grpc-go) has been a source of inspiration for some of the design decisions made in the cdp and rpcc packages. Some ideas have also been borrowed from the net/rpc package from the standard library.


You can’t perform that action at this time.