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

To capture a web page in Go with wkhtmltoimage, install the separate wkhtmltoimage executable, then launch it from Go with os/exec. Pass the source URL and output path as separate arguments, set the rendering options you need, and check both the process error and the resulting file. The executable uses QtWebKit and can run headlessly, but it is not a modern Chromium browser, so verify pages that rely on current CSS or JavaScript in your deployment environment.

What you need before writing the Go wrapper

wkhtmltoimage is a command-line renderer from the wkhtmltopdf project. It turns HTML into image formats using QtWebKit; it can run without a display service. Go does not include this renderer: your application must be able to find a compatible executable on the target system, either through PATH or an explicit executable path. See the wkhtmltopdf project and Go’s os/exec package documentation.

  • Install a build appropriate for the target operating system and architecture, or package the executable as part of your deployment.
  • Check the installed binary with wkhtmltoimage --version and wkhtmltoimage --extended-help. Option availability and behavior can differ between packaged builds.
  • Ensure the process user can execute the binary and write to the requested output directory.
  • Test target sites from the same network and runtime environment as the Go service. Local development success does not establish that production can reach the same hosts.

A complete Go example

This example accepts a URL, invokes wkhtmltoimage without a shell, captures diagnostic output, imposes a timeout, and verifies that a non-empty output file was produced. Save it as main.go, install the executable, then run go run . https://example.com capture.png.

package main

import (
	"bytes"
	"context"
	"fmt"
	"io/fs"
	"os"
	"os/exec"
	"strings"
	"time"
)

func capture(ctx context.Context, executable, sourceURL, outputPath string) error {
	cmd := exec.CommandContext(ctx, executable,
		"--format", "png",
		"--width", "1280",
		sourceURL,
		outputPath,
	)
	var stderr bytes.Buffer
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		detail := strings.TrimSpace(stderr.String())
		if detail != "" {
			return fmt.Errorf("wkhtmltoimage: %w: %s", err, detail)
		}
		return fmt.Errorf("wkhtmltoimage: %w", err)
	}

	info, err := os.Stat(outputPath)
	if err != nil {
		return fmt.Errorf("check output: %w", err)
	}
	if !info.Mode().IsRegular() || info.Size() == 0 {
		return fmt.Errorf("wkhtmltoimage produced no usable file at %q", outputPath)
	}
	return nil
}

