Help us shape the future of Go! Take the 2026 Go Developer Survey

chromedp

package module
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: MIT Imports: 40 Imported by: 2,460

README

About chromedp

chromedp logo

Package chromedp drives browsers that speak the Chrome DevTools Protocol from Go. It needs no external driver.

Unit Tests Go Reference Releases Discord Discussion

Installing

Install the package with go get. The module needs Go 1.25 or newer. The JSON types come from github.com/chromedp/cdproto/cdp/jsonv2. They are aliases of the types of the standard library package encoding/json/v2 on Go 1.27 and later, or on Go 1.25 and 1.26 with GOEXPERIMENT=jsonv2. Otherwise they are aliases of the types of github.com/go-json-experiment/json. Version v0.20.0 uses the typed cdproto v0.157.8 and has the generic and iterator API. The earlier versions of cdproto, v0.157.0, v0.157.1 and v0.157.2, have the old API.

go get -u github.com/chromedp/chromedp

The module uses only the Go standard library and cdproto. It starts a browser and talks to it through a pipe. Code that needs a websocket is in the package github.com/chromedp/chromedp/remote, which has its own WebSocket client. It is part of the same module, so go get installs it with the rest. Import it only when you connect to a browser that runs already, when you want the exec allocator to use a websocket, or when you keep the browser open after the program ends.

Usage

An action is a func that runs against a browser tab and returns a value. chromedp.Do runs actions that return nothing, and chromedp.Run runs one action and returns its value:

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)

A page event is an iterator. chromedp.Events subscribes when it returns, so a program can subscribe, trigger the event, and then read it:

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
}

docs/API.md describes the API. It has 27 examples that show the old code and the new code side by side. docs/MIGRATION.md lists every renamed and removed name.

See the Go reference for the documentation and examples.

More examples

The examples repository has 43 programs for larger tasks. Each program is one main.go file. Run one with go run, for example go run github.com/chromedp/examples/tabs@latest. Every program takes the flag -v to print the protocol messages. Every program except remote takes the flag -visible to show the browser window. Most programs take the flag -visible-on-terminal to draw the page in the terminal while they run, with termcast. Every program except fast reads local content and needs no internet. Some programs take the flag -url to read another site. The program termcast takes the flag -fps instead of -visible-on-terminal.

Read pages and fill forms:

  • click clicks an element that a selector finds.
  • text reads the text of an element.
  • eval runs JavaScript in the page and decodes the result.
  • structeval decodes JavaScript results into Go structs, slices and maps, and shows the errors.
  • logic mixes actions and Go code to read a list.
  • subtree walks a subtree of the DOM.
  • selectors shows the typed selectors side by side.
  • frames reaches elements inside an iframe and a shadow root.
  • submit fills out and submits a form.
  • keys sends key events to an element.
  • upload uploads a file on a form.
  • visible waits until an element is visible.
  • dragdrop drags and drops with the mouse and with HTML5 drag and drop.

Network, sessions and files:

  • cookie sets cookies on requests.
  • headers adds extra HTTP headers.
  • proxy signs in to a proxy server that needs a password.
  • intercept blocks, mocks and changes requests with the Fetch domain.
  • session saves a login session and restores it in another browser.
  • har writes a HAR file from the network events of a page.
  • download_file downloads a file with a headless browser.
  • download_image downloads an image from the network response.

Events and the protocol:

  • eventsiter reads the events of a page with iterators, and waits for the network to be idle.
  • console reads the console and the uncaught exceptions of a page.
  • dialogs answers alert, confirm, prompt and beforeunload dialogs.
  • popups works with popups and several targets, and with browser contexts.
  • exposefunc calls Go functions from the page.
  • extension loads a browser extension, uBlock Origin Lite, from a folder on disk and shows that it blocks the ads of a page.
  • latlon drives a map and reads the latitude and the longitude from the URL of the page.
  • rawcall sends protocol commands that have no action, such as timezone, locale, geolocation and throttling.

Screens and devices:

  • screenshot takes a screenshot of an element and of the whole page.
  • pdf prints a page to a PDF file.
  • pdfoptions prints a page to PDF files with different options.
  • pdfstream reads a printed PDF as a stream.
  • emulate emulates a device, such as an iPhone.
  • screencast saves the frames of a page as JPEG files.
  • termcast plays an animated SVG and streams the screen of the browser to the terminal with termcast.

Several tabs and browsers:

  • tabs uses several tabs of one browser, with or without a window for each tab, and switches between them.
  • workers runs many jobs at the same time in one browser with a pool of goroutines.
  • multi uses the headless-shell image in a container.
  • remote connects to a browser that is already running, with the package remote.

The program fast reads a live site, fast.com, and draws an image in the terminal. It can fail when the site changes. The programs forecast and geoip also draw an image in the terminal. Run these programs in a terminal that can show images. The tags of the examples repository follow the tags of chromedp.

Show the browser in the terminal

termcast streams the screen of a chromedp page to a terminal that can show images (Kitty, iTerm2 or Sixel). It uses the screencast of the Chrome DevTools Protocol, so it works with a headless browser, also over ssh. Start the browser first, and then start the stream with the context.

ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
chromedp.Do(ctx, chromedp.Navigate("https://example.com")) // starts the browser
s, err := termcast.Start(ctx)                               // draws 4 frames each second
if err != nil {
	log.Fatal(err) // termcast.ErrNoGraphics when the terminal has no graphics
}
defer s.Stop()

To draw one element and not the whole page, add termcast.WithElement(chromedp.CSS("#chart")) to the call of termcast.Start. The module termcast needs Go 1.25 or newer. The stream clears the terminal at each redraw. It holds the log lines while it runs, and prints them after the final frame. The type termcast.Flags adds the flags -visible-on-terminal and -terminal-fps to a program, as the programs in the examples repository have them.

Visible browser

By default, chromedp runs Chrome in headless mode, so no window opens. To see the browser, add WithVisibleWindow. Set the variable CHROMEDP_VISIBLEWINDOW=1 to get the same result with no change in the code. On Linux, a visible window needs DISPLAY or WAYLAND_DISPLAY. Without them, the first Run returns chromedp.ErrNoDisplay.

ctx, cancel := chromedp.NewContext(context.Background(), chromedp.WithVisibleWindow())
defer cancel()
chromedp.Do(ctx, chromedp.Navigate("https://example.com"))
chromedp.WaitClosed(ctx) // block until the user closes the window

To leave the browser open after the program ends, add remote.WithKeepOpen from the package github.com/chromedp/chromedp/remote. The program can print the address, and another program can attach to it with remote.NewAllocator. The profile directory stays on disk, and you must delete it yourself.

ctx, _ := chromedp.NewContext(context.Background(), chromedp.WithVisibleWindow(), remote.WithKeepOpen())
chromedp.Do(ctx, chromedp.Navigate("https://example.com"))
wsURL, profile := chromedp.KeptOpen(ctx)
fmt.Println("attach to", wsURL, "profile", profile)
// The program ends here. The browser stays open.

Remote browser

To connect to a browser that runs already, such as a container or a hosted service, use remote.NewAllocator with the websocket address of the browser:

allocCtx, cancel := remote.NewAllocator(context.Background(), "ws://127.0.0.1:9222/")
defer cancel()
ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel()
title, err := chromedp.Run(ctx, chromedp.Title())

A hosted service can need a header on the websocket request. Give the full address of the browser and the options remote.NoModifyURL and remote.WithDialHTTPHeader.

Frequently Asked Questions

I cannot see any Chrome browser window

By default, chromedp runs Chrome in headless mode. See Visible browser. See also DefaultExecAllocatorOptions, and see an example that overrides the default options.

I see "context canceled" errors

When the connection to the browser is lost, chromedp cancels the context. This can cause the error. It happens, for example, when someone closes the browser by hand, or when something kills the browser process. When the browser process dies on its own, the error also holds the exit error of the process. Use errors.As with an *exec.ExitError to read the signal or the exit status.

How does chromedp talk to the browser it starts?

By default, through a pipe. chromedp starts Chrome with --remote-debugging-pipe and two pipes, so Chrome opens no debugging port. On Windows the pipes are handles that the switch --remote-debugging-io-pipes names. To use a websocket and a debugging port instead, add the remote.WebSocket option of the package github.com/chromedp/chromedp/remote to the exec allocator. A remote-debugging-port or remote-debugging-address flag also selects the websocket, and so does KeepOpen, and they all need remote.WebSocket. A program for Windows needs no remote package for the default pipe.

Chrome exits as soon as my Go program finishes

On Linux, chromedp kills the Chrome child processes that it started, so that no resources leak. To leave Chrome open, add remote.WithKeepOpen. See Visible browser. You can also start Chrome yourself and connect with remote.NewAllocator.

Calling an action or a command results in "invalid context"

chromedp.Do, chromedp.Run and chromedp.Call need a context that came from chromedp.NewContext, because the context holds the browser and the tab. Any other context gives ErrInvalidContext.

How do I send a protocol command that has no action?

Call it with chromedp.Call, which runs the command on the tab of the context:

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

res, err := chromedp.Call(ctx, page.GetFrameTree, cdp.Empty{})

Inside an action, call cdp.Call(ctx, t, command, params) with the target t that the action receives. The target is the tab of the context. The commands and their parameter structs are in github.com/chromedp/cdproto.

I have an action of the old kind

Wrap it with chromedp.Legacy. The old kind is a value with a Do(context.Context) error method.

Is it safe to use one context from several goroutines?

Contexts that share one browser run in separate tabs, and they are safe to use in parallel. Call chromedp.Run once on a parent context so that it has a browser, and then make a child context for each goroutine with chromedp.NewContext. A child of a context that has no browser yet starts a browser of its own.

Do not share one context between goroutines. The actions of one context run in one tab, so they can race. For example, two Navigate actions on the same tab can fail. The first Run on a context starts the browser, and it must not run at the same time as another Run on that context.

ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
if err := chromedp.Do(ctx); err != nil { // starts the browser
	log.Fatal(err)
}
var wg sync.WaitGroup
for _, url := range urls {
	wg.Go(func() {
		tabCtx, cancel := chromedp.NewContext(ctx) // a new tab
		defer cancel()
		if err := chromedp.Do(tabCtx, chromedp.Navigate(url)); err != nil {
			log.Println(url, err)
		}
	})
}
wg.Wait()

I cannot reach an element or the network events of an iframe

Chrome runs an iframe from another site (a cross-site iframe) in its own process, as a separate target of the type iframe. The DOM tree of the page does not hold its content. The node of the iframe element has no ContentDocument, so a query with FromNode finds nothing and waits until the context ends. chromedp does not attach to the iframe target by itself, so the network events of the iframe do not reach the context of the page. An iframe from the same site is not affected.

To work in the iframe, find its target with chromedp.Targets and attach to it with chromedp.WithTargetID. The new context runs actions in the iframe and gets its events. The parent context must have run once, so that it has a browser.

infos, err := chromedp.Targets(ctx)
if err != nil {
	log.Fatal(err)
}
for _, info := range infos {
	if info.Type == "iframe" && strings.HasPrefix(info.URL, "https://other.example/") {
		frameCtx, cancel := chromedp.NewContext(ctx, chromedp.WithTargetID(info.TargetID))
		defer cancel()
		text, err := chromedp.Run(frameCtx, chromedp.Text(chromedp.CSS("#inner")))
		// ...
	}
}

The other way is to turn off site isolation, so that the iframe stays in the process of the page. Add Flag("disable-features", "SitePerProcess,IsolateOrigins") and Flag("disable-site-isolation-trials", true) to the options of the exec allocator. Then FromNode and the events of the page reach the iframe. This turns off a security feature of Chrome. Use it only for pages that you trust. See docs/decisions/2026-10-04-keep-site-isolation-on.md.

SendKeys with a new line inserts two line breaks

SendKeys sends the character \n as the Enter key, in the form \r. That is a keyDown event, a char event with the text \r, and a keyUp event. The key kb.Enter is the same as \r, so it sends the same events and does not help. An editor that handles Enter on keydown and cancels the default, such as Lexical, can insert two line breaks, because the char event inserts one more. To send the Enter key with no char event, send a rawKeyDown event and a keyUp event with input.DispatchKeyEvent, and send the text before and after it with SendKeys:

enter := chromedp.Func(func(ctx context.Context, t *chromedp.Target) error {
	for _, typ := range []input.DispatchKeyEventType{
		input.DispatchKeyEventTypeRawKeyDown, input.DispatchKeyEventTypeKeyUp,
	} {
		_, err := cdp.Call(ctx, t, input.DispatchKeyEvent, input.DispatchKeyEventParams{
			Type: typ, Key: "Enter", Code: "Enter",
			WindowsVirtualKeyCode: 13, NativeVirtualKeyCode: 13,
		})
		if err != nil {
			return err
		}
	}
	return nil
})
err := chromedp.Do(ctx,
	chromedp.SendKeys(sel, "Hello"),
	enter,
	chromedp.SendKeys(sel, "World"),
)

The browser closes when the timeout of my context ends

The first Run on a context starts the browser, and it binds the life of the browser to the context that you pass to that call. When that context ends, the browser stops. So a context from context.WithTimeout that you use for the first Run closes the browser when the timeout ends, and every later call on the parent context fails with context canceled.

To limit one action, start the browser first with a context that has no timeout. Then run the action with a context that you derive from it. When the timeout ends, Run returns an error that wraps context.DeadlineExceeded. The tab and the browser stay open, and ctx still works. Run has no option for the timeout of one action.

ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
if err := chromedp.Do(ctx); err != nil { // starts the browser, with no timeout
	log.Fatal(err)
}

tctx, tcancel := context.WithTimeout(ctx, 5*time.Second)
defer tcancel()
err := chromedp.Do(tctx, chromedp.Navigate(url)) // only this call has the timeout

Why does chromedp pass disable-dev-shm-usage, and can I turn it off?

DefaultExecAllocatorOptions sets disable-dev-shm-usage to true. Chrome then keeps the files of its shared memory in the temporary directory, such as /tmp, and not in /dev/shm. The flag is on because /dev/shm is small in many containers (64 MB in a default Docker container), and Chrome crashes when it fills the space.

The cost is that the shared memory files are file-backed memory in the temporary directory. They can be slower, and a program that runs for a long time and opens many pages can see growing memory. If /dev/shm is large enough, for example a memory volume that you mount in a container, turn the flag off after the default options:

opts := append(chromedp.DefaultExecAllocatorOptions[:],
	chromedp.Flag("disable-dev-shm-usage", false),
)
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()

I want to use chromedp on a headless environment

Run the Go program that uses chromedp inside the chromedp/headless-shell image. The image has headless-shell, a smaller headless build of Chrome. chromedp finds it by default.

Contributing

Read CONTRIBUTING.md before you send a change. AGENTS.md holds the rules for people and coding agents. The tests need Chrome or the headless-shell image. The repository holds two modules, and AGENTS.md tells how to test each one.

These documents are in docs/:

Document Holds
docs/PLAN.md the purpose, the architecture and the open questions
docs/PROGRESS.md where the work stands
docs/BACKLOG.md known work that is not done
docs/API.md the new API, with old and new code side by side
docs/MIGRATION.md every renamed and removed name
docs/decisions/README.md the index of every recorded decision

Questions and ideas

Ask a question, or suggest a feature, in Discussions. The issue tracker is for bugs. You can also chat on Discord.

Resources

Documentation

Overview

Package chromedp is a high level Chrome DevTools Protocol client. It drives browsers to scrape web pages, to test them, and to profile them.

chromedp needs no external driver. It implements the asynchronous protocol in Go.

This package includes a number of simple examples. The module chromedp/examples has more complex examples. The module chromedp/termcast draws the screen of a page in a terminal that shows images.

Example (DocumentDump)
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`<!doctype html>
<html>
<body>
  <div id="content" style="display:block;">the content</div>
</body>
</html>`))
	defer ts.Close()

	const expr = `(function(d, id, v) {
		var b = d.querySelector('body');
		var el = d.createElement('div');
		el.id = id;
		el.innerText = v;
		b.insertBefore(el, b.childNodes[0]);
	})(document, %q, %q);`

	s := fmt.Sprintf(expr, "thing", "a new thing!")

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	nodes, err := chromedp.Run(ctx, chromedp.Nodes(chromedp.JSPath(`document`),
		chromedp.Populate(-1, true)))
	if err != nil {
		log.Fatal(err)
	}
	if err := chromedp.Do(ctx,
		chromedp.WaitVisible(`#content`),
		chromedp.Evaluate[chromedp.Void](s),
		chromedp.WaitVisible(`#thing`),
	); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Document tree:")
	fmt.Print(nodes[0].Dump("  ", "  ", false))

}
Output:
Document tree:
  #document <Document>
    html <DocumentType>
    html
      head
      body
        div#thing
          #text "a new thing!"
        div#content [style="display:block;"]
          #text "the content"
