ScreenshotNeo

BlogHow-to

Take Website Screenshots in Go with chromedp on an AWS Mumbai Instance

Capture viewport, element, or full-page screenshots in Go with chromedp, then run the workflow on EC2 in AWS Mumbai’s ap-south-1 Region.

By the ScreenshotNeo team4 October 20267 min read

Use chromedp to control a compatible Chrome or Chromium browser from Go, navigate to a page, and save the screenshot bytes. On AWS, run the Go program and browser in an EC2 environment in the Mumbai Region, whose code is ap-south-1. chromedp is a Chrome DevTools Protocol client, not a browser, so the browser runtime must also be available. The examples below show viewport, element, and full-page capture; the right choice depends on what part of the page you need.

1. Choose the capture area

Mode What it captures Use it when
Viewport The current browser viewport You need the visible portion at a specific viewport size.
Element The node matched by a CSS selector You need a chart, card, report, or other specific page element.
Full page The page beyond the current viewport You need a tall-page image including content below the fold.

The chromedp package provides screenshot actions, and its examples demonstrate both element and full-page capture. Selectors are site-specific: verify that the element exists and is ready before capturing it.

2. Set up Go and a browser runtime

Create a module and add chromedp:

mkdir chromedp-shot
cd chromedp-shot
go mod init example.com/chromedp-shot
go get github.com/chromedp/chromedp

Install or package a compatible Chrome/Chromium browser runtime for the operating system you choose. The chromedp project documents a headless-shell container image as one option for headless environments. Chrome runs headless by default according to the project FAQ. The exact installation commands depend on your EC2 operating system image and browser packaging; verify them for the image you deploy rather than assuming one set of commands applies everywhere.

3. Capture a viewport, element, or full page

This runnable program takes the URL, output path, and mode from command-line arguments. For element mode, pass a selector as the fourth argument. It uses a timeout, waits for the document load event, and writes the resulting PNG bytes.

package main

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

	"github.com/chromedp/chromedp"
)

func main() {
	if len(os.Args) < 4 {
		fmt.Fprintln(os.Stderr, "usage: chromedp-shot URL OUTPUT.png viewport|full|element [CSS_SELECTOR]")
		os.Exit(2)
	}
	url, output, mode := os.Args[1], os.Args[2], os.Args[3]

	// For an untrusted URL, validate and restrict destinations before navigation.
	ctx, cancel := chromedp.NewContext(context.Background())
	defer cancel()
	ctx, cancel = context.WithTimeout(ctx, 45*time.Second)
	defer cancel()

	var image []byte
	var actions chromedp.Tasks
	switch mode {
	case "viewport":
		actions = chromedp.Tasks{
			chromedp.Navigate(url),
			chromedp.WaitReady("body", chromedp.ByQuery),
			chromedp.Screenshot("body", &image, chromedp.NodeVisible, chromedp.ByQuery),
		}
	case "full":
		actions = chromedp.Tasks{
			chromedp.Navigate(url),
			chromedp.WaitReady("body", chromedp.ByQuery),
			chromedp.FullScreenshot(&image, 90),
		}
	case "element":
		if len(os.Args) < 5 {
			fmt.Fprintln(os.Stderr, "element mode requires a CSS selector")
			os.Exit(2)
		}
		selector := os.Args[4]
		actions = chromedp.Tasks{
			chromedp.Navigate(url),
			chromedp.WaitVisible(selector, chromedp.ByQuery),
			chromedp.Screenshot(selector, &image, chromedp.NodeVisible, chromedp.ByQuery),
		}
	default:
		fmt.Fprintln(os.Stderr, "mode must be viewport, full, or element")
		os.Exit(2)
	}

	if err := chromedp.Run(ctx, actions); err != nil {
		fmt.Fprintln(os.Stderr, "capture failed:", err)
		os.Exit(1)
	}
	if err := os.WriteFile(output, image, 0644); err != nil {
		fmt.Fprintln(os.Stderr, "write failed:", err)
		os.Exit(1)
	}
	fmt.Printf("saved %d bytes to %s\n", len(image), output)
}

Run the examples:

go run . https://example.com viewport.png viewport
go run . https://example.com full.png full
go run . https://example.com chart.png element "main canvas"

chromedp.Screenshot captures a selected node. The example uses NodeVisible and waits for visibility in element mode. FullScreenshot captures the page beyond the viewport; its quality argument controls image quality for the JPEG output. Check the installed chromedp version’s package reference when adapting screenshot actions or output formats. For a viewport image, the example captures the visible body node; if you need exact viewport dimensions independent of body layout, use the viewport screenshot action documented by your chromedp version and set its device metrics explicitly.

4. Run the job on EC2 in Mumbai