func main() {
	if len(os.Args) != 3 {
		fmt.Fprintln(os.Stderr, "usage: go run . URL OUTPUT.png")
		os.Exit(2)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	if err := capture(ctx, "wkhtmltoimage", os.Args[1], os.Args[2]); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	info, err := os.Stat(os.Args[2])
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fmt.Printf("wrote %s (%d bytes)n", os.Args[2], info.Size())

	_ = fs.ValidPath // Remove this import and line if not needed in your Go version.
}

The example’s io/fs import and final placeholder line are unnecessary; remove both for a clean build. The runnable source should therefore omit "io/fs" from the imports and omit the _ = fs.ValidPath line. The timeout is an application choice, not a guaranteed maximum render duration for every page; tune it for your workload.

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.
#1 Best Overall
Sale
Kodak PIXPRO FZ45 16MP Compact Digital Camera, 4X Optical Zoom, AA, Black
  • 16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting
  • Optical Zoom: 4x optical zoom with a 27mm wide angle lens for flexible framing indoors or outdoors
  • Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
  • Memory Support: Works with Class 10 SD, SDHC, or SDXC cards up to 512GB
  • LCD Screen and Battery: 2.7in LCD screen with 2 AA alkaline batteries for convenient on-the-go use

Use a configured executable path

If the binary is not on PATH, pass its absolute path as the executable argument, for example /usr/local/bin/wkhtmltoimage. Avoid assuming that a developer machine’s installation path exists in a container or on another operating system.

Why arguments are passed separately

exec.CommandContext receives the program name and each argument as distinct values; it does not automatically start a shell. This prevents shell metacharacters in a value from being interpreted as shell syntax. It does not validate the URL, prevent server-side requests, or make untrusted HTML safe.

Choose options for the capture

Put options before the input and output values, and confirm exact syntax with the installed executable’s extended help. The Debian unstable wkhtmltoimage(1) manual documents the following controls; that reference is not proof every distribution’s binary behaves identically.

Need Option or approach What to watch
Select image type --format Choose a format supported by the installed build and use a matching filename extension.
Set viewport width --width The manual describes width as a guide unless smart-width behavior is disabled; verify the resulting layout.
Set screen height --height The documented default is derived from page content. Check whether your desired capture is a viewport or a full page for the installed version.
Adjust lossy image output --quality The manual gives a 0–100 scale. Quality is relevant to formats that use it; compare output size and appearance for your use case.
Control scripts --disable-javascript, --javascript-delay, or --window-status Disabling scripts can omit content; a delay only waits a fixed period, while window status depends on the page setting the requested value.
Handle failed loads --load-error-handling and --load-media-error-handling Choose whether document or media failures should stop the capture or be handled differently; inspect stderr and the image.
Constrain local files --disable-local-file-access and --allow Disable local access unless required; if required, permit only specific trusted paths.
Supply authenticated context Custom-header and cookie flags Treat header values and cookies as secrets. Avoid logging them or exposing them in errors.

Wait for dynamic content deliberately

Some pages populate content after the initial document loads. A fixed JavaScript delay can allow more time, but it adds latency to every capture and cannot guarantee that asynchronous work is complete. Where the target page can be changed, a page-defined window status provides a more explicit readiness signal. Neither technique makes a legacy renderer compatible with browser APIs it does not support.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Kodak PIXPRO FZ55 16MP Compact Digital Camera, 5X Optical Zoom, Black
  • 16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting
  • Optical Zoom: 5x optical zoom with a 28mm wide angle lens for flexible framing indoors or outdoors
  • Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
  • Memory Support: Works with Class 10 SD, SDHC, or SDXC cards up to 512GB
  • Rechargeable Battery: Included LB-012 lithium-ion battery charges in the camera over USB with the supplied adapter in about 2 hours; charge it for at least 4 hours before first use to maximize battery life

Choose width and output with the consumer in mind

A width that is too narrow can trigger mobile layout; a width that is too wide can produce tiny text when the image is displayed at a fixed size. PNG is a practical choice when faithful sharp edges matter, while lossy formats may reduce file size at a quality trade-off. Use the format and quality options supported by your binary and inspect the actual output rather than assuming a filename extension determines encoding.

Rendering limits and how to decide whether it fits

The project documents QtWebKit as the renderer. Treat wkhtmltoimage as a legacy WebKit-based rendering path rather than a current desktop browser. A page using modern CSS, recent JavaScript APIs, complex authentication, or lazy-loaded resources may appear differently or incompletely. Matching a viewport width and waiting longer cannot guarantee pixel parity with a current browser.

It is best suited when the target pages are controlled or have been verified against the installed build, and when a separate native executable is acceptable in deployment. If current-browser fidelity or JavaScript-heavy websites are essential, evaluate a maintained browser automation or rendering solution and compare runtime footprint, isolation, and operational cost before choosing.

Secure the renderer when inputs are not trusted

A service that renders a caller-supplied URL can cause the server to make network requests. Supplied HTML can also attempt to load remote resources or access local files if the process permits it. Calling the executable without a shell reduces one class of command-injection risk, but it does not address these network and filesystem risks.

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.
Rank #3
Sale
Digital Camera, Latest FHD 1080P Digital Camera for Teens with SD Card Anti Shake Point and Shoot Cameras Portable 16X Zoom Compact Small Cameras for Kids Boys Girls Seniors with Wrist Strap
  • Latest Digital Camera Built-in Fill Light : This compact digital camera is paired with a powerful CMOS processor and image stabilization to help you take & record the most exciting moments in 44 MP quality images & FHD 1080P quality videos anywhere, anytime. Plus, there is also a built-in fill light to help you take high quality pictures even in low light&dark settings, making this the perfect camera for all indoors/outdoors situations.
  • Long-Lasting Battery Life & 16X Digital Zoom :This point and shoot camera will retain its battery charge even after long use. The controls and functions are easy to operate making this the perfect choice for children, teens and younger. This kids camera supports 16x digital zoom, you can zoom in or out the subject by pressing the W/T button for taking still photos to zoom in or out on distant objects and capture all the details you need.
  • Multifunctional & Portable Digital Camera: This cheap digital camera is slim enough to fit in your pocket. You'll easily be able to take it with you on all your indoor/outdoor activities and adventures and ideal for beginners, children and teenagers. This kids digital camera is equipped with 20 filters, anti-shaking, self-timer, continuous shooting, date stamp, time-lapse recording, smile capture, internal MIC and speaker (recording sound videos), great for your daily photography needs.
  • WEBCAM & PAUSE FUNCTION : More than just a FHD 1080p digital camera, it also works as a webcam for video calls and vlogging. Connect the camera to the computer, press shutter and power button at the same time and the camera will automatically turn on webcam mode for all your video calling and live streaming needs. The pause function allows you to pause when seeing playback videos.
  • A Must Have Photography Device : This digital camera with SD card made from high-quality materials, this retro camera is safe and durable. Perfect for all ages to develop & improve their photographic abilities and observation skills. Our dedicated and experienced 24/7 support team is available for all after purchase troubleshooting, questions and technical help.
  • Allow only expected URL schemes, such as HTTPS where appropriate, and enforce an allowlist of permitted hosts. Validate redirects and resolved destinations too, so a permitted hostname cannot be used to reach restricted internal services.
  • Do not accept arbitrary local paths as sources. Disable local-file access where possible; if a workflow requires it, use the narrowest permitted directories.
  • Use a process deadline, limit concurrent renders, and apply operating-system or container resource limits appropriate to the service.
  • Run the converter with only the filesystem permissions it needs and isolate it from sensitive files and internal network services.
  • Keep cookies and custom headers out of logs, error responses, and command diagnostics exposed to callers.
  • Use argument slices, never build a shell command string from user input.

Troubleshoot blank, missing, or incorrect images

Symptom Likely cause What to check or change
exec: "wkhtmltoimage": executable file not found in $PATH The executable is missing or not on the service user’s path. Install/package the binary, configure its absolute path, and test as the same user that runs Go.
The process exits with an error Unsupported flags, inaccessible output path, or document/media load failure. Capture stderr, compare flags with --extended-help, verify directory permissions, and review load-error settings.
The output is blank or only partly populated The URL is unreachable, scripts are disabled or unfinished, or resources fail to load. Check network/TLS access from the deployment host, JavaScript settings and wait behavior, and stderr diagnostics.
The layout differs from the expected page Viewport width or legacy renderer compatibility. Adjust --width, inspect the installed version, and test the page’s CSS and browser APIs against QtWebKit.
Images, stylesheets, or local assets are absent Asset URLs cannot be reached, paths are inaccessible, or local-file access is restricted. Verify resource reachability and permissions; grant only narrowly scoped local access if the use case requires it.
The Go request never returns promptly The page or resource load is stalled or slow. Use exec.CommandContext with a deadline, inspect stderr, and set load behavior and resource limits deliberately.
File exists but cannot be opened as expected The process may have produced an empty or unexpected-format file. Check file size, configured format, extension, and actual output with the downstream consumer.

Diagnose in this order: executable and version, URL reachability and TLS, output permissions, script timing, viewport, then stderr and the file itself. Test representative pages in the actual deployment environment; compatibility cannot be inferred from a successful capture of a different site.

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

Alternative: use ScreenshotNeo when you do not want to deploy a renderer

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Instead of installing and operating a local browser renderer, your Go application can make one HTTP GET request and save the returned image. Its clean-capture steps accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses indicate the page verdict and billing status in headers.

Go example using the ScreenshotNeo API

Create an API key, then put it in an environment variable rather than hard-coding it in source. This example requests a WebP capture and writes the response body to a file. The API documentation is at ScreenshotNeo docs.

package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"time"
)