Example (Dump)
package main

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`<!doctype html>
<html>
<body>
  <div id="content" style="display:block;">the content</div>
</body>
</html>`))
	defer ts.Close()

	const expr = `(function(d, id, v) {
		var b = d.querySelector('body');
		var el = d.createElement('div');
		el.id = id;
		el.innerText = v;
		b.insertBefore(el, b.childNodes[0]);
	})(document, %q, %q);`

	s := fmt.Sprintf(expr, "thing", "a new thing!")

	var buf bytes.Buffer
	if err := chromedp.Do(ctx,
		chromedp.Navigate(ts.URL),
		chromedp.WaitVisible(`#content`),
		chromedp.Evaluate[chromedp.Void](s),
		chromedp.WaitVisible(`#thing`),
		chromedp.Dump(chromedp.JSPath(`document`), &buf),
	); err != nil {
		log.Fatal(err)
	}

	fmt.Println("Document tree:")
	fmt.Print(buf.String())

}
Output:
Document tree:
#document <Document>
  html <DocumentType>
  html
    head
    body
      div#thing
        #text "a new thing!"
      div#content [style="display:block;"]
        #text "the content"
Example (RetrieveHTML)
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`
<body>
<p id="content" onclick="changeText()">Original content.</p>
<script>
function changeText() {
	document.getElementById("content").textContent = "New content!"
}
</script>
</body>
	`))
	defer ts.Close()

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	outerBefore, err := chromedp.Run(ctx, chromedp.OuterHTML(chromedp.CSS("#content")))
	if err != nil {
		log.Fatal(err)
	}
	if err := chromedp.Do(ctx, chromedp.Click(chromedp.CSS("#content"))); err != nil {
		log.Fatal(err)
	}
	outerAfter, err := chromedp.Run(ctx, chromedp.OuterHTML(chromedp.CSS("#content")))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("OuterHTML before clicking:")
	fmt.Println(outerBefore)
	fmt.Println("OuterHTML after clicking:")
	fmt.Println(outerAfter)

}
Output:
OuterHTML before clicking:
<p id="content" onclick="changeText()">Original content.</p>
OuterHTML after clicking:
<p id="content" onclick="changeText()">New content!</p>

Index

Examples

Constants

Mouse event types for MouseEvent.

View Source
const (
	ModifierNone    = kb.ModifierNone
	ModifierAlt     = kb.ModifierAlt
	ModifierCtrl    = kb.ModifierCtrl
	ModifierMeta    = kb.ModifierMeta
	ModifierShift   = kb.ModifierShift
	ModifierCommand = kb.ModifierCommand
)

Modifier values.

View Source
const (
	NodeTypeElement               = 1
	NodeTypeAttribute             = 2
	NodeTypeText                  = 3
	NodeTypeCDATA                 = 4
	NodeTypeEntityReference       = 5
	NodeTypeEntity                = 6
	NodeTypeProcessingInstruction = 7
	NodeTypeComment               = 8
	NodeTypeDocument              = 9
	NodeTypeDocumentType          = 10
	NodeTypeDocumentFragment      = 11
	NodeTypeNotation              = 12
)

NodeType values.

View Source
const EmptyFrameID = cdp.FrameID("")

EmptyFrameID is the "non-existent" frame id.

View Source
const EmptyNodeID = cdp.NodeID(0)

EmptyNodeID is the "non-existent" node id.

Variables

View Source
var (
	// DefaultUnmarshalOptions are default unmarshal options.
	DefaultUnmarshalOptions = jsonv2.JoinOptions(
		jsonv2.DefaultOptionsV2(),
		jsonv2.AllowInvalidUTF8(true),
	)
	// DefaultMarshalOptions are default marshal options.
	DefaultMarshalOptions = jsonv2.JoinOptions(
		jsonv2.DefaultOptionsV2(),
		jsonv2.AllowInvalidUTF8(true),
	)
)
View Source
var (
	PaperLetter  = PaperSize{8.5, 11}
	PaperLegal   = PaperSize{8.5, 14}
	PaperTabloid = PaperSize{11, 17}
	PaperA3      = PaperSize{11.69, 16.54}
	PaperA4      = PaperSize{8.27, 11.69}
	PaperA5      = PaperSize{5.83, 8.27}
)

Common paper sizes, in inches.

View Source
var DefaultExecAllocatorOptions = [...]ExecAllocatorOption{
	NoFirstRun,
	NoDefaultBrowserCheck,
	Headless,

	Flag("disable-background-networking", true),
	Flag("enable-features", "NetworkService,NetworkServiceInProcess"),
	Flag("disable-background-timer-throttling", true),
	Flag("disable-backgrounding-occluded-windows", true),
	Flag("disable-breakpad", true),
	Flag("disable-client-side-phishing-detection", true),
	Flag("disable-default-apps", true),
	Flag("disable-dev-shm-usage", true),
	Flag("disable-extensions", true),
	Flag("disable-features", "Translate,BlinkGenPropertyTrees"),
	Flag("disable-hang-monitor", true),
	Flag("disable-ipc-flooding-protection", true),
	Flag("disable-popup-blocking", true),
	Flag("disable-prompt-on-repost", true),
	Flag("disable-renderer-backgrounding", true),
	Flag("disable-sync", true),
	Flag("force-color-profile", "srgb"),
	Flag("metrics-recording-only", true),
	Flag("safebrowsing-disable-auto-update", true),
	Flag("enable-automation", true),
	Flag("password-store", "basic"),
	Flag("use-mock-keychain", true),
}

DefaultExecAllocatorOptions are the ExecAllocator options that NewContext uses when the parent context has no allocator. Do not modify this global. Use NewExecAllocator instead. See ExampleExecAllocator.

The list runs the browser in headless mode. To get a visible window, add VisibleWindow to a copy of the list, or give WithVisibleWindow to NewContext.

The list sets disable-dev-shm-usage to true. Chrome then keeps the files of its shared memory in the temporary directory, such as /tmp, and not in /dev/shm. The flag is on because /dev/shm is small in many containers, for example 64 MB in a default Docker container, and Chrome crashes when it fills the space. The cost is that these files are file-backed memory in the temporary directory, which can be slower, and which a program that runs for a long time and opens many pages can see as growing memory. If /dev/shm is large enough, turn the flag off with Flag("disable-dev-shm-usage", false) after the default options:

opts := append(chromedp.DefaultExecAllocatorOptions[:],
	chromedp.Flag("disable-dev-shm-usage", false),
)

Functions

func BrowserEvents added in v0.17.0

func BrowserEvents[E any](ctx context.Context, ev cdp.Event[E]) iter.Seq2[E, error]

BrowserEvents is like Events for the events of the browser, such as the events of the target domain. It replaces ListenBrowser.

func ButtonLeft

func ButtonLeft(p *input.DispatchMouseEventParams)

ButtonLeft is a mouse action option to set the button clicked as the left mouse button.

func ButtonMiddle

func ButtonMiddle(p *input.DispatchMouseEventParams)

ButtonMiddle is a mouse action option to set the button clicked as the middle mouse button.

func ButtonNone

func ButtonNone(p *input.DispatchMouseEventParams)

ButtonNone is a mouse action option to set the button clicked as none (used for mouse movements).

func ButtonRight

func ButtonRight(p *input.DispatchMouseEventParams)

ButtonRight is a mouse action option to set the button clicked as the right mouse button.

func Call added in v0.17.0

func Call[P, R any](ctx context.Context, cmd cdp.Command[P, R], params P) (R, error)

Call runs the protocol command with the params on the target of the chromedp context, and returns its result. As Run does, it starts the browser and opens the target when the context has none yet.

Use it where only the context is at hand, for example in code that runs under Legacy. An Action receives its target, and calls cdp.Call with it:

res, err := chromedp.Call(ctx, page.Navigate, page.NavigateParams{URL: urlstr})

It returns ErrInvalidContext when ctx is not a chromedp context.

Example
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`<title>called</title>`))
	defer ts.Close()

	// Any protocol command runs on the target of an action. The target is
	// a cdp.Session, so cdp.Call takes it as is.
	frameTree := func(ctx context.Context, t *chromedp.Target) (*page.FrameTree, error) {
		res, err := cdp.Call(ctx, t, page.GetFrameTree, cdp.Empty{})
		return res.FrameTree, err
	}

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	tree, err := chromedp.Run(ctx, frameTree)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(strings.TrimPrefix(tree.Frame.URL, ts.URL) == "/")

	// Outside an action, use chromedp.Call with the context.
	res, err := chromedp.Call(ctx, page.GetFrameTree, cdp.Empty{})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(res.FrameTree.Frame.ID == tree.Frame.ID)

}
Output:
true
true

func CallBrowser added in v0.17.0

func CallBrowser[P, R any](ctx context.Context, cmd cdp.Command[P, R], params P) (R, error)

CallBrowser runs the protocol command with the params on the browser of the chromedp context, and returns its result. Use it for the commands of the browser and target domains. As Run does, it starts the browser when the context has none yet.

It returns ErrInvalidContext when ctx is not a chromedp context.

func Cancel added in v0.2.0

func Cancel(ctx context.Context) error

Cancel cancels a chromedp context, waits until the context frees its resources, and returns any error that occurred.

If the context allocated a browser, Cancel closes the browser gracefully. To limit how long Cancel waits for the browser to close, give the context a timeout:

tctx, tcancel := context.WithTimeout(ctx, 10 * time.Second)
defer tcancel()
chromedp.Cancel(tctx)

A "defer cancel()" is enough in most cases. Use Cancel to close a browser gracefully, or to get the errors that occur during the cancellation.

func Console added in v0.19.0

Console subscribes to the console of the target of the context, and returns an iterator over its messages. A message is a call of the console API such as console.log, an uncaught exception, an unhandled promise rejection, or an entry of the browser log. The iterator keeps the order of the messages.

Console reads the events runtime.ConsoleAPICalled, runtime.ExceptionThrown and log.EntryAdded. Events gives the same events one by one, as the protocol sends them, and Console joins them in one stream of simple values. The old API used [ListenTarget] with a func that tested the type of each event.

As Events does, Console subscribes when it returns, and not when the caller starts to range. A caller can subscribe, run the actions, and then range, so that no message is lost:

messages := chromedp.Console(ctx)
if err := chromedp.Do(ctx, chromedp.Navigate(url)); err != nil {
	return err
}
for m, err := range messages {
	if err != nil {
		break
	}
	fmt.Println(m)
}

A browser sends the messages only from the moment that the target exists, so a message that the page wrote before the first call of Console or of Run is lost. If the browser cannot start, the iterator yields the error. See cdp.Events for the rules about ending the iteration.

To stop, cancel the context or break out of the loop. Both end the subscription and free its queue, also when the program never ranged over the iterator.

The queue of the messages has no limit, so that a slow reader never blocks the page. The page keeps working when the program does not read the messages, but the queue grows with each message until the subscription ends. A program that reads slowly or stops to read must cancel the context or break out of the loop.

func DisableGPU added in v0.2.0

func DisableGPU(a *ExecAllocator)

DisableGPU is the command line option to disable the GPU process.

The --disable-gpu option is a temporary workaround for a few bugs in headless mode. The references below say that it is no longer required:

But this issue says that it is still required in some cases:

Chromium 139 and later has no fallback to Swiftshader, unless you pass the --enable-unsafe-swiftshader option:

func Do added in v0.17.0

func Do(ctx context.Context, steps ...Action[Void]) error

Do runs the actions against the target of the context, in order. It stops at the first error. See Run for the rules about the context.

For example:

err := chromedp.Do(ctx,
	chromedp.Navigate("https://example.com"),
	chromedp.Click(chromedp.CSS("a")),
)

func EmulateLandscape added in v0.4.0

EmulateLandscape is an emulate viewport option to set the device viewport screen orientation in landscape primary mode and an angle of 90.

func EmulateMobile added in v0.4.0

EmulateMobile is an emulate viewport option to toggle the device viewport to display as a mobile device.

func EmulatePortrait added in v0.4.0

EmulatePortrait is an emulate viewport option to set the device viewport screen orientation in portrait primary mode and an angle of 0.

func EmulateTouch added in v0.4.0

EmulateTouch is an emulate viewport option to enable touch emulation.

func EvalAsValue

func EvalAsValue(p *runtime.EvaluateParams)

EvalAsValue is an evaluate option that makes the evaluation encode the result of the expression as a JSON-encoded value.

func EvalAwaitPromise added in v0.19.0

func EvalAwaitPromise(p *runtime.EvaluateParams)

EvalAwaitPromise is an evaluate option that makes the evaluation wait for a promise that the expression returns, and use its result. A promise that is rejected makes the action return an *ExceptionError. Without the option, the result of an expression that returns a promise is the promise object, and not its value.

v, err := chromedp.Run(ctx, chromedp.Evaluate[string](`fetch("/api").then(r => r.text())`, chromedp.EvalAwaitPromise))

func EvalIgnoreExceptions

func EvalIgnoreExceptions(p *runtime.EvaluateParams)

EvalIgnoreExceptions is an evaluate option that makes the evaluation ignore exceptions.

func EvalWithCommandLineAPI

func EvalWithCommandLineAPI(p *runtime.EvaluateParams)

EvalWithCommandLineAPI is an evaluate option that makes the DevTools Command Line API available to the evaluated script.

See Evaluate for how evaluate actions work.

Note: do not use this with untrusted JavaScript.

func Events added in v0.17.0

func Events[E any](ctx context.Context, ev cdp.Event[E]) iter.Seq2[E, error]

Events subscribes to the event on the target of the context, and returns an iterator over its payloads. It replaces ListenTarget.

The subscription starts when Events returns, and not when the caller starts to range. A caller can subscribe, trigger the event, and then range, so that no event is lost:

events := chromedp.Events(ctx, page.LoadEventFired)
if err := chromedp.Do(ctx, chromedp.Navigate(url)); err != nil {
	return err
}
for ev, err := range events {
	...
}

As Run does, Events starts the browser and opens the target when the context has none yet. If that fails, the iterator yields the error. See cdp.Events for the rules about ending the iteration. To stop, cancel the context or break out of the loop. Both end the subscription, also when the program never ranged over the iterator. The queue of the events has no limit, so a reader that does not read makes it grow until the subscription ends.

Example (AcceptAlert)
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`
<input id='alert' type='button' value='alert' onclick='alert("alert text");'/>
	`))
	defer ts.Close()

	// The page waits for the dialog, and so does the Click below. A second
	// goroutine closes the dialog.
	dialogs := chromedp.Events(ctx, page.JavascriptDialogOpening)
	go func() {
		for ev, err := range dialogs {
			if err != nil {
				return
			}
			fmt.Println("closing alert:", ev.Message)
			_, err := chromedp.Call(ctx, page.HandleJavaScriptDialog, page.HandleJavaScriptDialogParams{Accept: true})
			if err != nil {
				log.Fatal(err)
			}
		}
	}()

	if err := chromedp.Do(ctx,
		chromedp.Navigate(ts.URL),
		chromedp.Click(chromedp.ID("alert")),
	); err != nil {
		log.Fatal(err)
	}

}
Output:
closing alert: alert text
Example (ConsoleLog)
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`
<body>
<script>
	console.log("hello js world")
	console.warn("scary warning", 123)
	null.throwsException
</script>
</body>
	`))
	defer ts.Close()

	// Subscribe first. The subscriptions buffer the events, so the loops
	// below see the events of the navigation although they start later.
	console := chromedp.Events(ctx, runtime.ConsoleAPICalled)
	exceptions := chromedp.Events(ctx, runtime.ExceptionThrown)

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}

	calls := 0
	for ev, err := range console {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("* console.%s call:\n", ev.Type)
		for _, arg := range ev.Args {
			fmt.Printf("%s - %s\n", arg.Type, arg.Value)
		}
		if calls++; calls == 2 {
			break
		}
	}
	for ev, err := range exceptions {
		if err != nil {
			log.Fatal(err)
		}
		// Since ts.URL uses a random port, replace it.
		s := (&chromedp.ExceptionError{ExceptionDetails: ev.ExceptionDetails}).Error()
		s = strings.ReplaceAll(s, ts.URL, "<server>")
		// V8 changed the error messages for property access on null/undefined in version 9.3.310.
		// see: https://chromium.googlesource.com/v8/v8/+/c0fd89c3c089e888c4f4e8582e56db7066fa779b
		//      https://github.com/chromium/chromium/commit/1735cbf94c98c70ff7554a1e9e01bb9a4f91beb6
		// The test normalizes the message to stay compatible with the versions before this change.
		s = strings.ReplaceAll(s, "Cannot read property 'throwsException' of null", "Cannot read properties of null (reading 'throwsException')")
		fmt.Printf("* %s\n", s)
		break
	}

}
Output:
* console.log call:
string - "hello js world"
* console.warning call:
string - "scary warning"
number - 123
* exception "Uncaught" (4:6): TypeError: Cannot read properties of null (reading 'throwsException')
    at <server>/:5:7
