Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
browser automation

How to Screenshot Webpages as PNG in Go with chromedp

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

Use a Chromium browser driven by the maintained chromedp Go package. Navigate to the page, run chromedp.FullScreenshot(&png, 100), and write the returned bytes with os.WriteFile. A quality value of 100 selects PNG; lower values select JPEG.

This approach renders the page as a real browser does, so modern HTML, CSS, JavaScript, fonts and images are available. Go image libraries alone cannot render a webpage.

Complete Go example: full webpage to PNG

Create a module, add chromedp, and save this as main.go:

package main

import (
    "context"
    "log"
    "os"

    "github.com/chromedp/chromedp"
)

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

    var png []byte
    err := chromedp.Run(ctx,
        chromedp.Navigate("https://example.com"),
        chromedp.FullScreenshot(&png, 100),
    )
    if err != nil {
        log.Fatal(err)
    }
    if err := os.WriteFile("page.png", png, 0o644); err != nil {
        log.Fatal(err)
    }
}
  1. Install a Chromium-based browser that chromedp can launch, or make a Chromium/Chrome executable available on the machine’s PATH.
  2. Initialize and fetch the dependency:
    go mod init example/screenshot
    go get github.com/chromedp/chromedp
    go run .
  3. Open page.png. The file is binary PNG data, not base64 or text.

chromedp.NewContext creates a browser context, Navigate loads the URL, and FullScreenshot returns the complete rendered page. The final os.WriteFile call persists those bytes with standard file permissions.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

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

Choose the capture scope

Viewport screenshot

chromedp.CaptureScreenshot(&buf) captures only what is currently visible in the browser viewport. It is appropriate for a screenshot that should match the initial window rather than the entire document.

var buf []byte
err := chromedp.Run(ctx,
    chromedp.Navigate("https://example.com"),
    chromedp.CaptureScreenshot(&buf),
)
if err != nil {
    log.Fatal(err)
}
if err := os.WriteFile("viewport.png", buf, 0o644); err != nil {
    log.Fatal(err)
}

One element

Use chromedp.Screenshot with a CSS selector and chromedp.NodeVisible to capture the first matching visible element:

var element []byte
err := chromedp.Run(ctx,
    chromedp.Navigate("https://example.com"),
    chromedp.Screenshot("#content", &element, chromedp.NodeVisible),
)
if err != nil {
    log.Fatal(err)
}
if err := os.WriteFile("content.png", element, 0o644); err != nil {
    log.Fatal(err)
}

If the selector matches nothing, or the node is not visible, the action fails. Use a selector that is stable across page versions and wait for the element when it is created by JavaScript.

Full page

chromedp.FullScreenshot(&buf, 100) is the direct full-page PNG path. It captures the entire browser viewport/document area rather than only the pixels currently on screen. Lazy-loaded content may require an explicit scroll or wait strategy before capture; see the timing section below.

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

Control timing so the page is ready

Navigation completing does not guarantee that asynchronous data, web fonts or images have finished rendering. Add actions that represent the page’s actual readiness condition.

Wait for a required element

err := chromedp.Run(ctx,
    chromedp.Navigate("https://example.com/dashboard"),
    chromedp.WaitVisible("main.dashboard", chromedp.ByQuery),
    chromedp.FullScreenshot(&png, 100),
)

A selector wait is preferable to an arbitrary sleep when a known element marks readiness. For pages without a reliable marker, a short delay can be used, but it is less deterministic.

Lazy images and long pages

Full-page capture can occur before images below the fold have been requested. A practical sequence is to wait for the main content, scroll through the document with JavaScript to trigger lazy loading, wait briefly for network responses, then call FullScreenshot. The exact script depends on the site; do not assume every lazy-loading implementation uses the same trigger.

Timeouts and cancellation

Wrap the browser context in a timeout so a broken or unresponsive site cannot hold a worker forever:

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.
base := context.Background()
ctx, cancel := chromedp.NewContext(base)
ctx, cancel = context.WithTimeout(ctx, 90*time.Second)
defer cancel()

Import time when using this form. A cancellation returns an error; record it and decide whether to retry.

PNG, JPEG, scale and clipping

PNG versus JPEG

The quality argument to FullScreenshot controls the output format: 100 keeps PNG, while values below 100 select JPEG. PNG is lossless and preserves text and transparency well, but can produce larger files. JPEG is lossy and can be smaller for photographic pages.

Scale factor

chromedp.ScreenshotScale changes the page scale factor. Increasing scale can improve detail for dense interfaces while increasing pixel dimensions and memory use. Keep the scale consistent when comparing screenshots or generating visual regression fixtures.

Viewport dimensions

The screenshot reflects the browser viewport. Set the viewport before navigation when a reproducible desktop or mobile layout matters. A different viewport can activate responsive breakpoints, alter wrapping and change the resulting PNG.

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

Clip a region with the Chrome DevTools Protocol

At the lower level, CDP’s Page.captureScreenshot supports a format, a clip rectangle and captureBeyondViewport. This is useful when you need a precise rectangle rather than a whole viewport or element. The chromedp CDP bindings return decoded image bytes that you can write with the same binary-safe file operation.