func main() {
	key := os.Getenv("SCREENSHOTNEO_ACCESS_KEY")
	if key == "" {
		fmt.Fprintln(os.Stderr, "set SCREENSHOTNEO_ACCESS_KEY")
		os.Exit(2)
	}

	endpoint, err := url.Parse("https://api.screenshotneo.com/v1/shot")
	if err != nil {
		panic(err)
	}
	q := endpoint.Query()
	q.Set("access_key", key)
	q.Set("url", "https://example.com")
	endpoint.RawQuery = q.Encode()

	client := &http.Client{Timeout: 90 * time.Second}
	resp, err := client.Get(endpoint.String())
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		fmt.Fprintf(os.Stderr, "ScreenshotNeo returned HTTP %sn", resp.Status)
		os.Exit(1)
	}
	out, err := os.Create("shot.webp")
	if err != nil {
		panic(err)
	}
	if _, err := io.Copy(out, resp.Body); err != nil {
		out.Close()
		panic(err)
	}
	if err := out.Close(); err != nil {
		panic(err)
	}
}

Use a maintained HTTP client and handle non-success responses before treating the body as an image. The API also supports PNG, JPEG, PDF, custom CSS and JavaScript, selector capture, viewport and device settings, request blocking, caching, signed image links, asynchronous jobs, bulk capture, and usage reporting; consult the current documentation for parameter names and limits.

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

