Website Screenshot API
for Go
Go's standard library makes HTTP calls trivial, which means calling a screenshot API is about 15 lines of code. If you need local browser control, chromedp and Rod are your options. Here's working code for all three.
1. GrabShot API (Standard Library Only)
Zero dependencies. Just net/http and os.
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
)
func screenshot(targetURL, output string) error {
apiKey := "YOUR_API_KEY" // Free at grabshot.dev
params := url.Values{
"url": {targetURL},
"format": {"webp"},
"width": {"1440"},
"apiKey": {apiKey},
}
resp, err := http.Get("https://grabshot.dev/v1/screenshot?" + params.Encode())
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("API error %d: %s", resp.StatusCode, body)
}
f, err := os.Create(output)
if err != nil {
return err
}
defer f.Close()
written, err := io.Copy(f, resp.Body)
if err != nil {
return err
}
fmt.Printf("Saved %d bytes to %s\n", written, output)
return nil
}
func main() {
if err := screenshot("https://github.com", "github.webp"); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
Pros: No dependencies, compiles to a single binary, works on any platform.
Cons: Can't interact with pages (click, scroll).
2. chromedp (Headless Chrome)
chromedp drives Chrome via the DevTools Protocol. Full browser control in Go.
go get github.com/chromedp/chromedp
package main
import (
"context"
"os"
"time"
"github.com/chromedp/chromedp"
)
func main() {
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
defer cancel()
var buf []byte
err := chromedp.Run(ctx,
chromedp.EmulateViewport(1440, 900),
chromedp.Navigate("https://github.com"),
chromedp.WaitReady("body"),
chromedp.CaptureScreenshot(&buf),
)
if err != nil {
panic(err)
}
os.WriteFile("github.png", buf, 0644)
}
Pros: Full browser control, can interact with pages, good Go API.
Cons: Needs Chrome installed. High memory usage. Complex error handling for production use.
3. Rod
Rod is a higher-level alternative to chromedp with auto-download of Chrome.
go get github.com/go-rod/rod
package main
import "github.com/go-rod/rod"
func main() {
page := rod.New().MustConnect().MustPage("https://github.com")
page.MustWaitStable()
page.MustScreenshot("github.png")
}
Pros: Simpler API than chromedp, auto-manages browser binary.
Cons: Same RAM/Chrome requirements. "Must" methods panic on error (use non-Must for production).
Concurrent Screenshots
Go's goroutines make batch screenshots easy with the API approach:
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"sync"
)
func main() {
urls := []string{
"https://github.com",
"https://stripe.com",
"https://vercel.com",
"https://linear.app",
}
apiKey := "YOUR_API_KEY"
var wg sync.WaitGroup
for _, u := range urls {
wg.Add(1)
go func(targetURL string) {
defer wg.Done()
params := url.Values{
"url": {targetURL}, "format": {"webp"},
"width": {"1440"}, "apiKey": {apiKey},
}
resp, err := http.Get("https://grabshot.dev/v1/screenshot?" + params.Encode())
if err != nil {
fmt.Printf("Error for %s: %v\n", targetURL, err)
return
}
defer resp.Body.Close()
// Domain as filename
name := strings.ReplaceAll(strings.TrimPrefix(
strings.TrimPrefix(targetURL, "https://"), "http://"), ".", "-")
f, _ := os.Create(name + ".webp")
io.Copy(f, resp.Body)
f.Close()
fmt.Printf("Done: %s\n", targetURL)
}(u)
}
wg.Wait()
fmt.Println("All screenshots captured")
}
Comparison
| Feature | GrabShot API | chromedp | Rod |
|---|---|---|---|
| Dependencies | None (stdlib) | Chrome + module | Auto-downloads Chrome |
| Binary size impact | ~0 | ~5MB | ~5MB |
| RAM per screenshot | ~1MB | 200-400MB | 200-400MB |
| Page interaction | No | Full | Full |
| Docker friendly | Yes (tiny image) | Needs Chrome layer | Auto-downloads |
See it in action
Try GrabShot right now — paste any URL and get a screenshot instantly. No signup needed.
Try Free Screenshot Tool →