Example (Network)
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/cdproto/network"
	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	// The page has an image that does not exist.
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" {
			http.NotFound(w, r)
			return
		}
		writeHTML(`<body><img src="/missing.png"/></body>`).ServeHTTP(w, r)
	}))
	defer ts.Close()

	// Subscribe before the navigation. The loop below can start after it.
	responses := chromedp.Events(ctx, network.ResponseReceived)

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	for ev, err := range responses {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(strings.TrimPrefix(ev.Response.URL, ts.URL), ev.Response.Status)
		if ev.Type == network.ResourceTypeImage {
			break
		}
	}

}
Output:
/ 200
/missing.png 404

func Headless added in v0.2.0

func Headless(a *ExecAllocator)

Headless is the command line option to run in headless mode. It sets the headless flag, hides scrollbars, and mutes audio.

func IgnoreCertErrors added in v0.7.4

func IgnoreCertErrors(a *ExecAllocator)

IgnoreCertErrors is the command line option to ignore certificate errors. Use it to access an HTTPS website through a proxy.

func KeepOpen added in v0.17.0

func KeepOpen(a *ExecAllocator)

KeepOpen is an ExecAllocatorOption that leaves the browser open when the Go program ends or when the context is canceled. Use it to look at the page after the program is done. See also KeptOpen and VisibleWindow.

The allocator needs a dialer for a kept browser, as it connects with a websocket. Without one, Allocate returns ErrNoDialer. Add WithDialer, or WebSocket of the package github.com/chromedp/chromedp/remote, to the options. For the default allocator of NewContext, give the option WithKeepOpen of that package to NewContext.

The browser must outlive the program, so KeepOpen changes how the allocator starts it:

  • The allocator uses the websocket and not the pipe, because the pipe closes when the Go process exits, and Chrome then exits too. It starts Chrome with --remote-debugging-port=0 and reads the address from the file DevToolsActivePort in the user data directory. The allocator of the remote package can connect to that address later.
  • The process starts detached: in a new session on Unix, and detached from the console and in a new process group on Windows. A func from ModifyCmdFunc runs first, and the detach settings come after it.
  • The allocator does not kill the process when the context ends. It waits for the process in a goroutine, so that no zombie process stays while the program runs.
  • The allocator never removes the user data directory. Unless you set UserDataDir, the directory is "keepopen-PID" in the directory "chromedp" of os.UserCacheDir, where PID is the process ID of the Go program. Each program run leaves one such directory, and you must remove it yourself. Two browsers of one program share the directory, so set UserDataDir when a program keeps more than one browser open.
  • Cancel does not close the browser. The output of the browser goes nowhere, so CombinedOutput has no effect. The library prints nothing. KeptOpen returns the address and the directory, so that the program can print them.

To close a kept browser, close its window, or kill its process. The process is available as Process of the Browser.

func KeptOpen added in v0.17.0

func KeptOpen(ctx context.Context) (wsURL, userDataDir string)

KeptOpen returns the websocket address of the browser of the context and the user data directory of the browser, so that a program can print them. Another program can attach to the address with the allocator of the package github.com/chromedp/chromedp/remote. The user can delete the directory when the browser is closed.

KeptOpen returns two empty strings when the context has no browser yet, or when the allocator did not start the browser with KeepOpen. The browser starts at the first Run, so call KeptOpen after it.

func NewAllocatorContext added in v0.18.0

func NewAllocatorContext(parent context.Context, a Allocator) (context.Context, context.CancelFunc)

NewAllocatorContext creates a new context that holds the allocator a. Use it with NewContext, as with the context of NewExecAllocator. It is for an Allocator that another package implements, such as the allocator of the package github.com/chromedp/chromedp/remote.

The cancel func cancels the context. It does not call the Wait method of a.

func NewContext added in v0.2.0

func NewContext(parent context.Context, opts ...ContextOption) (context.Context, context.CancelFunc)

NewContext creates a chromedp context from the parent context. The context inherits the Allocator of the parent. By default, that is an ExecAllocator with DefaultExecAllocatorOptions.

If the parent context holds an allocated Browser, the child context inherits it, and its first Run creates a new tab on that browser. Otherwise, its first Run allocates a new browser.

Canceling the returned context closes a tab or a whole browser, as the rules above describe. To cancel a context and read the errors, see Cancel.

NewContext does not allocate or start a browser. That happens the first time that you call Run on the context.

The lifetime of the browser

The first call of Run on a context starts the browser, and it binds the life of the browser to the context that you pass to that call. When that context ends, the browser stops. So a context from context.WithTimeout that you use for the first Run closes the browser when the timeout ends, and every later call on the parent context fails with context.Canceled.

To limit one action, start the browser first with a context that has no timeout. Then run the action with a context that you derive from it:

if err := chromedp.Do(ctx); err != nil { // starts the browser
	return err
}
tctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
err := chromedp.Do(tctx, chromedp.Navigate(url))

When the timeout ends, Run returns an error that wraps context.DeadlineExceeded. The tab and the browser stay open, and ctx still works. Run has no option for the timeout of one action.

Use from several goroutines

Contexts that share one browser run in separate tabs, and they are safe to use in parallel. To get them, call Run once on a parent context so that it has a browser, and then make a child context for each goroutine with NewContext. A child of a context that has no browser yet starts a browser of its own.

Do not share one context between goroutines. The actions of one context run in one tab, so they can race. For example, two Navigate actions on the same tab can fail. The first call of Run on a context starts the browser, and it must not run at the same time as another call on that context.

Example (ManyTabs)
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/chromedp/chromedp"
)

func main() {
	// new browser, first tab
	ctx1, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	// make sure that the first tab is created
	if err := chromedp.Do(ctx1); err != nil {
		log.Fatal(err)
	}

	// same browser, second tab
	ctx2, _ := chromedp.NewContext(ctx1)

	// make sure that the second tab is created
	if err := chromedp.Do(ctx2); err != nil {
		log.Fatal(err)
	}

	c1 := chromedp.FromContext(ctx1)
	c2 := chromedp.FromContext(ctx2)

	fmt.Printf("Same browser: %t\n", c1.Browser == c2.Browser)
	fmt.Printf("Same tab: %t\n", c1.Target == c2.Target)

}
Output:
Same browser: true
Same tab: false
Example (ReuseBrowser)
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"
	"time"

	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ts := httptest.NewServer(writeHTML(`
<body>
<script>
	// Show the current cookies.
	var p = document.createElement("p")
	p.innerText = document.cookie
	p.setAttribute("id", "cookies")
	document.body.appendChild(p)

	// Override the cookies.
	document.cookie = "foo=bar"
</script>
</body>
	`))
	defer ts.Close()

	// create a new browser
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	// start the browser without a timeout
	if err := chromedp.Do(ctx); err != nil {
		log.Fatal(err)
	}

	for i := range 2 {
		func() {
			// A slow machine, such as a CI runner, can need more than a
			// second.
			ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
			defer cancel()
			ctx, cancel = chromedp.NewContext(ctx)
			defer cancel()
			if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
				log.Fatal(err)
			}
			cookies, err := chromedp.Run(ctx, chromedp.Text("#cookies"))
			if err != nil {
				log.Fatal(err)
			}
			fmt.Printf("Cookies at i=%d: %q\n", i, cookies)
		}()
	}

}
Output:
Cookies at i=0: ""
Cookies at i=1: "foo=bar"

func NewExecAllocator added in v0.2.0

func NewExecAllocator(parent context.Context, opts ...ExecAllocatorOption) (context.Context, context.CancelFunc)

NewExecAllocator creates a new context with an ExecAllocator. Use it with NewContext.

func NoDefaultBrowserCheck added in v0.2.0

func NoDefaultBrowserCheck(a *ExecAllocator)

NoDefaultBrowserCheck is the Chrome command line option to disable the default browser check.

func NoFirstRun added in v0.2.0

func NoFirstRun(a *ExecAllocator)

NoFirstRun is the Chrome command line option to disable the first run dialog.

func NoInheritEnv added in v0.19.0

func NoInheritEnv(a *ExecAllocator)

NoInheritEnv is an allocator option that starts the browser with only the variables that Env gives, and the variables that a func of ModifyCmdFunc sets in cmd.Env. The browser does not get the environment of the Go process. Use it to keep the secrets of the program away from the browser.

On Linux, the browser then starts with an empty environment. A program can want to pass HOME, PATH, DISPLAY (or WAYLAND_DISPLAY) for a headed browser, and XDG_RUNTIME_DIR. On Windows, os/exec adds SYSTEMROOT by itself, and a browser can also need TEMP, LOCALAPPDATA and USERPROFILE. Give each variable that the browser needs to Env. Without the option, the browser gets the whole environment of the Go process, as before.

func NoSandbox added in v0.2.0

func NoSandbox(a *ExecAllocator)

NoSandbox is the Chrome command line option to disable the sandbox.

func NodeEnabled

func NodeEnabled(s *Selector)

NodeEnabled is an element query option that waits until the browser has sent all queried element nodes. The nodes must be enabled (that is, they have no 'disabled' attribute).

func NodeNotPresent

func NodeNotPresent(s *Selector)

NodeNotPresent is an element query option that waits until no element matches the query.

Note: it sets the expected number of element nodes to 0.

func NodeNotVisible

func NodeNotVisible(s *Selector)

NodeNotVisible is an element query option that waits until the browser has sent all queried element nodes and they are not visible.

func NodeReady

func NodeReady(s *Selector)

NodeReady is an element query option that waits until the browser has sent all queried element nodes.

func NodeSelected

func NodeSelected(s *Selector)

NodeSelected is an element query option that waits until the browser has sent all queried element nodes. The nodes must be selected (that is, they have a 'selected' attribute).

func NodeVisible

func NodeVisible(s *Selector)

NodeVisible is an element query option that waits until the browser has sent all queried element nodes and they are visible.

func Run added in v0.2.0

func Run[T any](ctx context.Context, a Action[T]) (T, error)

Run runs the action against the target of the context, and returns its value. The context must be a chromedp context, typically made with NewContext.

The first time that you call Run on a context, Run allocates a browser with the Allocator, and the browser lives as long as the context of that call. Do not set a timeout on the context of that first call, because the timeout stops the whole browser. To limit one action, run it with a context that you derive with context.WithTimeout from a context that has run once. See NewContext.

For example:

title, err := chromedp.Run(ctx, chromedp.Title())

If the browser process dies while nobody has asked it to stop, for example when it crashes or when the system kills it for lack of memory, then Run returns an error that wraps the exit error of the process and the error of the context. Use errors.As with a pointer to an os/exec.ExitError to read the signal or the status.

Use Do to run several actions that return no value.

Contexts that share a browser run in separate tabs, so goroutines can call Run in parallel when each one has its own context. Actions on one context share one tab, so they can race. See NewContext.

func RunResponse added in v0.5.4

func RunResponse(ctx context.Context, steps ...Action[Void]) (*network.Response, error)

RunResponse is an alternative to Do for a list of actions that trigger a page navigation, such as a click on a link or a button.

RunResponse runs the actions and blocks until a page loads. Then it returns the HTTP response of the HTML document. Use it to wait for the page, or to catch 404 status codes.

If the actions trigger several navigations, RunResponse uses only the first. If the actions trigger no navigation, RunResponse blocks until the context is canceled.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"net/http/httptest"

	"github.com/chromedp/chromedp"
)

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	// This server shows the URL path as the page title, and contains
	// a link that points to /foo.
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		fmt.Fprintf(w, `
			<head><title>%s</title></head>
			<body><a id="foo" href="/foo">foo</a></body>
		`, r.URL.Path)
	}))
	defer ts.Close()

	// The Navigate action already waits until a page loads, so Title runs
	// once the page is ready.
	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	firstTitle, err := chromedp.Run(ctx, chromedp.Title())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("first title:", firstTitle)

	// However, actions like Click do not always trigger a page navigation,
	// so they do not wait for a page load directly. Wrapping them with
	// RunResponse does that waiting, and also obtains the HTTP response.
	resp, err := chromedp.RunResponse(ctx, chromedp.Click(chromedp.ID("foo")))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("second status code:", resp.Status)

	// Getting the title again works, because the page finished loading once
	// more.
	secondTitle, err := chromedp.Run(ctx, chromedp.Title())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("second title:", secondTitle)

	// You can also wrap Navigate with RunResponse to get the response
	// information for that case too.
	resp, err = chromedp.RunResponse(ctx, chromedp.Navigate(ts.URL+"/bar"))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("third status code:", resp.Status)

	// NavigateResponse is a shorter way to do the same.
	resp, err = chromedp.Run(ctx, chromedp.NavigateResponse(ts.URL+"/baz"))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("fourth status code:", resp.Status)

}
Output:
first title: /
second status code: 200
second title: /foo
third status code: 200
fourth status code: 200

func Targets added in v0.2.0

func Targets(ctx context.Context) ([]*target.Info, error)

Targets lists the targets of the browser of the context.

func VisibleWindow added in v0.17.0

func VisibleWindow(a *ExecAllocator)

VisibleWindow is the command line option to run the browser with a visible window. It removes the flags that make the browser quiet or hidden, and it starts the window maximized.

It removes these flags: headless, hide-scrollbars, mute-audio, enable-automation (the infobar that says that software controls the browser) and disable-extensions. It keeps every other flag, and it adds start-maximized. It does not open the developer tools. To open them for every tab, add Flag("auto-open-devtools-for-tabs", true).

Add VisibleWindow after the options that it must change. It only removes the flags that exist when it runs. For example:

opts := append(chromedp.DefaultExecAllocatorOptions[:], chromedp.VisibleWindow)
ctx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)

On Linux, Allocate returns ErrNoDisplay when the environment variables DISPLAY and WAYLAND_DISPLAY are both empty. The allocator never falls back to headless mode. Allocate does no such check on macOS and Windows.

Example

This example shows the allocator options. They work with NewExecAllocator, when the program makes its own allocator.

package main

import (
	"context"
	"log"

	"github.com/chromedp/chromedp"
)

func main() {
	opts := append(chromedp.DefaultExecAllocatorOptions[:],
		chromedp.VisibleWindow,
		chromedp.Flag("auto-open-devtools-for-tabs", true),
	)
	allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
	defer cancel()
	ctx, cancel := chromedp.NewContext(allocCtx)
	defer cancel()

	if err := chromedp.Do(ctx, chromedp.Navigate("https://example.com")); err != nil {
		log.Fatal(err)
	}
	chromedp.WaitClosed(ctx)
}

func WaitClosed added in v0.17.0

func WaitClosed(ctx context.Context) error

WaitClosed blocks until the browser process of the context exits, for example when the user closes the last window, or until ctx ends. It returns nil when the process exited, and the error of ctx otherwise. Use it in a program that must stay alive while the user looks at the window.

If the context has no browser yet, WaitClosed starts one, as Run does. For a browser that an allocator of the remote package reaches, WaitClosed waits until the connection drops, because there is no process to watch.

func WaitNewTarget added in v0.4.0

func WaitNewTarget(ctx context.Context, fn func(*target.Info) bool) <-chan target.ID

WaitNewTarget waits for the current target to open a new target. When fn matches a new target that is not attached, WaitNewTarget sends its target ID on the returned channel. The channel closes without a value when the context has no valid target.

Example
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/cdproto/target"
	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	mux := http.NewServeMux()
	mux.Handle("/first", writeHTML(`
<input id='newtab' type='button' value='open' onclick='window.open("/second", "_blank");'/>
	`))
	mux.Handle("/second", writeHTML(``))
	ts := httptest.NewServer(mux)
	defer ts.Close()

	// Grab the first spawned tab that is not blank.
	ch := chromedp.WaitNewTarget(ctx, func(info *target.Info) bool {
		return info.URL != ""
	})
	if err := chromedp.Do(ctx,
		chromedp.Navigate(ts.URL+"/first"),
		chromedp.Click(chromedp.ID("newtab")),
	); err != nil {
		log.Fatal(err)
	}
	newCtx, cancel := chromedp.NewContext(ctx, chromedp.WithTargetID(<-ch))
	defer cancel()

	urlstr, err := chromedp.Run(newCtx, chromedp.Location())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("new tab's path:", strings.TrimPrefix(urlstr, ts.URL))

}
Output:
new tab's path: /second

Types

type Action

type Action[T any] func(ctx context.Context, t *Target) (T, error)

Action is a step that runs against the target of a chromedp context and returns a value of the type T. An action that returns no value has the type Action[Void].

An action is a plain func, so a program can write its own:

