Take screenshots, scrape content, and generate PDFs from Go without running a browser. Complete examples using net/http, goroutines for batch processing, and the official SnapAPI Go SDK.
Get Free API Key — 200 calls/moGo is a natural fit for API-driven workflows. Its standard library net/http package handles HTTP calls cleanly, goroutines make concurrent batch processing trivial, and the type system catches integration errors at compile time rather than runtime. These strengths apply directly to screenshot and web scraping workflows. Instead of embedding a Chromium binary in your Go binary (which is effectively impossible) or running a sidecar Node.js process to execute Puppeteer, you call SnapAPI’s REST endpoint from your Go service using standard net/http. The result is a PNG, PDF, clean Markdown, or typed JSON that you can process with Go’s excellent concurrency primitives.
Go microservices that handle screenshots as part of a larger pipeline benefit particularly from this pattern. A Go service that processes incoming URL webhooks, captures screenshots, uploads to S3, and notifies downstream services can handle hundreds of concurrent requests without the memory overhead of running browser instances. Each goroutine makes one HTTP call to SnapAPI and processes the response — the entire workflow is non-blocking and scales horizontally without additional infrastructure.
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
)
func takeScreenshot(targetURL, apiKey string) ([]byte, error) {
params := url.Values{}
params.Set("url", targetURL)
params.Set("width", "1280")
params.Set("format", "png")
req, err := http.NewRequest("GET",
"https://api.snapapi.pics/v1/screenshot?"+params.Encode(), nil)
if err != nil {
return nil, err
}
req.Header.Set("X-API-Key", apiKey)
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("snapapi: HTTP %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
func main() {
png, err := takeScreenshot("https://example.com", os.Getenv("SNAP_API_KEY"))
if err != nil {
panic(err)
}
os.WriteFile("screenshot.png", png, 0644)
fmt.Printf("Saved %d bytes\n", len(png))
}Go’s concurrency model makes batch screenshot processing elegant. Use a semaphore channel to cap concurrency and a WaitGroup to wait for all goroutines to finish. This pattern processes hundreds of URLs with controlled parallelism and aggregates results safely:
package main
import (
"fmt"
"sync"
"os"
)
type Result struct {
URL string
Bytes []byte
Err error
}
func batchScreenshots(urls []string, apiKey string, concurrency int) []Result {
sem := make(chan struct{}, concurrency)
results := make([]Result, len(urls))
var wg sync.WaitGroup
for i, u := range urls {
wg.Add(1)
go func(idx int, targetURL string) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
bytes, err := takeScreenshot(targetURL, apiKey)
results[idx] = Result{URL: targetURL, Bytes: bytes, Err: err}
}(i, u)
}
wg.Wait()
return results
}
func main() {
urls := []string{
"https://example.com",
"https://github.com",
"https://golang.org",
}
results := batchScreenshots(urls, os.Getenv("SNAP_API_KEY"), 5)
for _, r := range results {
if r.Err != nil {
fmt.Printf("FAIL %s: %v\n", r.URL, r.Err)
} else {
fmt.Printf("OK %s: %d bytes\n", r.URL, len(r.Bytes))
}
}
}SnapAPI’s scrape endpoint returns clean Markdown from any URL, and the extract endpoint returns typed JSON based on a schema you define. Both are straightforward to call from Go. The scrape response is a JSON object with a content field containing the Markdown. The extract response is a JSON object matching your schema. Go’s encoding/json package handles both cleanly:
type ScrapeResponse struct {
Content string `json:"content"`
}
type ProductSchema struct {
Name string `json:"name"`
Price float64 `json:"price"`
Currency string `json:"currency"`
InStock bool `json:"in_stock"`
Rating float64 `json:"rating"`
Description string `json:"description"`
}
func scrapeURL(targetURL, apiKey string) (string, error) {
params := url.Values{"url": {targetURL}, "format": {"markdown"}}
req, _ := http.NewRequest("GET", "https://api.snapapi.pics/v1/scrape?"+params.Encode(), nil)
req.Header.Set("X-API-Key", apiKey)
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Do(req)
if err != nil { return "", err }
defer resp.Body.Close()
var result ScrapeResponse
json.NewDecoder(resp.Body).Decode(&result)
return result.Content, nil
}Generating PDFs from Go traditionally requires cgo-based bindings to wkhtmltopdf, embedding a binary in your Docker image, or calling a Node.js subprocess to run a headless browser. SnapAPI eliminates all of these approaches. Send a POST request with a URL or raw HTML string and receive PDF bytes in the response body. No C bindings, no subprocess management, no system dependencies:
func generatePDF(targetURL, apiKey string) ([]byte, error) {
body, _ := json.Marshal(map[string]string{"url": targetURL, "format": "A4"})
req, _ := http.NewRequest("POST", "https://api.snapapi.pics/v1/pdf",
bytes.NewReader(body))
req.Header.Set("X-API-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil { return nil, err }
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("pdf error: %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}Production Go services use context.Context for request lifecycle management. SnapAPI calls should respect the parent context so they cancel cleanly when a request times out or the client disconnects. Wrap your API calls with http.NewRequestWithContext to propagate cancellation correctly:
func takeScreenshotCtx(ctx context.Context, targetURL, apiKey string) ([]byte, error) {
params := url.Values{"url": {targetURL}, "width": {"1280"}, "format": {"png"}}
req, err := http.NewRequestWithContext(ctx, "GET",
"https://api.snapapi.pics/v1/screenshot?"+params.Encode(), nil)
if err != nil { return nil, err }
req.Header.Set("X-API-Key", apiKey)
return httpDo(req)
}Yes. The official SnapAPI Go SDK is at github.com/Sleywill/snapapi-go. Install with go get github.com/Sleywill/snapapi-go. It wraps all four endpoints with typed structs, automatic retries with exponential backoff, and context support.
Use io.Pipe to connect the HTTP response body directly to an S3 upload. This keeps memory usage constant regardless of file size. The S3 SDK PutObject accepts an io.Reader, so you can pass resp.Body directly after checking the status code.
Set http.Client.Timeout to 30 seconds for standard pages and 60 seconds for complex SPAs or PDF generation. If you use context.WithTimeout, set it slightly longer than the HTTP client timeout so the context cancellation is the last resort, not the first trigger.
Free tier: 200 calls/month. No browser install. Pure HTTP, works in any Go service.
Get Your Free API KeyA standalone Go screenshot microservice is a common architecture for teams that need screenshot generation from multiple services. The microservice exposes an HTTP endpoint that accepts a URL, calls SnapAPI, and returns the image. Other services in the platform call the screenshot service rather than calling SnapAPI directly, which centralizes API key management, adds a caching layer, and provides a single point for rate limiting and monitoring.
The service typically uses a Redis cache keyed by URL hash with a configurable TTL. On a cache hit, it returns the stored image bytes immediately with a Cache-Hit header. On a cache miss, it calls SnapAPI, stores the result in Redis, and returns it. The cache dramatically reduces API usage and latency for repeated requests. For website monitoring use cases where the same URL is checked hourly, the effective SnapAPI call rate is one per cache TTL period rather than one per check.
Go’s standard library provides everything needed to build this service: net/http for the HTTP server, sync.Map or a Redis client for caching, context for request lifecycle management, and encoding/json for request and response handling. The entire service is typically under two hundred lines of idiomatic Go and compiles to a single binary with no runtime dependencies.
Production Go services need structured error handling and observability for external API calls. Wrap SnapAPI calls with prometheus metrics to track request duration, error rates, and response size. Use slog or zerolog for structured logging that includes the target URL, response time, HTTP status code, and any error details. This makes debugging slow or failing screenshot requests straightforward without requiring a debug session.
For retry logic, implement exponential backoff with jitter for 5xx responses and network errors. Do not retry 4xx errors from SnapAPI as they indicate a problem with the request parameters. The standard Go pattern uses a ticker-based retry loop with context cancellation so retries respect the parent request deadline. Limit retries to three attempts with delays of one, two, and four seconds to avoid creating thundering herd issues during API degradation events.
SnapAPI’s free tier includes two hundred API calls per month across all four endpoints. Sign up at snapapi.pics, copy your API key from the dashboard, and make your first call in under five minutes. The documentation covers all parameters for each endpoint, response formats, error codes, and code examples in JavaScript, Python, Go, PHP, Swift, and Kotlin. The Playground page lets you test any endpoint directly in the browser without writing any code, which is useful for validating parameters before integrating into your codebase.
Paid plans start at nineteen dollars per month for five thousand calls and seventy-nine dollars per month for fifty thousand calls. Custom plans with higher volume, dedicated infrastructure, and SLA guarantees are available for teams with specific requirements. Support is available via the in-app chat widget and email, with typical response times under one business day. The public status page at status.snapapi.pics shows real-time uptime, historical incident data, and average response times for each endpoint.