AWS identifies Mumbai as Region ap-south-1; EC2 endpoints are regional. A practical deployment sequence is:

  1. Choose an EC2 operating system image and instance size that fit your workload. The sources here do not establish a recommended image or size.
  2. Install Go or build the program for the instance’s operating system and architecture. Ensure the compatible Chrome/Chromium runtime is installed or included in the deployment image.
  3. Place the instance in ap-south-1 when the workload must run in Mumbai. Configure network access so it can reach the target sites and any required dependencies.
  4. Run the program as a service or job worker. Set a process-level timeout and ensure the browser process exits when a job ends.
  5. Monitor failed navigations, browser disconnects, timeouts, output sizes, and disk use. Avoid logging credentials or sensitive page content.

Region choice determines where this compute workload runs. It does not make the target website faster or guarantee that the site is reachable from the instance. Confirm routing, DNS, outbound access, and any target-site restrictions in your own environment.

5. Make captures dependable

Wait for the page state you need

A navigation finishing does not always mean a single-page app has populated the content you want. Wait for a known selector with WaitVisible or add a deliberate delay only when the page has no reliable readiness signal. For lazy-loaded content, full-page capture may require scrolling or another page-specific trigger before the screenshot action.

Use bounded timeouts and clean up

The example wraps the browser context with a deadline and defers cancellation. chromedp documents that losing the browser connection can cancel the context. Treat navigation, selector waits, and capture as fallible operations; return a job failure rather than writing an empty or partial result as if it were valid.

Limit untrusted input

If callers can submit URLs, validate the scheme and destination before navigating. Apply network controls to prevent access to internal services, metadata endpoints, or other destinations your application should not expose. Run browser jobs with restricted permissions and resource limits appropriate to your environment.

Choose viewport geometry intentionally

Viewport size affects responsive layout, line wrapping, and the resulting screenshot. For reproducible captures, set device metrics to the same width, height, and scale each time using the chromedp device emulation actions. Full-page and element captures answer different questions; test the target page’s fixed headers, sticky elements, and overflow behavior.

6. Troubleshoot common failures

Symptom Likely cause Fix
Chrome executable not found or cannot start No compatible browser runtime is installed, or its path/environment is unavailable. Install/package a compatible Chrome or Chromium runtime, verify it launches in the chosen environment, and configure chromedp’s allocator options if a non-default executable path is needed.
Browser exits or the context is canceled The browser process disconnected, crashed, or was stopped. Check process logs and memory limits, ensure the browser remains alive for the job, and create a fresh context for a retry.
Navigation times out The site is slow, unreachable, blocked, or waiting on long-lived resources. Check DNS and outbound networking, use a bounded but suitable deadline, and wait for the specific content selector when full network idle is inappropriate.
Element not found or not visible The selector is wrong, the site changed, or the element has not appeared. Inspect the current page DOM, update the selector, and wait for visibility of the actual target.
Screenshot is blank or incomplete The page content has not rendered, lazy content has not loaded, or the wrong capture mode was selected. Wait for a meaningful readiness condition, trigger lazy loading if needed, and choose viewport, element, or full-page capture intentionally.
Image is much taller or larger than expected Full-page capture includes content beyond the viewport, or the page has unusually large dimensions. Use viewport or element capture when appropriate; inspect image dimensions and impose output-size controls in your application.
Works locally but fails on EC2 Browser packaging, architecture, permissions, libraries, DNS, or outbound networking differ. Check the browser startup error and operating-system dependencies on the instance; verify the selected image and runtime together.

7. Performance, reliability, and cost

Each capture needs a browser session and page load, so page complexity and network conditions affect runtime and resource use. The research sources provide no workload-specific benchmarks or recommended EC2 size; measure representative pages in the selected environment before sizing concurrency. Reusing browser processes can reduce startup work, but requires lifecycle management and isolation between jobs. Bound concurrent tabs and jobs to the memory and CPU available, and recycle unhealthy browser processes.

EC2 cost depends on the instance, storage, network use, and runtime. No specific instance price or workload cost is established here. Estimate from the AWS pricing for the Region and configuration you choose, then account for failed jobs and browser capacity. For reliability, record per-job outcomes and retry only transient failures with limits; repeated retries cannot fix a broken selector or a site that consistently blocks access.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server by Yorker Media. Its API accepts a URL and returns an image or PDF; see the API documentation. For example, capture a page with one request:

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

ScreenshotNeo accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan. Visit ScreenshotNeo or sign up free for 1,000 screenshots a month, with no card required.

FAQ

Does chromedp include Chrome?

No. chromedp controls a separate compatible Chrome/Chromium browser runtime using the Chrome DevTools Protocol.

What is the AWS Mumbai Region code?

It is ap-south-1.

Can I use an element selector from another website?

Only if that selector matches a visible element on the current page. Check it against the target site because markup can change.

Which screenshot mode should I use for a long page?

Use full-page capture when you need content beyond the viewport; use element capture for one component and viewport capture for the visible browser area.