title := func(ctx context.Context, t *chromedp.Target) (string, error) {
	res, err := cdp.Call(ctx, t, runtime.Evaluate, runtime.EvaluateParams{
		Expression:    "document.title",
		ReturnByValue: ptr(true),
	})
	...
}

The target t is a cdp.Session. Use it with cdp.Call to send a protocol command, and with cdp.Events to receive protocol events.

func AttributeValue

func AttributeValue[S Selectable](sel S, name string, opts ...QueryOption) Action[AttributeResult]

AttributeValue is an element query action that retrieves the element attribute value for the first element node matching the selector. The result tells whether the attribute exists.

func Attributes

func Attributes[S Selectable](sel S, opts ...QueryOption) Action[map[string]string]

Attributes is an element query action that retrieves the element attributes for the first element node matching the selector.

func AttributesAll

func AttributesAll[S Selectable](sel S, opts ...QueryOption) Action[[]map[string]string]

AttributesAll is an element query action that retrieves the element attributes for all element nodes matching the selector. Note: use it with a CSSAll selector.

func Blur

func Blur[S Selectable](sel S, opts ...QueryOption) Action[Void]

Blur is an element query action that unfocuses (blurs) the first element node matching the selector.

func CallFunctionOn added in v0.7.4

func CallFunctionOn[T any](functionDeclaration string, opt CallOption, args ...any) Action[T]

CallFunctionOn is an action that calls a JavaScript function and decodes the result of the function into the type T.

T is handled as in Evaluate. A function that returns null gives ErrJSNull when T cannot be nil.

Do not set these fields of runtime.CallFunctionOnParams:

  • ReturnByValue: CallFunctionOn sets it from the type T.
  • Arguments: pass the arguments with args instead.

If the function throws an exception, CallFunctionOn returns it as an error.

func CaptureScreenshot

func CaptureScreenshot() Action[[]byte]

CaptureScreenshot is an action that takes a screenshot of the current browser viewport.

It acts like the command "Capture screenshot" in Chrome. See the behavior notes of Screenshot for more information.

To take a screenshot of one element, use the Screenshot action.

For an example that takes a screenshot of the entire page, see screenshot.

func Clear

func Clear[S Selectable](sel S, opts ...QueryOption) Action[Void]

Clear is an element query action that clears the values of any input/textarea element nodes matching the selector.

func Click

func Click[S Selectable](sel S, opts ...QueryOption) Action[Void]

Click is an element query action that sends a mouse click event to the first element node matching the selector.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"net/http/httptest"

	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/chromedp"
)

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		fmt.Fprintf(w, `<head><title>%s</title></head><body><a id="next" href="/next">next</a></body>`, r.URL.Path)
	}))
	defer ts.Close()

	// Click does not wait for a page load. So WaitEvent subscribes to the
	// load event first, then runs the click, and returns the first event
	// that comes after it. No event is lost between the click and the wait.
	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	_, err := chromedp.Run(ctx, chromedp.WaitEvent(page.LoadEventFired, nil,
		chromedp.Click(chromedp.ID("next"))))
	if err != nil {
		log.Fatal(err)
	}
	title, err := chromedp.Run(ctx, chromedp.Title())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("title after the click:", title)

}
Output:
title after the click: /next

func ComputedStyle

func ComputedStyle[S Selectable](sel S, opts ...QueryOption) Action[[]*css.ComputedStyleProperty]

ComputedStyle is an element query action that retrieves the computed style of the first element node matching the selector.

func Dimensions

func Dimensions[S Selectable](sel S, opts ...QueryOption) Action[*dom.BoxModel]

Dimensions is an element query action that retrieves the box model dimensions for the first element node matching the selector.

func DoubleClick

func DoubleClick[S Selectable](sel S, opts ...QueryOption) Action[Void]

DoubleClick is an element query action that sends a mouse double click event to the first element node matching the selector.

func DragAndDrop added in v0.19.0

func DragAndDrop[S, T Selectable](from S, to T, opts ...QueryOption) Action[Void]

DragAndDrop is an element query action that drags the first element node that matches from, and drops it on the first element node that matches to. It presses the left mouse button at the center of the first node, moves the mouse to the center of the second node in several steps, and releases the button. See DragAndDropXY for the details.

The two selectors can have different types. The query options apply to both queries. Both nodes must be in the viewport at the same time, because the action does not scroll while it drags. When they do not fit, the action returns ErrDragOutsideViewport and does not drag.

For example, to move a handle to the end of a slider:

err := chromedp.Do(ctx, chromedp.DragAndDrop(chromedp.CSS("#handle"), chromedp.CSS("#end")))

func DragAndDropXY added in v0.19.0

func DragAndDropXY(fromX, fromY, toX, toY float64, steps ...int) Action[Void]

DragAndDropXY is an action that drags from the point fromX, fromY and drops at the point toX, toY. The points are in CSS pixels, relative to the viewport. The optional steps value is the number of mouse moves between the two points. The default is 10, and a value below 1 means 1.

The action works for two kinds of page. It handles both with the same calls, and the page decides which one it is:

  • A page that listens for mouse events, such as a slider, a drag handle or a sortable list, gets a mousePressed event, the mouseMoved events and a mouseReleased event.
  • A page that uses HTML5 drag and drop, with draggable elements and the events dragstart, dragover and drop, gets the same mouse events up to the start of the drag. Then the browser starts a native drag, which a headless browser does not always finish with mouse events. So the action turns on input.SetInterceptDrags, reads the data of the drag from the event input.DragIntercepted, and sends the events dragEnter, dragOver and drop with input.DispatchDragEvent. The page sees them as the real events, with a DataTransfer that holds the data of the drag.

The action turns the interception off when it returns. When an error ends the drag after the mouse button went down, for example when the context ends, the action still releases the button at the last point of the mouse. It uses a new context with a limit of 5 seconds for the release, and ignores an error of the release. A drag that a page starts with a distance that is shorter than the drag threshold of the browser, a few pixels, does not start. Use points that are at least 10 pixels apart.

func Dump added in v0.9.5

func Dump[S Selectable](sel S, w io.Writer, opts ...QueryOption) Action[Void]

Dump is an element query action that writes a readable tree of the first element node matching the selector and its children. The tree ends at the specified depth.

See DumpTo for more options, which include the sleep wait timeout.

func DumpTo added in v0.9.5

func DumpTo[S Selectable](sel S, w io.Writer, prefix, indent string, nodeIDs bool, depth int64, pierce bool, wait time.Duration, opts ...QueryOption) Action[Void]

DumpTo is an element query action that writes a readable tree of the first element node matching the selector and its children. The tree ends at the specified depth.

See Dump for a simpler interface.

func Emulate added in v0.4.0

func Emulate(device Device) Action[Void]

Emulate is an action to emulate a specific device.

See device for a set of ready-made devices and modes.

Example
package main

import (
	"context"
	"log"
	"os"

	"github.com/chromedp/chromedp"
	"github.com/chromedp/chromedp/device"
)

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	if err := chromedp.Do(ctx,
		chromedp.Emulate(device.IPhone7),
		chromedp.Navigate(`https://duckduckgo.com/`),
		chromedp.SendKeys(`textarea[name=q]`, "what's my user agent?\n"),
		chromedp.WaitVisible(chromedp.ID(`zci-answer`)),
	); err != nil {
		log.Fatal(err)
	}
	buf, err := chromedp.Run(ctx, chromedp.CaptureScreenshot())
	if err != nil {
		log.Fatal(err)
	}

	if err := os.WriteFile("iphone7-ua.png", buf, 0o644); err != nil {
		log.Fatal(err)
	}

	// This example uses a live website and writes a file, so it has no
	// Output comment: go test builds it and does not run it. A live website
	// can change or be slow, and the example made the tests fail on CI.
}

func EmulateReset added in v0.4.0

func EmulateReset() Action[Void]

EmulateReset is an action that resets the device emulation.

It resets the viewport, the screen orientation, the user agent, and the mobile and touch emulation. The new values are the original values from the start of the browser.

func EmulateViewport added in v0.4.0

func EmulateViewport(width, height int64, opts ...EmulateViewportOption) Action[Void]

EmulateViewport is an action that changes the browser viewport.

It wraps calls to emulation.SetDeviceMetricsOverride and emulation.SetTouchEmulationEnabled.

Note: by default, this action sets the screen orientation to landscape and disables mobile and touch emulation. To change that, use the emulate viewport options EmulateOrientation (or EmulateLandscape or EmulatePortrait), EmulateMobile, and EmulateTouch.

func Evaluate

func Evaluate[T any](expression string, opts ...EvaluateOption) Action[T]

Evaluate is an action that evaluates the JavaScript expression and decodes the result of the script into the type T.

When T is Void, Evaluate ignores the script result.

When T is []byte, the result is the raw JSON-encoded value of the script result.

When T is *runtime.RemoteObject, the result is the low-level protocol type, and Evaluate does not convert it. The original objects can stay in memory until the page navigates or closes. Use `runtime.ReleaseObject` or `runtime.ReleaseObjectGroup` to ask the browser to release them.

For all other types, the script returns the result "by value" (that is, JSON-encoded). Evaluate then decodes it into a value of type T. Only a chan, func, interface, map, pointer, or slice type can be nil. When the script result is "undefined" or "null" and T cannot be nil, the action returns ErrJSUndefined or ErrJSNull respectively. The expression `null` gives ErrJSNull for an int, and a nil pointer for a *int. The expression `Promise.resolve(1)` needs the option EvalAwaitPromise.

For example:

n, err := chromedp.Run(ctx, chromedp.Evaluate[int](`1 + 2`))
Example
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/chromedp"
)

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	// Ignore the result:
	{
		if err := chromedp.Do(ctx, chromedp.Evaluate[chromedp.Void](`window.scrollTo(0, 100)`)); err != nil {
			log.Fatal(err)
		}
	}

	// Receive a primary value:
	{
		sum, err := chromedp.Run(ctx, chromedp.Evaluate[int](`1+2`))
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(sum)
	}

	// ErrJSUndefined:
	{
		if _, err := chromedp.Run(ctx, chromedp.Evaluate[int](`undefined`)); err != nil {
			fmt.Println(err)
		}
	}

	// ErrJSNull:
	{
		if _, err := chromedp.Run(ctx, chromedp.Evaluate[int](`null`)); err != nil {
			fmt.Println(err)
		}
	}

	// Accept undefined/null result:
	{
		val, err := chromedp.Run(ctx, chromedp.Evaluate[*int](`undefined`))
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(val)
	}

	// Receive an array value:
	{
		val, err := chromedp.Run(ctx, chromedp.Evaluate[[]int](`[1,2]`))
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(val)
	}

	// Map and Slice accept undefined/null:
	{
		val, err := chromedp.Run(ctx, chromedp.Evaluate[[]int](`null`))
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("slice is nil:", val == nil)
	}

	// Receive the raw bytes:
	{
		buf, err := chromedp.Run(ctx, chromedp.Evaluate[[]byte](`alert`))
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%s\n", buf)
	}

	// Receive the RemoteObject:
	{
		res, err := chromedp.Run(ctx, chromedp.Evaluate[*runtime.RemoteObject](`alert`))
		if err != nil {
			log.Fatal(err)
		}
		if res.ObjectID != "" {
			fmt.Println("objectId is present")
		}
	}

}
Output:
3
encountered an undefined value
encountered a null value
<nil>
[1 2]
slice is nil: true
{}
objectId is present

func EvaluateAsDevTools

func EvaluateAsDevTools[T any](expression string, opts ...EvaluateOption) Action[T]

EvaluateAsDevTools is an action that evaluates a JavaScript expression as Chrome DevTools does. It evaluates the expression in the "console" context and makes the Command Line API available to the script.

See Evaluate for how the expressions are evaluated.

Note: do not use this with untrusted JavaScript.

func ExposeFunc added in v0.19.0

func ExposeFunc[A, R any](name string, fn func(ctx context.Context, arg A) (R, error)) Action[Void]

ExposeFunc is an action that makes the Go func fn available to the page as window.<name>. A page script calls it like an async function. The call returns a promise that the browser settles with the result of fn, or rejects with an Error when fn returns an error. It is like exposeFunction in Puppeteer.

The function is there in the current document and in every document that the target loads later, for the main frame and for every iframe of the same site, so it survives a navigation. An iframe of another site runs in another process and is another target, so the function is not there. It stays until the target ends. The listener for the calls stops when the context of the target ends. A second call of ExposeFunc with the same name on the same target returns an error. So does a name that is empty, that is not valid UTF-8, or that starts with "__chromedp_", the prefix of the private names of the package.

A script passes its arguments as JSON, so a value such as a function or a DOM node does not work. How the arguments reach fn depends on the type A:

  • When A is a slice type, such as []any or []float64, fn gets all the arguments of the call in the slice. Use it for a call with several arguments, or with none.
  • For every other A, the call must have one argument, and the action decodes it into A. Use a struct for an object, or a basic type. A call with no argument gives the zero value of A, and a call with more than one argument is an error that rejects the promise.

The action encodes the result of fn as JSON for the page. When R is Void, the promise resolves with undefined.

The action runs fn in a new goroutine for each call, so fn can run several times at the same time and must be safe for that. The ctx of fn has the values of the context that ExposeFunc received, and it ends when the target ends. If fn panics, the promise rejects with an Error whose message is "panic:" and the panic value, for example "panic: boom". The message of an error that fn returns replaces each byte that is not valid UTF-8 with U+FFFD.

For example, a page that calls window.square(7):

err := chromedp.Do(ctx,
	chromedp.ExposeFunc("square", func(ctx context.Context, n float64) (float64, error) {
		return n * n, nil
	}),
	chromedp.Navigate(url),
)

func Focus

func Focus[S Selectable](sel S, opts ...QueryOption) Action[Void]

Focus is an element query action that focuses the first element node matching the selector.

func FullScreenshot added in v0.7.0

func FullScreenshot(quality int) Action[[]byte]

FullScreenshot takes a full screenshot of the entire browser viewport, with the given image quality.

It acts like the command "Capture full size screenshot" in Chrome. See the behavior notes of Screenshot for more information.

The valid range of the compression quality is [0..100]. When the quality is 100, the image format is png. Otherwise the image format is jpeg.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/chromedp/chromedp"
)

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	if err := chromedp.Do(ctx, chromedp.Navigate(`https://google.com`)); err != nil {
		log.Fatal(err)
	}
	buf, err := chromedp.Run(ctx, chromedp.FullScreenshot(90))
	if err != nil {
		log.Fatal(err)
	}

	if err := os.WriteFile("fullScreenshot.jpeg", buf, 0o644); err != nil {
		log.Fatal(err)
	}
	fmt.Println("wrote fullScreenshot.jpeg")
}
Output:
wrote fullScreenshot.jpeg

func Func added in v0.17.0

func Func(f func(ctx context.Context, t *Target) error) Action[Void]

Func makes an action that returns no value from a func that returns only an error.

func InnerHTML

func InnerHTML[S Selectable](sel S, opts ...QueryOption) Action[string]

InnerHTML is an element query action that retrieves the inner html of the first element node matching the selector.

func JavascriptAttribute

func JavascriptAttribute[T any, S Selectable](sel S, name string, opts ...QueryOption) Action[T]

JavascriptAttribute is an element query action that retrieves the JavaScript attribute for the first element node matching the selector. It decodes the attribute into the type T, as Evaluate does, with one difference. When the attribute is null, for example "onclick" with no handler, JavascriptAttribute returns the zero value of T and no error, and it does not return ErrJSNull. An attribute that the element does not have is undefined, and the action returns an error that wraps ErrJSUndefined for a type that cannot be nil.

func KeyEvent added in v0.4.0

func KeyEvent(keys string, opts ...KeyOption) Action[Void]

KeyEvent is a key action that synthesizes a keyDown, char, and keyUp event for each rune in keys, with any key options.

Only well-known, "printable" characters get char events. A key with the modifier Ctrl, Alt or Meta gets no char event, because the char event types the character on top of the shortcut. For example, Ctrl+A selects the text and types no "a". A key with the modifier Shift keeps its char event.

See the SendKeys action to synthesize key events for a specific element node.

See the kb package for implementation details and a list of well-known keys.

func KeyEventNode added in v0.4.0

func KeyEventNode(n *Node, keys string, opts ...KeyOption) Action[Void]

KeyEventNode is a key action that dispatches a key event on an element node.

func Legacy added in v0.17.0

func Legacy(a OldAction) Action[Void]

Legacy makes an action from an action of the previous version. The old action receives the same context, so Call and CallBrowser work inside it.

Example
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/cdproto/runtime"
	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

// oldTitle is an action of the previous version of chromedp. It has a Do
// method.
type oldTitle struct{ res *string }

