Screenshot -- Go Code Examples
HTTP-based examples for integrating the Nodium Screenshot API with Go using the net/http standard library. No third-party SDK required.
Basic Screenshot (GET)
The simplest way to capture a screenshot using query parameters.
go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
)
func main() {
params := url.Values{}
params.Set("url", "https://example.com")
params.Set("format", "png")
params.Set("viewport_width", "1280")
params.Set("viewport_height", "1024")
reqURL := "https://api.nodium.io/api/v1/screenshot/take?" + params.Encode()
req, err := http.NewRequest("GET", reqURL, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create request: %v\n", err)
os.Exit(1)
}
req.Header.Set("X-Access-Key", "YOUR_API_KEY")
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
fmt.Fprintf(os.Stderr, "API error (%d): %s\n", resp.StatusCode, body)
os.Exit(1)
}
file, err := os.Create("screenshot.png")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create file: %v\n", err)
os.Exit(1)
}
defer file.Close()
written, err := io.Copy(file, resp.Body)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write file: %v\n", err)
os.Exit(1)
}
fmt.Printf("Screenshot saved (%d bytes)\n", written)
}POST with JSON Body
Use POST for more complex configurations with a JSON request body.
go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type ScreenshotRequest struct {
URL string `json:"url"`
Format string `json:"format"`
ViewportWidth int `json:"viewport_width"`
ViewportHeight int `json:"viewport_height"`
FullPage bool `json:"full_page"`
ImageQuality int `json:"image_quality"`
BlockAds bool `json:"block_ads"`
Delay int `json:"delay,omitempty"`
}
type APIError struct {
ErrorCode string `json:"error_code"`
Message string `json:"message"`
HTTPStatusCode int `json:"http_status_code"`
}
func takeScreenshot(params ScreenshotRequest, apiKey string) ([]byte, error) {
body, err := json.Marshal(params)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
req, err := http.NewRequest("POST", "https://api.nodium.io/api/v1/screenshot/take", bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Access-Key", apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
var apiErr APIError
if err := json.Unmarshal(respBody, &apiErr); err == nil {
return nil, fmt.Errorf("API error [%s]: %s", apiErr.ErrorCode, apiErr.Message)
}
return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, respBody)
}
return respBody, nil
}
func main() {
data, err := takeScreenshot(ScreenshotRequest{
URL: "https://example.com",
Format: "png",
ViewportWidth: 1440,
ViewportHeight: 900,
FullPage: true,
ImageQuality: 90,
BlockAds: true,
}, "YOUR_API_KEY")
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
if err := os.WriteFile("screenshot.png", data, 0644); err != nil {
fmt.Fprintf(os.Stderr, "Failed to save file: %v\n", err)
os.Exit(1)
}
fmt.Printf("Screenshot saved (%d bytes)\n", len(data))
}Error Handling with Retries
Implement exponential backoff for retryable server errors.
go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"math"
"net/http"
"os"
"time"
)
func takeScreenshotWithRetry(payload []byte, apiKey string, maxRetries int) ([]byte, http.Header, error) {
client := &http.Client{Timeout: 60 * time.Second}
for attempt := 0; attempt <= maxRetries; attempt++ {
req, err := http.NewRequest("POST", "https://api.nodium.io/api/v1/screenshot/take", bytes.NewReader(payload))
if err != nil {
return nil, nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Access-Key", apiKey)
resp, err := client.Do(req)
if err != nil {
if attempt < maxRetries {
delay := time.Duration(math.Pow(2, float64(attempt))) * time.Second
time.Sleep(delay)
continue
}
return nil, nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, nil, err
}
if resp.StatusCode == http.StatusOK {
return body, resp.Header, nil
}
// Do not retry client errors (4xx)
if resp.StatusCode >= 400 && resp.StatusCode < 500 {
var apiErr struct {
ErrorCode string `json:"error_code"`
Message string `json:"message"`
}
json.Unmarshal(body, &apiErr)
return nil, nil, fmt.Errorf("[%s] %s", apiErr.ErrorCode, apiErr.Message)
}
// Retry server errors (5xx) with exponential backoff
if attempt < maxRetries {
delay := time.Duration(math.Pow(2, float64(attempt))) * time.Second
fmt.Printf("Retry %d/%d after %v...\n", attempt+1, maxRetries, delay)
time.Sleep(delay)
}
}
return nil, nil, fmt.Errorf("max retries (%d) exceeded", maxRetries)
}
func main() {
payload, _ := json.Marshal(map[string]any{
"url": "https://example.com",
"format": "png",
"viewport_width": 1280,
"viewport_height": 1024,
})
data, headers, err := takeScreenshotWithRetry(payload, "YOUR_API_KEY", 3)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
os.WriteFile("screenshot.png", data, 0644)
fmt.Printf("Saved (%s bytes, rendered in %ss)\n",
headers.Get("X-Nodium-Size-Bytes"),
headers.Get("X-Nodium-Rendering-Seconds"),
)
}Concurrent Screenshots with Goroutines
Capture multiple URLs concurrently using goroutines and channels.
go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"sync"
)
type CaptureResult struct {
URL string
Filename string
Size int
Err error
}
func captureURL(client *http.Client, apiKey, targetURL, filename string) CaptureResult {
payload, _ := json.Marshal(map[string]any{
"url": targetURL,
"format": "png",
"viewport_width": 1280,
"viewport_height": 1024,
})
req, err := http.NewRequest("POST", "https://api.nodium.io/api/v1/screenshot/take", bytes.NewReader(payload))
if err != nil {
return CaptureResult{URL: targetURL, Err: err}
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Access-Key", apiKey)
resp, err := client.Do(req)
if err != nil {
return CaptureResult{URL: targetURL, Err: err}
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return CaptureResult{URL: targetURL, Err: err}
}
if resp.StatusCode != http.StatusOK {
return CaptureResult{URL: targetURL, Err: fmt.Errorf("HTTP %d: %s", resp.StatusCode, body)}
}
if err := os.WriteFile(filename, body, 0644); err != nil {
return CaptureResult{URL: targetURL, Err: err}
}
return CaptureResult{URL: targetURL, Filename: filename, Size: len(body)}
}
func main() {
apiKey := "YOUR_API_KEY"
client := &http.Client{}
urls := []string{
"https://example.com",
"https://example.org",
"https://example.net",
"https://httpbin.org/html",
}
var wg sync.WaitGroup
results := make(chan CaptureResult, len(urls))
for i, u := range urls {
wg.Add(1)
go func(index int, targetURL string) {
defer wg.Done()
filename := fmt.Sprintf("screenshot-%d.png", index)
results <- captureURL(client, apiKey, targetURL, filename)
}(i, u)
}
go func() {
wg.Wait()
close(results)
}()
for result := range results {
if result.Err != nil {
fmt.Printf("[FAIL] %s: %v\n", result.URL, result.Err)
} else {
fmt.Printf("[OK] %s -> %s (%d bytes)\n", result.URL, result.Filename, result.Size)
}
}
}Signed URL Generation
Generate a signed URL by computing an HMAC-SHA256 signature over the query parameters.
go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
func generateSignedURL(apiKey, secretKey string, params map[string]string, expiresIn time.Duration) string {
// Set expiration timestamp
expires := time.Now().Add(expiresIn).Unix()
params["access_key"] = apiKey
params["expires"] = strconv.FormatInt(expires, 10)
// Sort parameter keys for consistent signing
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
// Build the string to sign
var parts []string
for _, k := range keys {
parts = append(parts, k+"="+params[k])
}
stringToSign := strings.Join(parts, "&")
// Compute HMAC-SHA256 signature
mac := hmac.New(sha256.New, []byte(secretKey))
mac.Write([]byte(stringToSign))
signature := hex.EncodeToString(mac.Sum(nil))
// Build the final URL
query := url.Values{}
for _, k := range keys {
query.Set(k, params[k])
}
query.Set("signature", signature)
return "https://api.nodium.io/api/v1/screenshot/take?" + query.Encode()
}
func main() {
signedURL := generateSignedURL(
"YOUR_API_KEY",
"YOUR_SECRET_KEY",
map[string]string{
"url": "https://example.com",
"format": "png",
"viewport_width": "1280",
"viewport_height": "1024",
},
1*time.Hour,
)
fmt.Println(signedURL)
}JSON Response Mode
Request a JSON response instead of raw binary to get the screenshot URL and metadata.
go
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
type JSONResponse struct {
ScreenshotURL string `json:"screenshot_url"`
CacheURL string `json:"cache_url"`
Metadata struct {
ImageSize struct {
Width int `json:"width"`
Height int `json:"height"`
} `json:"image_size"`
PageTitle string `json:"page_title"`
} `json:"metadata"`
}
func main() {
payload, _ := json.Marshal(map[string]any{
"url": "https://example.com",
"format": "png",
"response_type": "json",
})
req, _ := http.NewRequest("POST", "https://api.nodium.io/api/v1/screenshot/take", bytes.NewReader(payload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Access-Key", "YOUR_API_KEY")
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Fprintf(os.Stderr, "Request failed: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
var result JSONResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
fmt.Fprintf(os.Stderr, "Failed to decode response: %v\n", err)
os.Exit(1)
}
fmt.Printf("Screenshot URL: %s\n", result.ScreenshotURL)
fmt.Printf("Page title: %s\n", result.Metadata.PageTitle)
fmt.Printf("Dimensions: %dx%d\n", result.Metadata.ImageSize.Width, result.Metadata.ImageSize.Height)
}Next Steps
- API Reference -- Complete reference for all 145+ parameters
- Guides -- Practical guides for common use cases
- Getting Started -- Quick intro and cURL examples