Language

Go Screenshot API

High-performance screenshot capture with Go using the standard net/http package. Build fast, concurrent screenshot services with goroutines and channels. Includes examples for parallel batch capture, context-based timeouts, streaming responses to disk, and deploying as a microservice.

Quick summaryGo capture via net/http. Excellent fit for high-concurrency batch workers. Key patterns: context.Context for cancellation, a semaphore for concurrency control, and io.Copy for streaming.

Quick Start

1

Install dependencies

No external dependencies needed — Go's standard library net/http handles all HTTP requests.

2

Get your API key

Sign up for Screenshotly and get your API key from the dashboard.

3

Copy the code example

Use our Go code example as a starting point.

4

Customize and integrate

Modify the code to fit your specific use case and requirements.

Code Example

// Go
package main

import (
    "bytes"
    "encoding/json"
    "io"
    "net/http"
    "os"
)

func captureScreenshot(url, outputPath string) error {
    payload, _ := json.Marshal(map[string]interface{}{
        "url":    url,
        "device": "desktop",
        "format": "png",
    })

    req, _ := http.NewRequest("POST", 
        "https://api.screenshotly.app/screenshot", 
        bytes.NewBuffer(payload))
    
    req.Header.Set("Authorization", "Bearer "+os.Getenv("SCREENSHOTLY_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    
    data, _ := io.ReadAll(resp.Body)
    return os.WriteFile(outputPath, data, 0644)
}

When to Use Go with Screenshotly

Use the Go integration for high-throughput microservices, CLI tools, and concurrent screenshot pipelines. Go excels at processing thousands of captures per minute with minimal memory overhead thanks to goroutines and efficient streaming I/O.

Go Best Practices

Use a semaphore pattern (buffered channel of size N) to limit concurrent goroutines to your plan's rate limit.

Always pass context.WithTimeout to http.NewRequestWithContext — this prevents goroutine leaks on slow or hung API responses.

Use io.Copy(file, resp.Body) to stream directly to disk instead of io.ReadAll, especially for full-page screenshots.

Build a reusable http.Client with custom Transport settings: MaxIdleConnsPerHost=10, IdleConnTimeout=90s for connection pooling.

Go: Production Notes

Go is the highest-throughput runtime for screenshot workloads because goroutines plus a tuned HTTP transport gives thousands of concurrent requests with predictable memory. The foot-guns are forgetting to reuse `http.Client` (each new client creates its own connection pool) and not bounding concurrency with a semaphore.

For batch workloads: a worker pool sized to your rate-limit budget, `sync.WaitGroup` for orderly shutdown, and a `chan struct{}` semaphore capping parallel captures at 5–10. Bind captures to `context.WithCancel()` tied to the consumer's lifecycle so in-flight captures abort cleanly on shutdown.

For the response body, use `io.Copy(dst, resp.Body)` to stream directly to S3 or disk. `io.ReadAll(resp.Body)` buffers the entire image in memory — at 8 MB per capture × 50 concurrent = 400 MB of avoidable RAM.

Error Handling Recipes

Concrete strategies for each failure mode. Do not silently swallow errors — surface them to your monitoring so the pipeline is observable.

HTTP 429

Read Retry-After header, sleep, retry up to 3 times. Centralize in a helper function.

if resp.StatusCode == 429 {
    retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
    time.Sleep(time.Duration(retryAfter) * time.Second)
    return capture(ctx, url, attempt+1)
}

context.DeadlineExceeded

Happens when the parent ctx timeout fires. Propagate up; do not retry with a fresh context — the caller set the deadline intentionally.

net.OpError (connection reset)

Retry once with a fresh connection. Usually indicates a transient blip.

Production Hardening Checklist

The difference between dev code and prod code. Work through these before putting Go captures on a critical path.

  • Single http.Client reused across all captures, tuned with Transport.MaxIdleConnsPerHost.
  • context.Context propagated through every capture call.
  • Worker pool with semaphore bounds parallel captures (5–10 typical).
  • io.Copy streams response body — never io.ReadAll into memory for large captures.
  • Retry logic uses cenkalti/backoff or similar; not hand-rolled per call site.
  • Graceful shutdown drains in-flight captures before exit.

Rate-Limit Strategy

Use golang.org/x/time/rate.Limiter sized to ~80% of your plan's published rate, shared across goroutines. At rate.Every(time.Second), 10 you get 10 QPS steady-state with a burst of 10. For multi-process deployments, use Redis-backed distributed rate limiting.

When Go isn't the right fit

Go works well for most capture workloads, but these patterns are legitimate reasons to pick a different stack:

  • Your team has limited Go experience and the codebase is primarily Node or Python. The performance win rarely justifies introducing a second language just for capture workloads.
  • You need browser automation beyond pure capture — form filling, OAuth flows, multi-page scraping. chromedp is an option, but a dedicated screenshot API is not.
  • Your organization mandates Windows Server for deployment. Go works but the Chrome/Puppeteer side of any fallback is harder to run on Windows than on Linux.

Want a step-by-step walkthrough?

Read the full Go tutorial →

API Reference

EndpointPOST /api/screenshot
AuthenticationBearer token
Content-Typeapplication/json
View full API docs

Frequently Asked Questions

How do I capture screenshots concurrently in Go?

Use goroutines with a semaphore pattern (buffered channel) to limit concurrent requests. This prevents hitting rate limits while maximizing throughput. A worker pool of 5-10 concurrent captures is a good starting point.

What's the best way to handle errors in Go?

Check resp.StatusCode after each request. Implement retry logic with exponential backoff for 429 and 5xx errors. Use context.WithTimeout to prevent hung requests. Return errors up the call chain rather than logging and continuing.

Can I use Screenshotly in a Go microservice?

Yes. Create a screenshot service with an HTTP handler that accepts URL parameters and returns captured images. Use Go's standard http package or frameworks like Gin/Echo. Store API keys in environment variables.

How do I stream screenshot responses in Go?

Use io.Copy to stream the API response body directly to your HTTP response writer or file, avoiding loading the entire image into memory. This is especially important for full-page screenshots that can be several megabytes.

Start building with Go

Get your API key and start capturing screenshots in minutes.

Other Languages