func (a oldTitle) Do(ctx context.Context) error {
	res, err := chromedp.Call(ctx, runtime.Evaluate, runtime.EvaluateParams{
		Expression:    "document.title",
		ReturnByValue: ptr(true),
	})
	if err != nil {
		return err
	}
	return json.Unmarshal(res.Result.Value, a.res)
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`<title>old action</title>`))
	defer ts.Close()

	var title string
	if err := chromedp.Do(ctx,
		chromedp.Navigate(ts.URL),
		chromedp.Legacy(oldTitle{&title}),
	); err != nil {
		log.Fatal(err)
	}
	fmt.Println(title)

}

// ptr returns a pointer to a copy of v. It sets the optional fields of the
// protocol types, which are pointers.
func ptr[T any](v T) *T {
	return &v
}
Output:
old action

func Location

func Location() Action[string]

Location is an action that retrieves the document location.

func MatchedStyle

func MatchedStyle[S Selectable](sel S, opts ...QueryOption) Action[*css.GetMatchedStylesForNodeResult]

MatchedStyle is an element query action that retrieves the matched style information for the first element node matching the selector.

func MouseClickNode

func MouseClickNode(n *Node, opts ...MouseOption) Action[Void]

MouseClickNode is an action that dispatches a left mouse button click event at the center of a node.

Note: the action scrolls the window if the node is not within the viewport of the window.

func MouseClickXY

func MouseClickXY(x, y float64, opts ...MouseOption) Action[Void]

MouseClickXY is an action that sends a left mouse button click (that is, a mousePressed and a mouseReleased event) to the X, Y location.

func MouseEvent added in v0.4.0

func MouseEvent(typ input.DispatchMouseEventType, x, y float64, opts ...MouseOption) Action[Void]

MouseEvent is a mouse event action to dispatch the specified mouse event type at coordinates x, y.

func Navigate(urlstr string) Action[Void]

Navigate is an action that navigates the current frame and waits for the page to load.

This action does not collect HTTP response information. To get it, use NavigateResponse or RunResponse.

func NavigateBack() Action[Void]

NavigateBack is an action that navigates the current frame backwards in its history, and waits for the page to load.

func NavigateForward() Action[Void]

NavigateForward is an action that navigates the current frame forwards in its history, and waits for the page to load.

func NavigateResponse(urlstr string) Action[*network.Response]

NavigateResponse is like Navigate, and returns the HTTP response of the HTML document.

func NavigateToHistoryEntry(entryID int64) Action[Void]

NavigateToHistoryEntry is an action to navigate to the specified navigation entry, and wait for the page to load.

func NavigationEntries() Action[page.GetNavigationHistoryResult]

NavigationEntries is an action that retrieves the page's navigation history entries. The result holds the index of the current entry and the entries.

func Nodes

func Nodes[S Selectable](sel S, opts ...QueryOption) Action[[]*Node]

Nodes is an element query action that retrieves the document element nodes matching the selector.

func OuterHTML

func OuterHTML[S Selectable](sel S, opts ...QueryOption) Action[string]

OuterHTML is an element query action that retrieves the outer html of the first element node matching the selector.

func Poll added in v0.6.11

func Poll[T any](expression string, opts ...PollOption) Action[T]

Poll is a poll action that waits for a general JavaScript predicate. It builds the predicate from a JavaScript expression.

This is a copy of page.waitForFunction of puppeteer. It is named Poll on purpose, so that it does not mix with the Wait* query actions. The behavior is not guaranteed to be compatible. For example, in our implementation the poll task does not survive a navigation. In this case the action returns an error (see unit test TestPoll/NotSurviveNavigation).

Polling Options

The default polling mode is "raf". It runs pageFunction in a requestAnimationFrame callback all the time. This is the tightest polling mode, and it is suitable to observe styling changes. The WithPollingInterval option polls the predicate at a given interval. The WithPollingMutation option polls the predicate on every DOM mutation.

The WithPollingTimeout option sets the maximum time to wait until the predicate returns a truthy value. It defaults to 30 seconds. Pass 0 to disable the timeout.

The WithPollingInFrame option sets the frame in which to evaluate the predicate. Without it, the action evaluates the predicate in the root page of the current tab.

The WithPollingArgs option gives extra arguments to the predicate. Use this option only when the predicate is built from a function. See PollFunction.

The action returns the truthy value of the predicate, decoded into the type T. T is handled as in Evaluate. Use Void when the value does not matter.

func PollFunction added in v0.6.11

func PollFunction[T any](pageFunction string, opts ...PollOption) Action[T]

PollFunction is a poll action that waits for a general JavaScript predicate. It builds the predicate from a JavaScript function.

See Poll for how to build poll tasks.

func PrintToPDF added in v0.19.0

func PrintToPDF(opts ...PDFOption) Action[[]byte]

PrintToPDF is an action that prints the page to a PDF file, and returns the bytes of the file. With no option, the browser prints on Letter paper, in portrait, with the margins of 1 cm, and with no header, footer or background.

A length is in inches, and a CSS pixel is 1/96 of an inch. For example, a landscape A4 page with a header and a page number:

buf, err := chromedp.Run(ctx, chromedp.PrintToPDF(
	chromedp.PDFPaper(chromedp.PaperA4),
	chromedp.PDFLandscape(),
	chromedp.PDFMargin(0.5),
	chromedp.PDFPrintBackground(),
	chromedp.PDFHeaderTemplate(`<div style="font-size:8px"><span class="title"></span></div>`),
	chromedp.PDFFooterTemplate(`<div style="font-size:8px"><span class="pageNumber"></span></div>`),
))

For a field that no option sets, send page.PrintToPDF yourself with cdp.Call, and give an option that changes the parameters. An option is a func, so it can do that:

func(p *page.PrintToPDFParams) { p.TransferMode = page.PrintToPDFTransferModeReturnAsStream }

The browser returns an error when the page ranges select no page. Wait for the page to load before the call.

Example
package main

import (
	"context"
	"log"
	"os"

	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/chromedp"
)

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	// A custom action sends the protocol command with cdp.Call. It returns
	// the bytes of the PDF file.
	printToPDF := func(ctx context.Context, t *chromedp.Target) ([]byte, error) {
		res, err := cdp.Call(ctx, t, page.PrintToPDF, page.PrintToPDFParams{
			DisplayHeaderFooter: ptr(false),
			Landscape:           ptr(true),
		})
		return res.Data, err
	}

	if err := chromedp.Do(ctx, chromedp.Navigate(`https://pkg.go.dev/github.com/chromedp/chromedp`)); err != nil {
		log.Fatal(err)
	}
	buf, err := chromedp.Run(ctx, printToPDF)
	if err != nil {
		log.Fatal(err)
	}

	if err := os.WriteFile("page.pdf", buf, 0o644); err != nil {
		log.Fatal(err)
	}

	// This example uses a live website and writes a file, so it has no
	// Output comment: go test builds it and does not run it. A live website
	// can change or be slow, and the example made the tests fail on CI.
}

// ptr returns a pointer to a copy of v. It sets the optional fields of the
// protocol types, which are pointers.
func ptr[T any](v T) *T {
	return &v
}
Example (Options)
package main

import (
	"context"
	"log"
	"os"

	"github.com/chromedp/chromedp"
)

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	if err := chromedp.Do(ctx, chromedp.Navigate(`https://pkg.go.dev/github.com/chromedp/chromedp`)); err != nil {
		log.Fatal(err)
	}
	// The options replace the page.PrintToPDFParams of the example above.
	buf, err := chromedp.Run(ctx, chromedp.PrintToPDF(
		chromedp.PDFPaper(chromedp.PaperA4),
		chromedp.PDFLandscape(),
		chromedp.PDFMargin(0.5),
		chromedp.PDFPrintBackground(),
		chromedp.PDFFooterTemplate(`<div style="font-size:8px"><span class="pageNumber"></span> / <span class="totalPages"></span></div>`),
	))
	if err != nil {
		log.Fatal(err)
	}

	if err := os.WriteFile("page.pdf", buf, 0o644); err != nil {
		log.Fatal(err)
	}

	// This example uses a live website and writes a file, so it has no
	// Output comment.
}

func Query

func Query[S Selectable](sel S, opts ...QueryOption) Action[Void]

Query is an action that queries the browser for element nodes that match the criteria, and waits until they meet the node conditions. It returns no value. To get the nodes, see Nodes.

Query actions that target element nodes share one selector. Use the After option or QueryAfter to read data from the selected elements or to change them.

For example:

chromedp.Do(ctx, chromedp.SendKeys(chromedp.ID("thing"), "hello"))

This runs a SendKeys action on the first element that has the id "thing".

Element selection queries work with specific actions. They are the main way to automate steps in the browser. They have this form:

Action(selector[, parameter1, ...parameterN][, queryOptions...])

Where:

  • Action - the action to run
  • selector - the element query, a Selectable value. The action applies to every node that matches it.
  • parameter[1-N] - the parameters that the action needs (if any)
  • queryOptions - change how the query runs, or how it waits for nodes

An action that reads a value returns it. For example, Text returns the text as a string.

Selectors

The type of the selector chooses the lookup that the browser runs. A plain string, or any other string type that this package does not define, is a Search.

The Search type (the default) queries elements by plain text, CSS selector, or XPath query. It wraps DOM.performSearch.

The ID type queries a single element by its CSS ID. It wraps DOM.querySelector. ID is like document.querySelector('#' + ID) in the browser.

The CSS type queries a single element with a CSS selector. It wraps DOM.querySelector. CSS is like document.querySelector() in the browser.

The CSSAll type queries elements with a CSS selector. It wraps DOM.querySelectorAll. CSSAll is like document.querySelectorAll() in the browser.

The JSPath type queries a single element by its "JS Path" value. It wraps Runtime.evaluate. JSPath is like a JavaScript snippet that returns an element in the browser. Use it only with trusted element queries. chromedp passes the query directly to Runtime.evaluate and does not sanitize it. The type is useful for DOM elements that the other types cannot retrieve, such as ShadowDOM elements. The expression can give a node, an array or a NodeList of nodes, or null or undefined. Null, undefined and an empty list select no element, so WaitNotPresent succeeds and the other waits keep waiting. Any other value is an error, and the query returns it at once.

The NodeIDs type selects the elements with the given node IDs. It uses DOM.requestChildNodes to retrieve them.

A type outside the Selectable set, such as an int or a *Node, does not compile.

Query Options

The Node* options set node conditions. The query waits until the condition is true. Without a Node* option, the query uses the NodeReady condition.

The AtLeast option sets the minimum number of nodes that the query must return. The default is 1.

The After option sets a func that runs after the query returns one or more elements and the node condition is true.

The ByFunc option replaces the lookup of the selector with a custom func.

Node Options

The NodeReady option (the default) makes the query wait until the browser has returned all element nodes that match the selector.

The NodeVisible option makes the query wait until the browser has returned all element nodes that match the selector, and they are visible.

The NodeNotVisible option makes the query wait until the browser has returned all element nodes that match the selector, and they are not visible.

The NodeEnabled option makes the query wait until the browser has returned all element nodes that match the selector. The nodes must be enabled (that is, they have no 'disabled' attribute).

The NodeSelected option makes the query wait until the browser has returned all element nodes that match the selector. The nodes must be selected (that is, they have a 'selected' attribute).

The NodeNotPresent option makes the query wait until no element node matches the selector.

func QueryAfter

func QueryAfter[T any, S Selectable](sel S, f func(ctx context.Context, t *Target, nodes []*Node) (T, error), opts ...QueryOption) Action[T]

QueryAfter is an element query action that queries the browser for selector sel. It waits until the node conditions of the query are met, then runs f and returns its value.

func QueryNodeIDs added in v0.17.0

func QueryNodeIDs[S Selectable](sel S, opts ...QueryOption) Action[[]cdp.NodeID]

QueryNodeIDs is an element query action that retrieves the element node IDs matching the selector.

func Reload

func Reload() Action[Void]

Reload is an action that reloads the current page, and waits for the page to load.

func RemoveAttribute

func RemoveAttribute[S Selectable](sel S, name string, opts ...QueryOption) Action[Void]

RemoveAttribute is an element query action that removes the element attribute with name from the first element node matching the selector.

func Reset

func Reset[S Selectable](sel S, opts ...QueryOption) Action[Void]

Reset is an element query action that resets the parent form of the first element node matching the selector.

func ResetViewport added in v0.4.0

func ResetViewport() Action[Void]

ResetViewport is an action that resets the browser viewport to the values that the browser started with.

Note: it does not change the emulated User-Agent of the browser, if any.

func Screenshot

func Screenshot[S Selectable](sel S, opts ...QueryOption) Action[[]byte]

Screenshot is an element query action that takes a screenshot of the first element node that matches the selector.

It acts like the command "Capture node screenshot" in Chrome.

Behavior notes: the Protocol Monitor shows that the command also sends these protocol commands:

  • Emulation.clearDeviceMetricsOverride
  • Network.setUserAgentOverride with {"userAgent": ""}
  • Overlay.setShowViewportSizeOnResize with {"show": false}

chromedp does not send these protocol commands. If the result is not what you expect, send them yourself.

To capture the browser viewport, see CaptureScreenshot.

For an example that takes a screenshot of the entire page, see screenshot.

func ScreenshotNodes added in v0.9.4

func ScreenshotNodes(nodes []*Node, scale float64) Action[[]byte]

ScreenshotNodes is an action that takes a screenshot of the specified nodes. It calculates the extents from the top most left node and the bottom most right node.

func ScreenshotScale added in v0.9.3

func ScreenshotScale[S Selectable](sel S, scale float64, opts ...QueryOption) Action[[]byte]

ScreenshotScale is like Screenshot but takes a scale parameter, which is the page scale factor.

func ScrollIntoView

func ScrollIntoView[S Selectable](sel S, opts ...QueryOption) Action[Void]

ScrollIntoView is an element query action that scrolls the window to the first element node matching the selector.

func SendKeys

func SendKeys[S Selectable](sel S, v string, opts ...QueryOption) Action[Void]

SendKeys is an element query action that sends key events to the first element node that matches the selector. It synthesizes the key down, char, and key up events that the runes in v need.

See keys for a complete example of how to use SendKeys.

Note: when the element query matches an input[type="file"] node, SendKeys uses dom.SetFileInputFiles to set the upload path of the input node to v.

A "\n" in v is the Enter key. SendKeys sends it as "\r", which is the same as kb.Enter: a keyDown event, a char event with the text "\r", and a keyUp event. An editor that handles Enter on keydown and cancels the default, such as Lexical, can then insert two line breaks, because the char event inserts one more. To send the Enter key with no char event, send a rawKeyDown event and a keyUp event with the command input.DispatchKeyEvent:

enter := chromedp.Func(func(ctx context.Context, t *chromedp.Target) error {
	for _, typ := range []input.DispatchKeyEventType{
		input.DispatchKeyEventTypeRawKeyDown, input.DispatchKeyEventTypeKeyUp,
	} {
		_, err := cdp.Call(ctx, t, input.DispatchKeyEvent, input.DispatchKeyEventParams{
			Type: typ, Key: "Enter", Code: "Enter",
			WindowsVirtualKeyCode: 13, NativeVirtualKeyCode: 13,
		})
		if err != nil {
			return err
		}
	}
	return nil
})
err := chromedp.Do(ctx,
	chromedp.SendKeys(sel, "Hello"),
	enter,
	chromedp.SendKeys(sel, "World"),
)
Example
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`
<body>
<form id="form"><input id="name" name="name"/><input id="color" name="color"/></form>
</body>
	`))
	defer ts.Close()

	if err := chromedp.Do(ctx,
		chromedp.Navigate(ts.URL),
		chromedp.SendKeys(chromedp.ID("name"), "Ada"),
		chromedp.SetValue(chromedp.ID("color"), "green"),
	); err != nil {
		log.Fatal(err)
	}
	name, err := chromedp.Run(ctx, chromedp.Value(chromedp.ID("name")))
	if err != nil {
		log.Fatal(err)
	}
	color, err := chromedp.Run(ctx, chromedp.Value(chromedp.ID("color")))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(name, color)

}
Output:
Ada green

func SetAttributeValue

func SetAttributeValue[S Selectable](sel S, name, value string, opts ...QueryOption) Action[Void]

SetAttributeValue is an element query action that sets the element attribute with name to value for the first element node matching the selector.

func SetAttributes

func SetAttributes[S Selectable](sel S, attributes map[string]string, opts ...QueryOption) Action[Void]

SetAttributes is an element query action that sets the element attributes for the first element node matching the selector.

func SetJavascriptAttribute

func SetJavascriptAttribute[S Selectable](sel S, name, value string, opts ...QueryOption) Action[Void]

SetJavascriptAttribute is an element query action that sets the JavaScript attribute for the first element node matching the selector.

func SetUploadFiles