Cost and agent workflow

ScreenshotNeo’s listed monthly plans are Free: 1,000 shots with no card; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; and Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. The MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

Rank #4
Kodak PIXPRO FZ55 16MP Compact Digital Camera, 5X Optical Zoom, Red
  • 16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting
  • Optical Zoom: 5x optical zoom with a 28mm wide angle lens for flexible framing indoors or outdoors
  • Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
  • Memory Support: Works with Class 10 SD, SDHC, or SDXC cards up to 512GB
  • Rechargeable Battery: Included LB-012 lithium-ion battery charges in the camera over USB with the supplied adapter in about 2 hours; charge it for at least 4 hours before first use to maximize battery life

To try the API without a card, sign up for ScreenshotNeo’s free plan.

Frequently Asked Questions

Can wkhtmltoimage capture a local HTML file instead of a URL?

Yes. Its input may be a local HTML file or a URL; ensure the process can read the file and that local resource access is configured safely.

Does calling wkhtmltoimage from Go require a Go wrapper library?

No. Go’s standard os/exec package can start the separate executable directly.

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

Can I use wkhtmltoimage for pages requiring a login?

The command reference documents cookie and custom-header options, but authentication flows may not work like they do in a current browser. Protect credentials and verify the exact page and installed build.

Quick Recap

SaleBestseller No. 1
Kodak PIXPRO FZ45 16MP Compact Digital Camera, 4X Optical Zoom, AA, Black
Kodak PIXPRO FZ45 16MP Compact Digital Camera, 4X Optical Zoom, AA, Black
16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting; Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
$99.99
SaleBestseller No. 2
Kodak PIXPRO FZ55 16MP Compact Digital Camera, 5X Optical Zoom, Black
Kodak PIXPRO FZ55 16MP Compact Digital Camera, 5X Optical Zoom, Black
16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting; Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
$139.99
Bestseller No. 4
Kodak PIXPRO FZ55 16MP Compact Digital Camera, 5X Optical Zoom, Red
Kodak PIXPRO FZ55 16MP Compact Digital Camera, 5X Optical Zoom, Red
16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting; Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
$139.99

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.