Browser and deployment requirements

  • Chromium runtime: chromedp controls a Chromium-based browser; it is not an HTML renderer by itself.
  • Executable discovery: In local development, ensure Chrome or Chromium is installed and discoverable. In containers, install a compatible browser and its required shared libraries.
  • Sandbox policy: Do not disable the Chromium sandbox casually. If your container requires special flags, apply the smallest policy-approved change and understand its security impact.
  • Fonts and assets: Missing fonts, blocked resources or a different timezone can change pixels. Install the fonts your page requires and provide network access to its assets.
  • Concurrency: Reuse a browser process carefully and isolate contexts, or limit parallel launches. Each page consumes browser resources; measure your own workload rather than relying on an unverified throughput number.

For repeatable output, pin the browser image and Go dependencies in your build, set a known viewport, and capture from a controlled network environment. There is no generally applicable speed, memory or PNG-size figure established for this workflow; those values depend on the page, browser version, fonts and machine.

Reliable patterns for production code

Check every error

Check errors from navigation, waits, screenshot actions and file writes separately when possible. A successful navigation followed by a failed write is still a failed capture from the application’s perspective.

Use temporary files for atomic output

Write to a temporary path in the destination directory, close it, then rename it to the final filename. Consumers will not observe a half-written PNG if the process is interrupted.

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

Retry only transient failures

Retries can help with temporary network failures, but repeating a deterministic selector error wastes browser time. Classify errors, use a bounded retry count and vary neither the URL nor capture settings unless that is intentional.

Protect secrets

If a page needs authentication, provide credentials through the browser context or request headers without logging cookies, authorization values or the resulting private screenshot. Treat captured files as sensitive data.

Troubleshooting

“exec: … chromium … no such file or directory”

Cause: No compatible browser is installed or the executable is not discoverable. Fix: Install Chromium/Chrome in the runtime image, add it to PATH, or configure chromedp’s allocator options with the actual executable path.

Screenshot is blank or shows a loading shell

Cause: The capture ran before client-side rendering completed, or required resources were blocked. Fix: wait for a visible, content-specific selector; verify network access and JavaScript errors; then capture.

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

Element screenshot reports no matching node

Cause: The selector is wrong, the element is inside a frame, or it has not been inserted yet. Fix: verify the selector in DevTools, wait for it, and handle frames explicitly when the target is not in the top document.

Full page misses images below the fold

Cause: lazy loading has not been triggered. Fix: scroll the document programmatically, wait for image completion where practical, and then run FullScreenshot.

Output is JPEG instead of PNG

Cause: The quality argument was below 100. Fix: pass exactly 100 for the PNG path and use a .png filename.

Text or layout differs between machines

Cause: Different viewport, device scale, browser version, fonts, timezone or network responses. Fix: standardize those inputs and avoid comparing captures made under different environments.

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

The process hangs

Cause: A page never reaches the expected state or a network request remains open. Fix: apply a context timeout, wait for a concrete condition instead of indefinite network idleness, and capture diagnostic logs before retrying.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo provides a website screenshot API when you do not want to package and operate Chromium. Cookie and consent banners, newsletter popups and chat widgets are removed before the shot. Bot checks/CAPTCHAs, blank pages, failed loads and timeouts are not billed, and cache hits are free; the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.

For a PNG response, call the API from Go or any HTTP client:

package main

import (
    "io"
    "log"
    "net/http"
    "net/url"
    "os"
)

func main() {
    endpoint, _ := url.Parse("https://api.screenshotneo.com/v1/shot")
    q := endpoint.Query()
    q.Set("access_key", "YOUR_API_KEY")
    q.Set("url", "https://example.com")
    endpoint.RawQuery = q.Encode()

    resp, err := http.Get(endpoint.String())
    if err != nil { log.Fatal(err) }
    defer resp.Body.Close()
    if resp.StatusCode < 200 || resp.StatusCode >= 300 { log.Fatalf("HTTP %s", resp.Status) }
    f, err := os.Create("page.png")
    if err != nil { log.Fatal(err) }
    defer f.Close()
    if _, err := io.Copy(f, resp.Body); err != nil { log.Fatal(err) }
}

See the ScreenshotNeo API documentation for all 63 options, including full-page and element capture, device presets, retina scale, custom CSS/JavaScript, waits, blocking rules, headers, cookies, geolocation, caching, signed links, asynchronous webhooks and bulk capture.

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

The equivalent command-line and language examples are:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account.

Which approach should you use?

Need Best fit Reason
Go-native local capture and full control of Chromium chromedp Direct Go actions, viewport/element/full-page APIs and CDP clipping.
Hosted capture without browser installation ScreenshotNeo Clean shots, only clean shots billed, and a $5 paid plan for 3,000 shots.
AI-agent-driven screenshots ScreenshotNeo MCP server Tools for taking screenshots, page information and PDFs from MCP clients.

Frequently Asked Questions

Can Go take a webpage screenshot without Chrome or Chromium?

Not for a modern rendered webpage with chromedp: a Chromium-based browser is required. Go can write the resulting bytes, but it does not replace the browser rendering engine.

How do I capture only the visible viewport?

Navigate with chromedp and call CaptureScreenshot(&buf), then write buf to a PNG file.

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

Why does quality 100 matter?

For chromedp.FullScreenshot, quality 100 selects PNG output; lower values select JPEG.

Can I capture a CSS-selected element?

Yes. Use chromedp.Screenshot with the selector and chromedp.NodeVisible, after waiting until the element exists and is visible.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

Read next

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.