func SetUploadFiles[S Selectable](sel S, files []string, opts ...QueryOption) Action[Void]

SetUploadFiles is an element query action that sets the files to upload for the first element node matching the selector. The node must be an input[type="file"] node.

func SetValue

func SetValue[S Selectable](sel S, value string, opts ...QueryOption) Action[Void]

SetValue is an element query action that sets the JavaScript value of the first element node matching the selector.

Use it to set the JavaScript value of a form, input, textarea, select, or other element with a '.value' field.

func Sleep

func Sleep(d time.Duration) Action[Void]

Sleep is an action that waits for the duration, or until the context ends.

func Steps added in v0.17.0

func Steps(steps ...Action[Void]) Action[Void]

Steps joins the actions into one action that runs them in order and stops at the first error. It replaces the type Tasks.

func Stop

func Stop() Action[Void]

Stop is an action that stops all navigation and pending resource retrieval.

func Submit

func Submit[S Selectable](sel S, opts ...QueryOption) Action[Void]

Submit is an element query action that submits the parent form of the first element node matching the selector.

func Tap added in v0.19.0

func Tap[S Selectable](sel S, opts ...QueryOption) Action[Void]

Tap is an element query action that sends a touch tap to the center of the first element node matching the selector. The action scrolls the node into view, and then sends a touchStart event and a touchEnd event. See TapXY.

The browser sends the touch events and the click event to the page only when touch emulation is on. Use EmulateViewport with EmulateTouch for it.

func TapXY added in v0.19.0

func TapXY(x, y float64) Action[Void]

TapXY is an action that sends a touch tap to the X, Y location. It sends a touchStart event and then a touchEnd event with one touch point. The browser turns the touch into a click event, if the page runs with touch emulation. See EmulateTouch.

func Text

func Text[S Selectable](sel S, opts ...QueryOption) Action[string]

Text is an element query action that retrieves the visible text of the first element node matching the selector.

func TextContent added in v0.4.1

func TextContent[S Selectable](sel S, opts ...QueryOption) Action[string]

TextContent is an element query action that retrieves the text content of the first element node matching the selector.

func Title

func Title() Action[string]

Title is an action that retrieves the document title.

Example
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`
<head>
	<title>fancy website title</title>
</head>
<body>
	<div id="content"></div>
</body>
	`))
	defer ts.Close()

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	title, err := chromedp.Run(ctx, chromedp.Title())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(title)

}
Output:
fancy website title

func Value

func Value[S Selectable](sel S, opts ...QueryOption) Action[string]

Value is an element query action that retrieves the JavaScript value field of the first element node matching the selector.

Use it to read the JavaScript value of a form, input, textarea, select, or other element with a '.value' field.

Value follows JavascriptAttribute. An element without a '.value' field gives an error that wraps ErrJSUndefined.

func WaitEnabled

func WaitEnabled[S Selectable](sel S, opts ...QueryOption) Action[Void]

WaitEnabled is an element query action that waits until the element that matches the selector is enabled (that is, it has no attribute 'disabled').

func WaitEvent added in v0.17.0

func WaitEvent[E, T any](ev cdp.Event[E], match func(E) bool, trigger Action[T]) Action[E]

WaitEvent makes an action that waits for an event. It subscribes to the event, runs the trigger action, and then returns the first payload for which match returns true. A nil match accepts every payload. The trigger runs after the subscription, so the event cannot arrive too early.

For example, to wait for the load event that a click causes:

_, err := chromedp.Run(ctx, chromedp.WaitEvent(page.LoadEventFired, nil,
	chromedp.Click(chromedp.CSS("a"))))

When the context ends before a matching event arrives, WaitEvent returns the error of the context.

func WaitNotPresent

func WaitNotPresent[S Selectable](sel S, opts ...QueryOption) Action[Void]

WaitNotPresent is an element query action that waits until no element that matches the selector is present.

func WaitNotVisible

func WaitNotVisible[S Selectable](sel S, opts ...QueryOption) Action[Void]

WaitNotVisible is an element query action that waits until the element matching the selector is not visible.

func WaitReady

func WaitReady[S Selectable](sel S, opts ...QueryOption) Action[Void]

WaitReady is an element query action that waits until the element that matches the selector is ready (that is, "loaded").

func WaitSelected

func WaitSelected[S Selectable](sel S, opts ...QueryOption) Action[Void]

WaitSelected is an element query action that waits until the element that matches the selector is selected (that is, it has the attribute 'selected').

func WaitVisible

func WaitVisible[S Selectable](sel S, opts ...QueryOption) Action[Void]

WaitVisible is an element query action that waits until the element matching the selector is visible.

type Allocator added in v0.2.0

type Allocator interface {
	// Allocate creates a new browser. Canceling the provided context frees all
	// resources of the browser, such as temporary directories.
	Allocate(context.Context, ...BrowserOption) (*Browser, error)

	// Wait blocks until the allocator has freed all of its resources.
	// Canceling the allocator context does this too, so normally you do not
	// need to call Wait.
	Wait()
}

An Allocator creates and manages a number of browsers.

This interface hides how the browser process runs. For example, an Allocator can reuse browser processes, or connect to browsers that already run on remote machines.

type Attacher added in v0.18.0

type Attacher interface {
	// Attaches reports whether the allocator attaches to a browser that
	// runs already.
	Attaches() bool
}

An Attacher is an optional interface of an Allocator. An allocator that implements it connects to a browser that already runs, and it does not start the browser itself. NewContext then treats the context of such an allocator as a new tab of that browser, and not as the owner of a browser process. The allocator of the package github.com/chromedp/chromedp/remote implements it.

type AttributeResult added in v0.17.0

type AttributeResult struct {
	// Value is the value of the attribute. It is empty when the attribute
	// does not exist.
	Value string

	// Exists is true when the element has the attribute.
	Exists bool
}

AttributeResult is the result of the AttributeValue action.

type Browser added in v0.2.0

type Browser struct {

	// LostConnection is closed when the connection to Chrome drops. The
	// connection is a pipe or a websocket.
	// Use it to make sure that the context of the Browser is canceled (and the
	// handler stopped) after the connection fails.
	LostConnection chan struct{}
	// contains filtered or unexported fields
}

Browser manages a browser through the Chrome DevTools Protocol. It handles the browser process runner, the connection to the browser, the targets, and the network, page, and DOM events. The connection is a pipe or a websocket.

func NewBrowserTransport added in v0.17.0

func NewBrowserTransport(ctx context.Context, tr Transport, opts ...BrowserOption) (*Browser, error)

NewBrowserTransport creates a new browser that uses tr, a connection to a browser that is already open, such as a *PipeConn. The browser closes tr when it stops. Typically you do not call it directly, because the Allocator interface does it.

func (*Browser) Call added in v0.17.0

func (b *Browser) Call(ctx context.Context, method string, params, res any) error

Call sends the command to the browser, waits for the response, and decodes the result into res. It satisfies cdp.Session.

Call returns a browser error as a *cdproto.Error. It returns an error when the connection to the browser is lost, also when ctx never ends. The error wraps the reason of the loss and context.Canceled.

func (*Browser) Process added in v0.7.2

func (b *Browser) Process() *os.Process

Process returns the process object of the browser.

It is nil when the browser was allocated by an allocator that attaches to a browser that runs already, such as the allocator of the remote package. A monitoring system can use it to collect process metrics of the browser process (see prometheus.NewProcessCollector for an example).

Example:

if process := chromedp.FromContext(ctx).Browser.Process(); process != nil {
	fmt.Printf("Browser PID: %v", process.Pid)
}

func (*Browser) Subscribe added in v0.17.0

func (b *Browser) Subscribe(method string) (<-chan jsonv2.Value, func())

Subscribe starts to buffer the browser events with the method, and returns the channel that the raw event parameters arrive on. It satisfies cdp.Session.

type BrowserOption added in v0.2.0

type BrowserOption = func(*Browser)

BrowserOption is a browser option.

func WithBrowserDebugf added in v0.2.0

func WithBrowserDebugf(f func(string, ...any)) BrowserOption

WithBrowserDebugf is a browser option that sets the func that receives the protocol messages.

func WithBrowserErrorf added in v0.2.0

func WithBrowserErrorf(f func(string, ...any)) BrowserOption

WithBrowserErrorf is a browser option that sets the func that receives error messages.

func WithBrowserLogf added in v0.2.0

func WithBrowserLogf(f func(string, ...any)) BrowserOption

WithBrowserLogf is a browser option that sets the func that receives general log messages.

func WithConsolef

func WithConsolef(f func(string, ...any)) BrowserOption

WithConsolef is a browser option that sets the func that receives chrome log events.

Note: it is not implemented yet.

type CSS added in v0.17.0

type CSS string

CSS is a selector for the first element that matches a CSS selector. It uses DOM.querySelector.

type CSSAll added in v0.17.0

type CSSAll string

CSSAll is a selector for every element that matches a CSS selector. It uses DOM.querySelectorAll.

type CallOption added in v0.7.4

type CallOption = func(params *runtime.CallFunctionOnParams)

CallOption is a func that changes the runtime.CallFunctionOnParams of a call.

type ConsoleMessage added in v0.19.0

type ConsoleMessage struct {
	// Type is the kind of the message. An uncaught exception and an unhandled
	// promise rejection have the type [ConsoleException]. An entry of the browser
	// log has the type "debug", "info", "warning" or "error", for the levels
	// verbose, info, warning and error.
	Type ConsoleType

	// Text is the text that the DevTools console shows. A string argument is
	// there as it is, and another value has its description or a short form of
	// its properties. A format such as %s and %d in the first argument takes the
	// arguments that follow it. For an exception, the text is the error and its
	// message, and the stack is in Stack.
	Text string

	// Args are the arguments of the call to the console API, as the protocol
	// reports them. The objects have no value, only a description and a
	// preview. Use [runtime.GetProperties] with the object id to read one. Args
	// is empty for an exception and for an entry of the browser log.
	Args []*runtime.RemoteObject

	// Time is the time of the message, as the browser reports it.
	Time time.Time

	// URL, Line and Column tell where the message came from. A call of the
	// console API has the place of the call. An exception has the place of the
	// throw. They can be empty. The line and the column start at 0, as in the
	// protocol.
	URL    string
	Line   int64
	Column int64

	// Stack is the stack trace of the call or of the exception. It is nil when
	// the browser reports none.
	Stack *runtime.StackTrace

	// Exception holds the details of an exception, and it is nil for another
	// message.
	Exception *runtime.ExceptionDetails

	// Source tells which part of the browser wrote a message of the browser
	// log, for example "network" or "security". It is empty for a call of the
	// console API and for an exception.
	Source string
}

ConsoleMessage is a message that the page wrote to the console. It is a call of the console API, an exception that nothing caught, or an entry of the browser log.

func (ConsoleMessage) IsException added in v0.19.0

func (m ConsoleMessage) IsException() bool

IsException reports whether the message is an uncaught exception or an unhandled promise rejection.

func (ConsoleMessage) String added in v0.19.0

func (m ConsoleMessage) String() string

String returns the type and the text of the message.

type ConsoleType added in v0.19.0

type ConsoleType string

ConsoleType is the kind of a ConsoleMessage. The values for a call of the console API are the names of the protocol, such as "log", "warning" and "error". The package defines a constant for the common ones.

const (
	ConsoleLog       ConsoleType = "log"
	ConsoleDebug     ConsoleType = "debug"
	ConsoleInfo      ConsoleType = "info"
	ConsoleWarning   ConsoleType = "warning"
	ConsoleError     ConsoleType = "error"
	ConsoleException ConsoleType = "exception"
)

Console message types.

type Context added in v0.2.0

type Context struct {
	// Allocator creates new browsers. A child context inherits it from the
	// parent context.
	Allocator Allocator

	// Browser is the browser of the context. A child context inherits it from
	// the parent context.
	Browser *Browser

	// Target is the target that actions run against. A child context does not
	// inherit it. Typically each context has its own Target, which points to a
	// separate browser tab (page).
	Target *Target

	// BrowserContextID is set by WithExistingBrowserContext.
	//
	// Otherwise, BrowserContextID is not empty in these cases:
	//
	// 1. The context was made with WithNewBrowserContext. Its first run creates
	// a new BrowserContext, and BrowserContextID holds the id of that
	// BrowserContext.
	//
	// 2. The context was not made with WithTargetID, and the parent context
	// has a BrowserContextID that is not empty. The context copies it from the
	// parent context.
	BrowserContextID cdp.BrowserContextID
	// contains filtered or unexported fields
}

Context is the data that NewContext stores in a context.Context. Run needs it.

func FromContext added in v0.2.0

func FromContext(ctx context.Context) *Context

FromContext returns the Context that a context.Context holds, or nil.

type ContextOption added in v0.2.0

type ContextOption = func(*Context)

ContextOption is a context option.

func WithAllocatorOptions added in v0.18.0

func WithAllocatorOptions(opts ...ExecAllocatorOption) ContextOption

WithAllocatorOptions makes NewContext add opts to the options of the default allocator, after DefaultExecAllocatorOptions and after VisibleWindow. The package github.com/chromedp/chromedp/remote uses it for its own WithKeepOpen.

The option only applies when the parent context has no allocator. It has no effect on an allocator that the caller made, and it has no effect on a context that inherits a browser. For an allocator that you make, add the options to NewExecAllocator instead.

func WithBrowserOption added in v0.2.0

func WithBrowserOption(opts ...BrowserOption) ContextOption

WithBrowserOption passes browser options to the allocator when it allocates a new browser. As a result, you can use this option only when the context allocates a new browser.

func WithDebugf

func WithDebugf(f func(string, ...any)) ContextOption

WithDebugf is a shortcut for WithBrowserOption(WithBrowserDebugf(f)).

func WithDetachOnCancel added in v0.19.0

func WithDetachOnCancel() ContextOption

WithDetachOnCancel makes the cancellation of the context detach from its tab and leave the tab open. By default, the cancellation closes the tab that the context created or attached to with WithTargetID, and it disposes of a BrowserContext that WithNewBrowserContext made.

Use it with a remote browser that keeps its tabs when a client leaves, so that a later client can attach to the tab again with WithTargetID. Read the ID of the tab from the Target field of FromContext after the first Run. With this option, the context also keeps a BrowserContext that it owns, because disposing of it closes the tab. It creates that BrowserContext without the setting disposeOnDetach. The program must dispose of it with the command target.DisposeBrowserContext when it no longer needs it.

The option has no effect on the first context of a browser that the exec allocator starts, because the cancellation stops that browser. It is not inherited by a child context.

func WithErrorf

func WithErrorf(f func(string, ...any)) ContextOption

WithErrorf is a shortcut for WithBrowserOption(WithBrowserErrorf(f)).

func WithExistingBrowserContext added in v0.8.8

func WithExistingBrowserContext(id cdp.BrowserContextID) ContextOption

WithExistingBrowserContext makes a context create a new target in the given BrowserContext.

func WithLogf

func WithLogf(f func(string, ...any)) ContextOption

WithLogf is a shortcut for WithBrowserOption(WithBrowserLogf(f)).

func WithNewBrowserContext added in v0.8.8

func WithNewBrowserContext(options ...CreateBrowserContextOption) ContextOption

WithNewBrowserContext makes a context create a new BrowserContext and a new target in it. A child context creates its target in this BrowserContext too, unless another option applies. The context disposes the new BrowserContext when the context is done.

func WithNewWindow added in v0.18.0

func WithNewWindow(newWindow bool) ContextOption

WithNewWindow chooses where a new tab opens. By default, the first Run of a context that creates a tab opens it in a new window, so that each tab is visible and gets animation frames. WithNewWindow(false) opens the tab in the window of the browser, as a real tab. A child context inherits the choice.

Chrome hides every tab of a window except the active one, and a hidden page gets no animation frames. So an action that waits for a frame, such as Poll and the actions that use it, can wait for ever on a tab that is not active. Make a tab active with the command target.ActivateTarget, or with page.BringToFront in the tab, before you run such an action on it.

WithNewWindow has no effect on the first context of a browser, which uses the tab that the browser opens, or on a context that attaches to an existing target with WithTargetID.

func WithTargetID added in v0.3.0

func WithTargetID(id target.ID) ContextOption

WithTargetID makes a context attach to an existing target, and not create a new one.

It also works for an iframe from another site (a cross-site iframe). Chrome runs such an iframe in its own process, and lists it as a target of the type "iframe" in Targets. FromNode and the DOM tree of the page do not reach it, and the network events of the iframe do not arrive in the context of the page, because chromedp does not attach to the iframe by itself. A context that WithTargetID attaches to the iframe runs actions in the iframe and gets its events. The parent context must have run already, so that it has a browser. For example:

