To capture screenshots for many URLs in Go, reuse a Selenium WebDriver session: navigate to each URL, wait for the page state you need, call the Go client’s screenshot method, and save the returned PNG bytes under a deterministic filename. Log failures per URL so one bad page does not discard the rest of the batch. Standard WebDriver screenshots capture the current browsing context—usually the visible viewport—not automatically the entire page.
What you need before running a screenshot batch
Selenium lets Go control a browser through WebDriver. You need a compatible browser and its WebDriver installation, plus a Go Selenium client. The tebeka/selenium repository documents browser and driver setup, dependency downloads, and hosted execution options. Browser and driver versions must be compatible; if a session cannot start, check that first.
- A recent Go installation and a Go module for your program.
- A browser installed on the machine running the program.
- The matching WebDriver binary available to the program, or a reachable Selenium server/Grid endpoint.
- A list of URLs and a directory with room for the resulting images.
The example below uses the tebeka client’s familiar API shape. Confirm the exact method names against the version you install: Go bindings and their full-page screenshot behavior can vary by version. In particular, the boolean argument to Screenshot should not be assumed to mean full-page capture without checking that binding’s documentation.
Capture a list of URLs in one Go session
This example creates one browser session, navigates through a URL list, waits for document readiness, saves each screenshot as a PNG, and writes a JSON-lines manifest containing each URL, output filename, timestamp, and any error. Navigation, screenshot, and file-write failures are recorded separately, and the loop continues when an individual page fails.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →#1 Best Overall
- CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
- WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
- A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"time"
"github.com/tebeka/selenium"
)
type Result struct {
URL string `json:"url"`
File string `json:"file,omitempty"`
Captured time.Time `json:"captured_at"`
Error string `json:"error,omitempty"`
}
func main() {
urls := []string{
"https://example.com/",
"https://go.dev/",
}
const (
port = 4444
geckoPath = "/usr/local/bin/geckodriver"
outputDir = "screenshots"
)
// Start geckodriver separately, for example with:
// geckodriver --port 4444
caps := selenium.Capabilities{"browserName": "firefox"}
service, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
if err != nil {
log.Fatalf("create WebDriver session: %v", err)
}
defer service.Quit()
_ = geckoPath // Driver installation/startup is environment-specific.
if err := os.MkdirAll(outputDir, 0o755); err != nil {
log.Fatalf("create output directory: %v", err)
}
manifest, err := os.Create(filepath.Join(outputDir, "manifest.jsonl"))
if err != nil {
log.Fatalf("create manifest: %v", err)
}
defer manifest.Close()
for i, rawURL := range urls {
result := Result{URL: rawURL, Captured: time.Now().UTC()}
if err := service.Get(rawURL); err != nil {
result.Error = "navigation: " + err.Error()
writeResult(manifest, result)
continue
}
// document.readyState is a basic readiness check. For a dynamic page,
// wait for the particular content selector your capture depends on.
if err := waitForReady(service, 20*time.Second); err != nil {
result.Error = "readiness: " + err.Error()
writeResult(manifest, result)
continue
}
png, err := service.Screenshot(false)
if err != nil {
result.Error = "screenshot: " + err.Error()
writeResult(manifest, result)
continue
}
name := fmt.Sprintf("%06d-%s.png", i+1, safeHost(rawURL))
path := filepath.Join(outputDir, name)
if err := os.WriteFile(path, png, 0o644); err != nil {
result.Error = "write: " + err.Error()
writeResult(manifest, result)
continue
}
result.File = name
writeResult(manifest, result)
}
}
func waitForReady(driver selenium.WebDriver, timeout time.Duration) error {
deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
value, err := driver.ExecuteScript("return document.readyState", nil)
if err == nil && value == "complete" {
return nil
}
time.Sleep(200 * time.Millisecond)
}
return fmt.Errorf("document did not reach readyState complete within %s", timeout)
}
func safeHost(rawURL string) string {
parts := strings.Split(strings.TrimPrefix(strings.TrimPrefix(rawURL, "https://"), "http://"), "/")
host := strings.ToLower(parts[0])
host = strings.ReplaceAll(host, ":", "-")
return host
}
func writeResult(file *os.File, result Result) {
if err := json.NewEncoder(file).Encode(result); err != nil {
log.Printf("write manifest entry for %s: %v", result.URL, err)
}
}
WebDriver’s screenshot operation applies to the current browsing context and returns an image encoded in Base64 at the protocol level. Go bindings commonly decode that data and expose bytes; the Selenium documentation describes the endpoint in its window interactions documentation. Check both the error and the returned bytes before writing. The example treats the client result as PNG bytes; if your installed binding exposes Base64 text instead, decode it before saving.
Install and start the driver for your environment
The code connects to a WebDriver server at http://localhost:4444/wd/hub. Start a compatible local driver or Selenium server at that address before running the program, and set the requested browser capability to match the browser you installed. WebDriver startup commands and endpoints depend on the driver/server version, so use the setup instructions for your installed browser and driver rather than copying a command for a different environment.
Create a Go module, add the tebeka Selenium client version you intend to use, save the program as main.go, then run it with go run .. The output directory will contain numbered PNG files and manifest.jsonl. A manifest entry with an error has no successful screenshot filename; correct the cause and retry just those URLs.
Replace the basic readiness check when needed
document.readyState == "complete" means the document load event has completed; it does not guarantee that a single-page app finished rendering, that a lazy image entered the viewport, or that a delayed overlay disappeared. For repeatable captures, wait for a stable, page-specific condition: for example, the presence of the main article selector and the disappearance of a loading indicator. Set a finite timeout and record a readiness error instead of taking a screenshot of a partial page.
Rank #2
- CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
- SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
Make batches reliable and retryable
Use stable filenames and a manifest
A numeric prefix preserves input order, while a host label makes files easier to inspect. Hostnames alone are not unique when the list contains multiple pages on the same site, so retain the index or add a short URL hash if you need filenames that remain stable when input order changes. Avoid using raw URL paths as filenames without sanitizing characters and checking for collisions.
Keep the manifest as the source of truth for retries. Record the original URL, output path, capture time, and an error category. Distinguish navigation failures from waits that timed out, screenshot failures, and local disk errors: each calls for a different fix. For large jobs, write a manifest entry after each URL so an interrupted process does not erase the status of earlier items.
Separate page failures from session failures
A navigation error, a page-specific readiness timeout, or a screenshot error may be limited to one URL. Log it and continue if the WebDriver session still responds. If the browser process or session has become unusable, stop assigning URLs to it, close it, start a fresh session, and resume from the remaining manifest entries. Repeatedly retrying through a dead session can turn every remaining URL into a misleading failure.
Control page-load and script timeouts
Slow sites and pages with long-running scripts can hold a batch worker for a long time. Set page-load and script timeouts appropriate to the sites being captured, and use a separate explicit wait for the actual content required in the image. A timeout that is too short creates false failures; one that is too long makes a broken page stall the batch. Choose limits based on your workload, and record the timeout category for later review.
Recommended Free Tools
Rank #3
- Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
- Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
- Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
- In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
- Ultra-thin bezels: Maximize your viewing experience with thin bezels.
Keep state isolated where necessary
A reused session carries browser state, including cookies and storage, between URLs. That is useful when a batch must remain signed in, but it can also make captures depend on the order of URLs. If sites require different authentication or isolated state, assign them to separate sessions or clear and re-establish state deliberately. Do not share one authenticated session across unrelated workers unless that is intended.
Capture full pages, not just the viewport
A normal WebDriver screenshot captures the current browsing context, commonly the visible browser viewport. It does not, by itself, promise a full-page image. Full-page behavior is browser- and binding-specific; consult the API for your installed Go client and browser before relying on a “full page” flag.
When a full-page screenshot is unavailable in the browser’s WebDriver implementation, options include browser-specific screenshot support, scrolling and stitching viewport images, or using a service designed to produce full-page captures. Scrolling and stitching needs care: fixed headers may appear in every segment, sticky elements can move, and lazy-loaded content may not exist until it is scrolled into view. If completeness matters, wait for images and page content to load before stitching and inspect the result for seams or missing sections.
The Go screenpng project is a concrete reference for an HTTP server that produces full-page PNG screenshots through Selenium. Its behavior is a separate implementation, not a guarantee that every Go Selenium binding supports full-page output identically.
Scale the work with independent browser sessions
One session processes a URL list sequentially, which is simpler and makes shared state predictable, but total completion time grows with the number and load time of pages. To increase throughput, partition the URL list among independent browser sessions or use a hosted Selenium Grid. Each worker should have its own driver session and output naming scheme; do not send concurrent navigation commands through one session.
Rank #4
- CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
- SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
- MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
- KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
- INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
Parallelism increases browser and machine resource use. Start with a modest number of workers, monitor memory and CPU, and increase only while sessions remain responsive. A worker should always call Quit when it finishes, including on shutdown paths, so browser processes are not left behind. Save progress centrally or give each worker a separate manifest that can be merged by URL after the batch.
The tebeka client documentation also describes hosted execution through Sauce Labs. Hosted Selenium Grid or cloud browser execution can avoid maintaining local browser binaries, but it adds a remote dependency and requires configuring the provider’s endpoint and credentials. Keep credentials out of source code and logs.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If the job is simply to obtain screenshots for a URL list, ScreenshotNeo provides a screenshot API and MCP server. It can remove cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server lets AI agents use screenshot tools, and the Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsFor a single capture, the Go equivalent of its one-request workflow is:
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
url := "https://example.com/"
req, err := http.NewRequest(http.MethodGet, "https://api.screenshotneo.com/v1/shot", nil)
if err != nil { panic(err) }
q := req.URL.Query()
q.Set("access_key", os.Getenv("SCREENSHOTNEO_API_KEY"))
q.Set("url", url)
req.URL.RawQuery = q.Encode()
client := &http.Client{}
resp, err := client.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
panic(fmt.Sprintf("screenshot request failed: %s: %s", resp.Status, body))
}
file, err := os.Create("shot.webp")
if err != nil { panic(err) }
defer file.Close()
if _, err := io.Copy(file, resp.Body); err != nil { panic(err) }
}
See the ScreenshotNeo API documentation for request options and response details. The example saves the returned image response as a WebP file. For a bulk Go job, make the request once per URL, apply a timeout, check the response status, and retain the URL-to-file manifest just as with Selenium. ScreenshotNeo also supports full-page capture and bulk capture of up to 100 URLs per call; it offers cache TTLs, async jobs with signed webhooks, usage API access, and parameter names used by other screenshot APIs for easier switching.
Best Value
- 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
- 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
- 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
Sign up for ScreenshotNeo free for 1,000 screenshots per month with no card.
Troubleshooting common failures
- Session creation fails: confirm the browser and driver are installed, compatible, running, and reachable at the configured WebDriver endpoint. Check the browser capability and server path.
- Navigation succeeds but the image is incomplete: the page may still be rendering after the load event. Wait for the specific content selector and for loading markers to disappear; increase the explicit wait only as far as the page’s normal behavior requires.
- Images or lower sections are missing: the screenshot may be viewport-only, or lazy-loaded content may not have been triggered. Scroll the page or use a supported full-page method, then verify the captured dimensions and content.
- The screenshot call errors after several URLs: the session or browser may have failed. Stop using that worker, record the failed URL, restart the session, and retry remaining entries instead of continuing against an unresponsive driver.
- Files overwrite one another: hostname-only naming collides for multiple URLs on the same site. Include an input index or a short hash derived from the full URL.
- Some pages differ depending on order: a reused session may carry cookies or other browser state. Use isolated sessions or reset state where the pages need independent visitors.
- The saved file cannot be opened: ensure the binding returned decoded PNG bytes rather than Base64 text, verify the write succeeded, and check that the captured content is not an error response or empty result.
FAQ
Can I use one WebDriver session for every URL?
Yes, for a sequential batch when shared browser state is acceptable. Use separate sessions when URLs require isolation or when processing in parallel.
Does a successful WebDriver screenshot mean the whole page was captured?
No. It means the current browsing context was captured; full-page output depends on browser- or service-specific support.
Can I run this on a hosted browser?
Yes. A hosted Selenium Grid can provide remote browser sessions; configure the Go client with the provider’s endpoint and required credentials. The tebeka client documentation includes a Sauce Labs execution path.
Quick Recap
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.




