Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

With chromedp, navigate to the page, poll a JavaScript predicate that checks the page’s current <img> elements, and capture only after the predicate succeeds. Check both img.complete and img.naturalWidth > 0: completion alone does not distinguish a successfully loaded image from a broken one. This is a practical wait for ordinary image elements, not a guarantee that lazy-loaded, CSS-background, or canvas images have appeared.

Wait for current images, then capture

The sequence below navigates, waits until every image currently in document.images is complete and has a positive natural width, and writes a full-page PNG. It assumes you have a Go module and a Chrome-compatible browser available for chromedp to control. The project’s rolling documentation does not pin a chromedp or Chrome version, so this example does not claim a specific tested version.

package main

import (
	"context"
	"os"

	"github.com/chromedp/chromedp"
)

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

	const url = "https://example.com"
	const imagesLoaded = `Array.from(document.images).every(img => img.complete && img.naturalWidth > 0)`

	var buf []byte
	err := chromedp.Run(ctx,
		chromedp.Navigate(url),
		chromedp.Poll(imagesLoaded, nil),
		chromedp.FullScreenshot(&buf, 100),
	)
	if err != nil {
		panic(err)
	}
	if err := os.WriteFile("screenshot.png", buf, 0644); err != nil {
		panic(err)
	}
}

Create the module and add chromedp using the version-management workflow appropriate for your project, then run the program:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
go mod init example.com/screenshot
 go get github.com/chromedp/chromedp
go run .

Replace https://example.com with the page to capture. chromedp.Poll waits for a general JavaScript predicate; placing it between navigation and capture ensures the screenshot action does not run until that predicate returns true. The code propagates errors from the chromedp task before attempting to write output.

What the image predicate does—and does not—wait for

document.images represents the page’s current image elements. For each one, complete indicates that loading has finished, while naturalWidth > 0 is used here to exclude failed images and images without usable source content. MDN notes that complete may also be true when an image has no source or when loading failed; it is not, by itself, proof of a successful load: HTMLImageElement.complete.

The predicate is deliberately limited to those current DOM images. A page may defer below-the-fold images until scrolling, use CSS backgrounds, render imagery to canvas, or load content after application-specific work. For those cases, trigger the page’s intended behavior—such as scrolling through the relevant content—and wait for a signal that matches the page, or inspect the relevant resources separately. There is no single documented chromedp wait in the referenced APIs that settles every such pattern. If broken images should not be allowed to pass the wait, the positive-width condition is useful; if you instead want to capture a page even when an image is broken, adjust the predicate to match that policy.

Choose the capture target and format

Keep the capture action after the wait in the same chromedp.Run sequence. The official chromedp screenshot example demonstrates element capture with Screenshot and full-page capture with FullScreenshot: screenshot example.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • One element: use chromedp.Screenshot(selector, &buf, ...) to capture a selected element. The selector must identify content present in the page when the action runs.
  • Current viewport: use chromedp.CaptureScreenshot(&buf) for the visible viewport. The generated Page protocol API also exposes capture parameters for format, quality, clipping, surface capture, and capture beyond the viewport: cdproto Page API.
  • Full page: use chromedp.FullScreenshot(&buf, 100) to capture beyond the viewport. The documented quality value of 100 yields PNG; other supported values yield JPEG. The helper overrides device emulation settings, so do not assume a mobile or custom emulated viewport remains in effect for this capture.

The choice depends on whether the output should show a component, the visible viewport, or the full document. For viewport emulation-sensitive work, account for the full-page helper’s documented override and choose the capture path accordingly.

Or skip the browser setup

If you want an API call instead of managing a browser session, ScreenshotNeo accepts a URL and returns a screenshot or PDF. Its cleanup can accept consent banners and remove known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with verdict and billing details in response headers. It also offers an MCP server with screenshot, page-info, and PDF tools for AI clients.

For this example, a cURL request is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

See the ScreenshotNeo API documentation for access-key setup and request options. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Sign up for free.

Troubleshoot common failures

  • The wait never finishes: one image may be broken, have no usable source, or remain pending. The positive-width check intentionally does not treat failed images as successful. Inspect the page’s image elements and network behavior; if a failed image is acceptable for your use case, change the predicate to wait for completion without requiring positive natural width.
  • The screenshot misses images below the fold: lazy loading may not begin until an image approaches the viewport. Scroll the page or target section to trigger loading, then wait again before capturing.
  • Some visual content is still absent: the predicate covers DOM image elements, not CSS backgrounds, canvas drawings, or app-specific rendering. Wait on the relevant application signal or handle that content separately.
  • The capture is not the expected viewport: FullScreenshot overrides device emulation settings. Use a capture approach suited to the required viewport, or account for the override in the sequence.
  • No screenshot file is written: chromedp.Run may have returned a navigation, wait, or capture error. The example exits on that error before writing; inspect the returned error and verify browser availability and page access.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Frequently Asked Questions

Does chromedp.WaitReady mean every image has loaded?

No. It reports DOM readiness for an element, not successful completion of every page image. Use an explicit image predicate when that condition matters.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why check naturalWidth as well as complete?

An image can be complete even when it has no source or failed to load. A positive naturalWidth helps distinguish usable image content.

Does FullScreenshot preserve mobile device emulation?

The documented helper overrides device emulation settings. Choose the capture method with that behavior in mind.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.