infos, _ := chromedp.Targets(ctx)
for _, info := range infos {
	if info.Type == "iframe" && strings.HasPrefix(info.URL, "https://other.example/") {
		frameCtx, cancel := chromedp.NewContext(ctx, chromedp.WithTargetID(info.TargetID))
		defer cancel()
		text, err := chromedp.Run(frameCtx, chromedp.Text(chromedp.CSS("#inner")))
	}
}

The other way is to turn off site isolation in the browser. Give the exec allocator Flag("disable-features", "SitePerProcess,IsolateOrigins") and Flag("disable-site-isolation-trials", true). The iframe then stays in the page process, and FromNode and the events of the page reach it. This turns off a security feature of Chrome. See docs/decisions/2026-10-04-keep-site-isolation-on.md.

func WithVisibleWindow added in v0.17.0

func WithVisibleWindow() ContextOption

WithVisibleWindow makes NewContext build the default allocator with VisibleWindow and without Headless, so that the browser opens a visible window. The window stays open until the context ends. See also KeepOpen and WaitClosed.

The environment variable CHROMEDP_VISIBLEWINDOW has the same effect with no change in the code. Any value other than the empty string, "false" and "0" turns it on.

The option only applies when the parent context has no allocator, because then NewContext builds the allocator. It has no effect on an allocator that the caller made, and it has no effect on a context that inherits a browser. For an allocator that you make, add VisibleWindow to the options of NewExecAllocator instead.

On Linux, the first Run returns ErrNoDisplay when the environment has no display.

Example

This example opens a visible window and waits until the user closes it. The variable CHROMEDP_VISIBLEWINDOW=1 has the same effect as the option.

package main

import (
	"context"
	"log"

	"github.com/chromedp/chromedp"
)

func main() {
	ctx, cancel := chromedp.NewContext(context.Background(), chromedp.WithVisibleWindow())
	defer cancel()

	if err := chromedp.Do(ctx, chromedp.Navigate("https://example.com")); err != nil {
		log.Fatal(err)
	}
	// Block until the user closes the window.
	chromedp.WaitClosed(ctx)
}

type CreateBrowserContextOption added in v0.8.8

type CreateBrowserContextOption = func(*target.CreateBrowserContextParams)

CreateBrowserContextOption is an option for the creation of a BrowserContext.

type Device added in v0.4.0

type Device interface {
	// Device returns the device info.
	Device() device.Info
}

Device is the shared interface for known device types.

See device for a set of ready-made devices and modes.

type Dialer added in v0.18.0

type Dialer = func(ctx context.Context, wsURL string) (Transport, error)

A Dialer connects to the websocket address of a browser and returns the connection as a Transport. The package github.com/chromedp/chromedp/remote has a Dialer. See WithDialer.

type EmulateViewportOption added in v0.4.0

EmulateViewportOption is the type for emulate viewport options.

func EmulateOrientation added in v0.4.0

func EmulateOrientation(orientation emulation.ScreenOrientationType, angle int64) EmulateViewportOption

EmulateOrientation is an emulate viewport option to set the device viewport screen orientation.

func EmulateScale added in v0.4.0

func EmulateScale(scale float64) EmulateViewportOption

EmulateScale is an emulate viewport option to set the device viewport scaling factor.

type Error

type Error string

Error is a chromedp error.

const (
	// ErrNoDialer is the error of an ExecAllocator that needs a websocket and
	// has no dialer. See [WithDialer].
	ErrNoDialer Error = "" /* 143-byte string literal not displayed */

	// ErrInvalidDimensions is the invalid dimensions error.
	ErrInvalidDimensions Error = "invalid dimensions"

	// ErrNoResults is the no results error.
	ErrNoResults Error = "no results"

	// ErrHasResults is the has results error.
	ErrHasResults Error = "has results"

	// ErrNotVisible is the not visible error.
	ErrNotVisible Error = "not visible"

	// ErrVisible is the visible error.
	ErrVisible Error = "visible"

	// ErrDisabled is the disabled error.
	ErrDisabled Error = "disabled"

	// ErrNotSelected is the not selected error.
	ErrNotSelected Error = "not selected"

	// ErrInvalidBoxModel is the invalid box model error.
	ErrInvalidBoxModel Error = "invalid box model"

	// ErrChannelClosed is the channel closed error.
	ErrChannelClosed Error = "channel closed"

	// ErrInvalidTarget is the invalid target error.
	ErrInvalidTarget Error = "invalid target"

	// ErrPageLoad is the error that every [LoadError] wraps.
	ErrPageLoad Error = "page load error"

	// ErrNoDisplay is the error when a visible window is requested on Linux
	// and the environment has no display.
	ErrNoDisplay Error = "" /* 190-byte string literal not displayed */

	// ErrInvalidContext is the invalid context error.
	ErrInvalidContext Error = "invalid context"

	// ErrPollingTimeout is the error when the timeout ends before the pageFunction returns a truthy value.
	ErrPollingTimeout Error = "waiting for function failed: timeout"

	// ErrJSUndefined is the error that the type of RemoteObject is "undefined".
	ErrJSUndefined Error = "encountered an undefined value"

	// ErrJSNull is the error that the value of RemoteObject is null.
	ErrJSNull Error = "encountered a null value"
)

Error types.

const ErrDragOutsideViewport Error = "the nodes of the drag are not in the viewport at the same time"

ErrDragOutsideViewport is the error of DragAndDrop when the two nodes do not fit in the viewport at the same time. The action does not scroll while it drags, so a drag between two such nodes does nothing.

func (Error) Error

func (err Error) Error() string

Error satisfies the error interface.

type EvaluateOption

type EvaluateOption = func(*runtime.EvaluateParams)

EvaluateOption is the type for JavaScript evaluation options.

func EvalObjectGroup

func EvalObjectGroup(objectGroup string) EvaluateOption

EvalObjectGroup is an evaluate option to set the object group.

type ExceptionError added in v0.17.0

type ExceptionError struct {
	*runtime.ExceptionDetails
}

ExceptionError is the error for a JavaScript exception. It wraps the protocol details of the exception.

func (*ExceptionError) Error added in v0.17.0

func (e *ExceptionError) Error() string

Error satisfies the error interface.

type ExecAllocator added in v0.2.0

type ExecAllocator struct {
	// contains filtered or unexported fields
}

ExecAllocator is an Allocator which starts new browser processes on the host machine.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/chromedp/chromedp"
)

func main() {
	dir, err := os.MkdirTemp("", "chromedp-example")
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		// The child processes of Chrome can still write in the directory for
		// a short time after the browser stops. Then RemoveAll fails with
		// "directory not empty", so try again.
		for range 50 {
			if err := os.RemoveAll(dir); err == nil {
				return
			}
			time.Sleep(100 * time.Millisecond)
		}
	}()

	opts := append(chromedp.DefaultExecAllocatorOptions[:],
		chromedp.DisableGPU,
		chromedp.UserDataDir(dir),
	)

	allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
	defer cancel()

	// also set up a custom logger
	taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
	defer cancel()

	sum, err := chromedp.Run(taskCtx, chromedp.Evaluate[int](`1 + 2`))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(sum)

}
Output:
3

func (*ExecAllocator) Allocate added in v0.2.0

func (a *ExecAllocator) Allocate(ctx context.Context, opts ...BrowserOption) (*Browser, error)

Allocate satisfies the Allocator interface. It returns ErrNoDialer when the allocator needs a websocket and has no dialer.

func (*ExecAllocator) Wait added in v0.2.0

func (a *ExecAllocator) Wait()

Wait satisfies the Allocator interface.

type ExecAllocatorOption added in v0.2.0

type ExecAllocatorOption = func(*ExecAllocator)

ExecAllocatorOption is an exec allocator option.

func CombinedOutput added in v0.4.0

func CombinedOutput(w io.Writer) ExecAllocatorOption

CombinedOutput sets the io.Writer that receives the stdout and stderr of the browser.

func Env added in v0.4.1

func Env(vars ...string) ExecAllocatorOption

Env sets environment variables, in the form NAME=value, for the new Chrome process. They add to the environment of the Go process, which os.Environ returns. To start the browser with only these variables, add NoInheritEnv.

func ExecPath added in v0.2.0

func ExecPath(path string) ExecAllocatorOption

ExecPath returns an ExecAllocatorOption that uses the given path to run browser processes. The path can be an absolute path to a binary, or the name of a program that exec.LookPath finds.

func Flag added in v0.2.0

func Flag(name string, value any) ExecAllocatorOption

Flag is a generic command line option that passes a flag to Chrome. If the value is a string, Flag passes --name=value. If it is a boolean, Flag passes --name when the value is true.

The flags go to Chrome in the order of the options. Set a flag again, and it keeps its first place with the new value. This order matters for the flags --flag-switches-begin and --flag-switches-end, which must surround the switches that Chrome takes as the switches of chrome://flags. When you add to a copy of DefaultExecAllocatorOptions, the default flags come first.

func ModifyCmdFunc added in v0.7.3

func ModifyCmdFunc(f func(cmd *exec.Cmd)) ExecAllocatorOption

ModifyCmdFunc runs a func on the exec.Cmd of the browser. It replaces the default func, which sends SIGKILL to any open browsers when the Go program exits.

func ProxyServer added in v0.2.0

func ProxyServer(proxy string) ExecAllocatorOption

ProxyServer is the command line option to set the outbound proxy server.

func UserAgent added in v0.2.0

func UserAgent(userAgent string) ExecAllocatorOption

UserAgent is the command line option to set the default User-Agent header.

func UserDataDir added in v0.2.0

func UserDataDir(dir string) ExecAllocatorOption

UserDataDir is the command line option to set the user data directory. Use it to choose the profile directory of Chrome. Without it, ExecAllocator creates a default path in the /tmp directory.

func WSURLReadTimeout added in v0.8.4

func WSURLReadTimeout(t time.Duration) ExecAllocatorOption

WSURLReadTimeout sets how long ExecAllocator waits to read the WebSocket URL. The default is 20 seconds. It only applies to the websocket mode, see WithDialer.

func WindowSize added in v0.2.0

func WindowSize(width, height int) ExecAllocatorOption

WindowSize is the command line option to set the initial window size.

func WithDialer added in v0.18.0

func WithDialer(d Dialer) ExecAllocatorOption

WithDialer is an ExecAllocatorOption that makes the allocator connect to the browser with a websocket, as chromedp did before the pipe became the default. The allocator starts the browser with a debugging port, reads the websocket address, and calls d to connect to it.

The core module has no websocket code, so it needs a dialer. The function WebSocket of the package github.com/chromedp/chromedp/remote makes the ExecAllocatorOption that sets one. Use a dialer when the browser must open a debugging port, for example to let a second program connect to it. The Flag options "remote-debugging-port" and "remote-debugging-address" also need a dialer.

type Frame added in v0.17.0

type Frame struct {
	*cdp.Frame

	// State is the state of the frame.
	State FrameState
	// Root is the document root of the frame.
	Root *Node
	// Nodes holds the nodes of the frame by node id.
	Nodes map[cdp.NodeID]*Node

	sync.RWMutex
}

Frame is a frame of a page. It embeds the protocol frame and adds the node tree of the frame and the state that chromedp keeps up to date from the browser events.

Hold the lock of a Frame before you read a field that chromedp updates.

type FrameState added in v0.17.0

type FrameState uint16

FrameState is the state of a Frame.

const (
	FrameDOMContentEventFired FrameState = 1 << (15 - iota)
	FrameLoadEventFired
	FrameAttached
	FrameNavigated
	FrameLoading
	FrameScheduledNavigation
)

FrameState enum values.

func (FrameState) String added in v0.17.0

func (fs FrameState) String() string

String satisfies stringer interface.

type ID added in v0.17.0

type ID string

ID is a selector for the element with this id. A leading "#" is optional. It uses DOM.querySelector.

type JSPath added in v0.17.0

type JSPath string

JSPath is a selector for the elements that a JavaScript expression gives. It uses Runtime.evaluate. Use it only with trusted values, because chromedp passes the expression to the browser without a check.

Example
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/cdproto/dom"
	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`
<body>
	<div id="content">cool content</div>
</body>
	`))
	defer ts.Close()

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	ids, err := chromedp.Run(ctx, chromedp.QueryNodeIDs(chromedp.JSPath(`document`)))
	if err != nil {
		log.Fatal(err)
	}
	res, err := chromedp.Call(ctx, dom.GetOuterHTML, dom.GetOuterHTMLParams{NodeID: ids[0]})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Outer HTML:")
	fmt.Println(res.OuterHTML)

}
Output:
Outer HTML:
<html><head></head><body>
	<div id="content">cool content</div>
</body></html>

type KeyOption

type KeyOption = func(*input.DispatchKeyEventParams)

KeyOption is a key action option.

func KeyModifiers

func KeyModifiers(modifiers ...Modifier) KeyOption

KeyModifiers is a key action option to add modifiers to the key press.

type LoadError added in v0.18.0

type LoadError struct {
	// ErrorText is the error text of the browser, such as
	// "net::ERR_NAME_NOT_RESOLVED". Chromium lists these texts in
	// net/base/net_error_list.h.
	ErrorText string
}

LoadError is the error for a page that did not load. Navigate and RunResponse return it when the browser reports an error for the request of the page, for example when the host name does not exist. Use errors.As to read the text of the browser, or errors.Is with ErrPageLoad to test for any load error.

func (*LoadError) Error added in v0.18.0

func (e *LoadError) Error() string

Error satisfies the error interface. The text is the same as in earlier versions.

func (*LoadError) Unwrap added in v0.18.0

func (e *LoadError) Unwrap() error

Unwrap returns ErrPageLoad, so that errors.Is finds it.

type Modifier added in v0.17.0

type Modifier = kb.Modifier

Modifier is a bit field of pressed modifier keys.

type MouseOption

type MouseOption = func(*input.DispatchMouseEventParams)

MouseOption is a mouse action option.

func Button

func Button(btn string) MouseOption

Button is a mouse action option to set the button to click from a string.

func ButtonModifiers

func ButtonModifiers(modifiers ...Modifier) MouseOption

ButtonModifiers is a mouse action option to add input modifiers for a button click.

func ButtonType

func ButtonType(button input.MouseButton) MouseOption

ButtonType is a mouse action option to set the button to click.

func ClickCount

func ClickCount(n int) MouseOption

ClickCount is a mouse action option to set the click count.

type Node added in v0.17.0

type Node struct {
	*cdp.Node

	// Parent is the parent node.
	Parent *Node
	// Children shadows the Children field of the protocol node.
	Children []*Node
	// ContentDocument shadows the ContentDocument field of the protocol node.
	ContentDocument *Node
	// ShadowRoots shadows the ShadowRoots field of the protocol node.
	ShadowRoots []*Node
	// TemplateContent shadows the TemplateContent field of the protocol node.
	TemplateContent *Node
	// PseudoElements shadows the PseudoElements field of the protocol node.
	PseudoElements []*Node

	// Invalidated is closed when the node is no longer valid.
	Invalidated chan struct{}
	// State is the state of the node.
	State NodeState

	sync.RWMutex
}

Node is a DOM node in the node tree of a frame. It embeds the protocol node and adds the tree links and the state that chromedp keeps up to date from the browser events.

Hold the lock of a Node before you read a field of the tree.

func (*Node) Attribute added in v0.17.0

func (n *Node) Attribute(name string) (string, bool)

Attribute returns the named attribute for the node and if it exists.

func (*Node) AttributeValue added in v0.17.0

func (n *Node) AttributeValue(name string) string

AttributeValue returns the named attribute for the node.

func (*Node) Dump added in v0.17.0

func (n *Node) Dump(prefix, indent string, nodeIDs bool) string

Dump builds a printable string representation of the node and its children.

func (*Node) FullXPath added in v0.17.0

func (n *Node) FullXPath() string

FullXPath returns the full XPath for the node. It stops only at the top most document root.

func (*Node) FullXPathByID added in v0.17.0

func (n *Node) FullXPathByID() string

FullXPathByID returns the full XPath for the node. It stops at the top most document root or at the closest parent node with an id attribute.

func (*Node) PartialXPath added in v0.17.0

func (n *Node) PartialXPath() string

PartialXPath returns the partial XPath for the node. It stops at the nearest parent document node.

func (*Node) PartialXPathByID added in v0.17.0

func (n *Node) PartialXPathByID() string

PartialXPathByID returns the partial XPath for the node. It stops at the first parent with an id attribute or at the nearest parent document node.

func (*Node) WriteTo added in v0.17.0

func (n *Node) WriteTo(w io.Writer, prefix, indent string, nodeIDs bool) (int, error)

WriteTo writes a readable representation of the node and all its children to w.

type NodeIDs

type NodeIDs []cdp.NodeID

NodeIDs is a selector for the elements with these node IDs.

type NodeState added in v0.17.0

type NodeState uint8

NodeState is the state of a DOM node.

