Go net/http No CGo

Screenshot API for Go

Capture website screenshots in Go using only the standard library. No chromedp, no CGo, no Chrome dependency. Pure HTTP.

Get Free API Key →

Quick Start

package main

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

func main() {
    params := url.Values{}
    params.Set("url", "https://example.com")
    params.Set("key", os.Getenv("GRABSHOT_API_KEY"))

    resp, err := http.Get("https://grabshot.dev/v1/screenshot?" + params.Encode())
    if err != nil {
        fmt.Fprintf(os.Stderr, "request failed: %v\n", err)
        os.Exit(1)
    }
    defer resp.Body.Close()

    f, _ := os.Create("screenshot.png")
    defer f.Close()
    io.Copy(f, resp.Body)
    fmt.Println("Saved screenshot.png")
}

Reusable Client

package grabshot

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

type Client struct {
    APIKey string
    HTTP   *http.Client
}

type Options struct {
    Width       string
    Height      string
    Format      string
    FullPage    bool
    DarkMode    bool
    DeviceFrame string
}

func NewClient(apiKey string) *Client {
    return &Client{
        APIKey: apiKey,
        HTTP:   &http.Client{Timeout: 30 * time.Second},
    }
}

func (c *Client) Capture(targetURL string, opts *Options) ([]byte, error) {
    params := url.Values{}
    params.Set("url", targetURL)
    params.Set("key", c.APIKey)

    if opts != nil {
        if opts.Width != "" { params.Set("width", opts.Width) }
        if opts.Height != "" { params.Set("height", opts.Height) }
        if opts.Format != "" { params.Set("format", opts.Format) }
        if opts.FullPage { params.Set("fullPage", "true") }
        if opts.DarkMode { params.Set("darkMode", "true") }
        if opts.DeviceFrame != "" { params.Set("deviceFrame", opts.DeviceFrame) }
    }

    resp, err := c.HTTP.Get("https://grabshot.dev/v1/screenshot?" + params.Encode())
    if err != nil {
        return nil, fmt.Errorf("request failed: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != 200 {
        body, _ := io.ReadAll(resp.Body)
        return nil, fmt.Errorf("API error %d: %s", resp.StatusCode, body)
    }

    return io.ReadAll(resp.Body)
}

// Usage:
// client := grabshot.NewClient(os.Getenv("GRABSHOT_API_KEY"))
// img, err := client.Capture("https://github.com", &grabshot.Options{
//     Width: "1920", FullPage: true, DeviceFrame: "macbook",
// })

Gin Handler

import "github.com/gin-gonic/gin"

func screenshotHandler(c *gin.Context) {
    targetURL := c.Query("url")
    if targetURL == "" {
        c.JSON(400, gin.H{"error": "url required"})
        return
    }

    client := NewClient(os.Getenv("GRABSHOT_API_KEY"))
    img, err := client.Capture(targetURL, nil)
    if err != nil {
        c.JSON(500, gin.H{"error": err.Error()})
        return
    }

    c.Data(200, "image/png", img)
}

Pricing

Free: 25 screenshots/month. No credit card.

Starter: $9/mo for 2,500 screenshots.

Pro: $29/mo for 10,000 screenshots with AI cleanup.

Start Free — No Credit Card →