const (
	NodeStateReady NodeState = 1 << (7 - iota)
	NodeStateVisible
	NodeStateHighlighted
)

NodeState enum values.

func (NodeState) String added in v0.17.0

func (ns NodeState) String() string

String satisfies stringer interface.

type NodeType added in v0.17.0

type NodeType int64

NodeType is the type of a DOM node. It is the value of the NodeType field of the protocol node.

func (NodeType) String added in v0.17.0

func (t NodeType) String() string

String returns the name of the node type.

type OldAction added in v0.17.0

type OldAction interface {
	// Do runs the action. The context holds the chromedp context.
	Do(context.Context) error
}

OldAction is the interface of an action of the previous version of chromedp. The previous version named it Action.

type PDFOption added in v0.19.0

type PDFOption = func(*page.PrintToPDFParams)

PDFOption is an option of PrintToPDF. It changes the parameters of the protocol command page.PrintToPDF.

func PDFFooterTemplate added in v0.19.0

func PDFFooterTemplate(html string) PDFOption

PDFFooterTemplate is like PDFHeaderTemplate for the footer.

func PDFHeaderTemplate added in v0.19.0

func PDFHeaderTemplate(html string) PDFOption

PDFHeaderTemplate is an option of PrintToPDF that sets the HTML of the header, and turns on the header and the footer. The template can use these classes, and the browser puts the value in an element that has one: date, title, url, pageNumber and totalPages. The font size of the browser for a header is 0, so the template must set one. The header and the footer use the page margins, so a margin that is too small hides them.

When you give only a header, the browser prints its own footer. Give PDFFooterTemplate with `<span></span>` to print no footer.

func PDFLandscape added in v0.19.0

func PDFLandscape() PDFOption

PDFLandscape is an option of PrintToPDF that prints in landscape. The width and the height of the paper swap.

func PDFMargin added in v0.19.0

func PDFMargin(inches float64) PDFOption

PDFMargin is an option of PrintToPDF that sets the four margins to the same length in inches. The default is 1 cm, which is about 0.4 inches. A margin of 0 is valid.

func PDFMargins added in v0.19.0

func PDFMargins(top, right, bottom, left float64) PDFOption

PDFMargins is an option of PrintToPDF that sets the margins in inches. The order is the same as in CSS: top, right, bottom and left.

func PDFOutlineAndTagged added in v0.19.0

func PDFOutlineAndTagged() PDFOption

PDFOutlineAndTagged is an option of PrintToPDF that adds the outline of the document, which is a table of contents that a PDF viewer shows for the headings, and that makes a tagged PDF, which holds the structure of the document for a screen reader. Chrome 154 and later make a tagged PDF by default, so with them the option adds the outline.

func PDFPageRanges added in v0.19.0

func PDFPageRanges(ranges string) PDFOption

PDFPageRanges is an option of PrintToPDF that selects the pages to print, for example "1-3, 5". The numbers start at 1. The default is all pages.

func PDFPaper added in v0.19.0

func PDFPaper(size PaperSize) PDFOption

PDFPaper is an option of PrintToPDF that sets the size of the paper. Give one of the sizes of the package, such as PaperA4, or a PaperSize of your own. The default is PaperLetter. A zero width or height gives the default for that side, so PDFPaper(PaperSize{}) changes nothing. The size is for portrait, and PDFLandscape swaps it.

func PDFPreferCSSPageSize added in v0.19.0

func PDFPreferCSSPageSize() PDFOption

PDFPreferCSSPageSize is an option of PrintToPDF that uses the page size of the CSS rule @page, when the page has one. Otherwise the browser scales the content to fit the paper.

func PDFPrintBackground added in v0.19.0

func PDFPrintBackground() PDFOption

PDFPrintBackground is an option of PrintToPDF that prints the background colors and images. By default, the browser leaves them out.

func PDFScale added in v0.19.0

func PDFScale(scale float64) PDFOption

PDFScale is an option of PrintToPDF that sets the scale of the page. The default is 1, and 0 gives the default, so PDFScale(0) changes nothing. The browser accepts 0.1 to 2.

func PDFStream added in v0.19.0

func PDFStream() PDFOption

PDFStream is an option of PrintToPDF that makes the browser send the file as a stream that the action reads in pieces, and not in one message. Use it for a large file. The result is the same.

type PaperSize added in v0.19.0

type PaperSize struct {
	Width, Height float64
}

PaperSize is the size of a sheet of paper in inches. Use it with PDFPaper. A field that is 0 gives the default of the browser for that field, so PaperSize{Width: 5} is 5 inches wide and 11 inches high, and the zero value is Letter paper.

type PipeConn added in v0.17.0

type PipeConn struct {
	// contains filtered or unexported fields
}

PipeConn implements Transport with the two pipes of a browser that was started with the --remote-debugging-pipe flag.

On Unix, the browser reads the commands from its file descriptor 3 and writes the responses and the events to its file descriptor 4. On Windows, it uses two handles. Each JSON message ends with one zero byte, in both directions.

func NewPipeConn added in v0.17.0

func NewPipeConn(r io.ReadCloser, w io.WriteCloser, opts ...PipeOption) *PipeConn

NewPipeConn returns a Transport that reads the messages of the browser from r and writes the messages for the browser to w. Close closes both r and w.

func (*PipeConn) Close added in v0.17.0

func (c *PipeConn) Close() error

Close satisfies the io.Closer interface. It closes both ends of the pipe, which makes the browser exit.

func (*PipeConn) Read added in v0.17.0

func (c *PipeConn) Read(_ context.Context, msg *cdproto.Message) error

Read reads the next message. It returns io.EOF when the browser closes its end of the pipe.

func (*PipeConn) SetDebugf added in v0.18.0

func (c *PipeConn) SetDebugf(f func(string, ...any))

SetDebugf sets the protocol logger. NewBrowserTransport calls it with the logger of the browser.

func (*PipeConn) Write added in v0.17.0

func (c *PipeConn) Write(_ context.Context, msg *cdproto.Message) error

Write writes a message. It is safe to call from more than one goroutine.

type PipeOption added in v0.17.0

type PipeOption = func(*PipeConn)

PipeOption is an option of NewPipeConn.

func WithPipeDebugf added in v0.17.0

func WithPipeDebugf(f func(string, ...any)) PipeOption

WithPipeDebugf is a pipe option to set a protocol logger.

type PollOption added in v0.6.11

type PollOption = func(task *pollTask)

PollOption is a poll task option.

func WithPollingArgs added in v0.6.11

func WithPollingArgs(args ...any) PollOption

WithPollingArgs provides extra arguments to pass to the predicate.

func WithPollingInFrame added in v0.6.11

func WithPollingInFrame(frame *Node) PollOption

WithPollingInFrame sets the frame in which to evaluate the predicate. Without it, the action evaluates the predicate in the root page of the current tab.

func WithPollingInterval added in v0.6.11

func WithPollingInterval(interval time.Duration) PollOption

WithPollingInterval polls the predicate at the given interval.

func WithPollingMutation added in v0.6.11

func WithPollingMutation() PollOption

WithPollingMutation polls the predicate on every DOM mutation.

func WithPollingTimeout added in v0.6.11

func WithPollingTimeout(timeout time.Duration) PollOption

WithPollingTimeout sets the maximum time to wait until the predicate returns a truthy value. It defaults to 30 seconds. Pass 0 to disable the timeout.

type PopulateOption added in v0.9.5

type PopulateOption = func(*time.Duration)

PopulateOption is an element populate action option.

func PopulateWait added in v0.9.5

func PopulateWait(wait time.Duration) PopulateOption

PopulateWait is a populate option that sets a wait interval after the request for child nodes.

type QueryOption

type QueryOption = func(*Selector)

QueryOption is an element query action option.

func After

func After(f func(ctx context.Context, t *Target, nodes []*Node) error) QueryOption

After is an element query option that sets a func to run when the browser has returned the matched nodes and the node condition is true.

func AtLeast

func AtLeast(n int) QueryOption

AtLeast is an element query option that sets the minimum number of elements that the query must return.

By default, a query needs 1.

func ByFunc

func ByFunc(f func(context.Context, *Target, *Node) ([]cdp.NodeID, error)) QueryOption

ByFunc is an element query action option that sets the func that selects elements. It replaces the lookup that the type of the selector chooses. The selector is then only a label in error messages, so pass "" or any string.

func FromNode added in v0.5.4

func FromNode(node *Node) QueryOption

FromNode is an element query action option that sets the node where the query runs. That is, the query looks only at the element sub-tree of the node. By default, or when you pass nil, the query uses the root element of the document.

Note: Search and JSPath selectors do not support FromNode now. The option is mainly useful for CSS selectors.

FromNode does not reach into an iframe from another site. Chrome runs such an iframe in its own process, as a separate target, and the node of the iframe element has no ContentDocument. A query from that node finds nothing and waits until its context ends. See WithTargetID for how to attach to the iframe.

Example
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`
<body>
	<p class="content">outer content</p>
	<div id="section"><p class="content">inner content</p></div>
</body>
	`))
	defer ts.Close()

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}
	nodes, err := chromedp.Run(ctx, chromedp.Nodes(chromedp.CSS("#section")))
	if err != nil {
		log.Fatal(err)
	}
	sectionNode := nodes[0]

	// Queries run from the document root by default, so Text picks the
	// first node that it finds.
	queryRoot, err := chromedp.Run(ctx, chromedp.Text(chromedp.CSS(".content")))
	if err != nil {
		log.Fatal(err)
	}

	// We can choose a different node to run the query from. In this case,
	// we can narrow the search to #section.
	queryFromNode, err := chromedp.Run(ctx, chromedp.Text(chromedp.CSS(".content"), chromedp.FromNode(sectionNode)))
	if err != nil {
		log.Fatal(err)
	}

	// A CSS selector like "#section > .content" achieves the same here. But
	// FromNode accepts a node from an entirely separate step, so it allows
	// custom logic.
	queryNestedSelector, err := chromedp.Run(ctx, chromedp.Text(chromedp.CSS("#section > .content")))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Simple query from the document root:", queryRoot)
	fmt.Println("Simple query from the section node:", queryFromNode)
	fmt.Println("Nested query from the document root:", queryNestedSelector)

}
Output:
Simple query from the document root: outer content
Simple query from the section node: inner content
Nested query from the document root: inner content

func Populate added in v0.9.5

func Populate(depth int64, pierce bool, opts ...PopulateOption) QueryOption

Populate is an element query option that retrieves the queried nodes for later use. Use a depth of -1 to retrieve all child nodes. When pierce is true, it also pierces child containers (for example iframes).

NOTE: this can use a lot of resources. Use it only when necessary.

func RetryInterval added in v0.8.6

func RetryInterval(interval time.Duration) QueryOption

RetryInterval is an element query action option that sets how often the query retries when it fails to select the target elements.

The default is 5ms.

func WaitFunc

func WaitFunc(wait func(context.Context, *Target, *Frame, runtime.ExecutionContextID, ...cdp.NodeID) ([]*Node, error)) QueryOption

WaitFunc is an element query option to set a custom node condition wait.

type Search string

Search is a selector that the browser resolves with DOM.performSearch. It matches nodes by plain text, CSS selector or XPath query. It is the lookup of a plain string.

type Selectable added in v0.17.0

type Selectable interface {
	~string | ~[]cdp.NodeID
}

Selectable is what an element query accepts as the selector. The type of the selector chooses the lookup. A plain string is a Search. A named string type that this package does not define also counts as a Search.

The set of selector types is closed. A type that you define cannot add a new lookup. For a custom lookup, use the option ByFunc. It replaces the lookup of the selector with a func that receives the Target of the tab and the Node where the query starts, and returns the node IDs of the elements. The target is a session for cdp.Call. The start node is the root of the document, or the node of FromNode. The selector is then only a label in error messages, so pass "" or any string. For example, this lookup finds the elements with a data-testid attribute:

func byTestID(id string) chromedp.QueryOption {
	return chromedp.ByFunc(func(ctx context.Context, t *chromedp.Target, n *chromedp.Node) ([]cdp.NodeID, error) {
		res, err := cdp.Call(ctx, t, dom.QuerySelectorAll, dom.QuerySelectorAllParams{
			NodeID:   n.NodeID,
			Selector: fmt.Sprintf("[data-testid=%q]", id),
		})
		return res.NodeIDs, err
	})
}

err := chromedp.Do(ctx, chromedp.Click("", byTestID("submit")))
Example
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/chromedp/chromedp"
)

func writeHTML(content string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.TrimSpace(content))
	})
}

func main() {
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()

	ts := httptest.NewServer(writeHTML(`
<body>
	<p id="a" class="item">first</p>
	<p id="b" class="item">second</p>
</body>
	`))
	defer ts.Close()

	if err := chromedp.Do(ctx, chromedp.Navigate(ts.URL)); err != nil {
		log.Fatal(err)
	}

	// The type of the selector chooses the lookup. A plain string is a
	// Search, which takes a CSS selector, an XPath query or text.
	plain, err := chromedp.Run(ctx, chromedp.Text("#a"))
	if err != nil {
		log.Fatal(err)
	}
	// CSS selects the first match of a CSS selector.
	css, err := chromedp.Run(ctx, chromedp.Text(chromedp.CSS(".item")))
	if err != nil {
		log.Fatal(err)
	}
	// CSSAll selects every match of a CSS selector.
	all, err := chromedp.Run(ctx, chromedp.Nodes(chromedp.CSSAll(".item")))
	if err != nil {
		log.Fatal(err)
	}
	// ID selects the element with an id.
	id, err := chromedp.Run(ctx, chromedp.Text(chromedp.ID("b")))
	if err != nil {
		log.Fatal(err)
	}
	// NodeIDs selects the nodes with these ids.
	ids, err := chromedp.Run(ctx, chromedp.QueryNodeIDs(chromedp.CSSAll(".item")))
	if err != nil {
		log.Fatal(err)
	}
	byNodeIDs, err := chromedp.Run(ctx, chromedp.Text(chromedp.NodeIDs(ids[1:])))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(plain, css, len(all), id, byNodeIDs)

	// A type outside of the Selectable set does not compile. Both calls
	// below are errors at build time, not at run time:
	//
	//	chromedp.Click(42)
	//	chromedp.Click(node)

}
Output:
first first 2 second second

type Selector

type Selector struct {
	// contains filtered or unexported fields
}

Selector holds the data of an element selection query.

See Query for how to build an element selector and its options.

type Target added in v0.2.0

type Target struct {
	SessionID target.SessionID
	TargetID  target.ID
	// contains filtered or unexported fields
}

Target manages a Chrome DevTools Protocol target.

func (*Target) Call added in v0.17.0

func (t *Target) Call(ctx context.Context, method string, params, res any) error

Call sends the command to the target, waits for the response, and decodes the result into res. It satisfies cdp.Session.

Call returns a browser error as a *cdproto.Error. It returns an error when the connection to the browser is lost, also when ctx never ends. The error wraps the reason of the loss and context.Canceled.

func (*Target) Subscribe added in v0.17.0

func (t *Target) Subscribe(method string) (<-chan jsonv2.Value, func())

Subscribe starts to buffer the target events with the method, and returns the channel that the raw event parameters arrive on. It satisfies cdp.Session.

type Transport added in v0.2.0

type Transport interface {
	Read(context.Context, *cdproto.Message) error
	Write(context.Context, *cdproto.Message) error
	io.Closer
}

Transport is the common interface to send and receive the protocol messages of a browser. PipeConn implements it, and so does the websocket connection of the package github.com/chromedp/chromedp/remote. Browser reads and writes its messages through it, and NewBrowserTransport accepts any Transport.

A Transport can also have the method SetDebugf(func(string, ...any)). NewBrowserTransport then calls it with the protocol logger of the browser.

type Void added in v0.17.0

type Void = struct{}

Void is the result type of an action that returns no value.

Directories

Path Synopsis
Package device contains device emulation definitions for use with chromedp's Emulate action.
Package device contains device emulation definitions for use with chromedp's Emulate action.
internal
chromedptest
Package chromedptest holds the helpers that the tests of the chromedp packages share.
Package chromedptest holds the helpers that the tests of the chromedp packages share.
testenv
Package testenv reads the environment variables that change the tests of chromedp.
Package testenv reads the environment variables that change the tests of chromedp.
Package kb provides keyboard mappings for Chrome DOM Keys for use with input events.
Package kb provides keyboard mappings for Chrome DOM Keys for use with input events.
Package remote connects chromedp to a browser with a websocket.
Package remote connects chromedp to a browser with a websocket.
internal/websocket
Package websocket is a WebSocket client as RFC 6455 defines it.
Package websocket is a WebSocket client as RFC 6455 defines it.
internal/wstest
Package wstest is a minimal WebSocket server for tests.
Package wstest is a minimal WebSocket server for tests.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL