API Documentation

The SavePage.io API lets you capture screenshots of any website with a single HTTP request. This reference covers authentication, endpoints, parameters, and response formats.

Base URL

All API requests are made to the following base URL:

https://api.savepage.io/v1/

Authentication

Authenticate your requests by including your API key in the Authorization header:

Terminal
bash
curl "https://api.savepage.io/v1/?url=https://example.com" \
  -H "Authorization: Bearer YOUR_API_KEY"

Get a free API key by signing up. Free, no credit card required. 100 screenshots per month.

Endpoints

GET/v1/

Capture a screenshot of the specified URL. Returns a JSON response with the screenshot URL and metadata.

Query Parameters

ParameterTypeRequiredDefaultDescription
urlstringRequired-The URL to screenshot. Must be a valid HTTP or HTTPS URL.
widthintegerOptional1440Viewport width in pixels. Range: 320-3840.
heightintegerOptional900Viewport height in pixels. Range: 240-2160.
fullpagebooleanOptionalfalseCapture the full scrollable page, not just the viewport.
formatstringOptionalpngOutput format. Accepted values: "png", "jpeg".
qualityintegerOptional80JPEG quality. Range: 1-100. Ignored for PNG.
delayintegerOptional0Wait time in milliseconds before capture. Max: 30000 (Pro), 5000 (Free).
selectorstringOptional-CSS selector to capture a specific element instead of the full page.
scalenumberOptional1Device scale factor. Range: 0.5-3. Use 2 for retina screenshots.

Response

Successful requests return a JSON object with the following fields:

200 OK
json
{
  "status": "success",
  "url": "https://example.com",
  "image": "https://cdn.savepage.io/captures/a1b2c3d4.png",
  "width": 1440,
  "height": 900,
  "format": "png",
  "size": 847291,
  "fullpage": false,
  "captured_at": "2026-04-01T12:00:00Z"
}

Error Codes

CodeMeaningDescription
400Bad RequestMissing or invalid parameters. Check the url parameter.
401UnauthorizedMissing or invalid API key.
403ForbiddenAPI key does not have access to the requested feature.
429Too Many RequestsRate limit exceeded. Check the Retry-After header.
500Server ErrorInternal server error. Retry the request after a few seconds.
504TimeoutThe target page took too long to load.
Error Response
json
{
  "status": "error",
  "code": 400,
  "message": "Missing required parameter: url"
}

Rate Limits

Rate limits depend on your plan:

PlanMonthly LimitRequests/MinuteMax Delay
Free10055,000ms
Pro10,0006030,000ms
EnterpriseCustomCustom60,000ms

Rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

Code Examples

Python

screenshot.py
python
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.savepage.io/v1/"

def capture(url, width=1440, height=900, fmt="png", fullpage=False):
    response = requests.get(
        BASE_URL,
        params={
            "url": url,
            "width": width,
            "height": height,
            "format": fmt,
            "fullpage": str(fullpage).lower(),
        },
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    response.raise_for_status()
    return response.json()

# Desktop screenshot
result = capture("https://example.com")
print(f"Screenshot: {result['image']}")

# Mobile screenshot
result = capture("https://example.com", width=375, height=812)
print(f"Mobile: {result['image']}")

# Full page JPEG
result = capture("https://example.com", fmt="jpeg", fullpage=True)
print(f"Full page: {result['image']}")

JavaScript / Node.js

screenshot.js
javascript
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://api.savepage.io/v1/";

async function capture(url, options = {}) {
  const params = new URLSearchParams({
    url,
    width: String(options.width || 1440),
    height: String(options.height || 900),
    format: options.format || "png",
    fullpage: String(options.fullpage || false),
  });

  const response = await fetch(`${BASE_URL}?${params}`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  return response.json();
}

// Desktop screenshot
const result = await capture("https://example.com");
console.log("Screenshot:", result.image);

// Mobile screenshot
const mobile = await capture("https://example.com", {
  width: 375,
  height: 812,
});
console.log("Mobile:", mobile.image);

Go

main.go
go
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
)

type CaptureResponse struct {
    Status     string `json:"status"`
    URL        string `json:"url"`
    Image      string `json:"image"`
    Width      int    `json:"width"`
    Height     int    `json:"height"`
    Format     string `json:"format"`
    Size       int    `json:"size"`
    CapturedAt string `json:"captured_at"`
}

func capture(targetURL, apiKey string) (*CaptureResponse, error) {
    params := url.Values{}
    params.Set("url", targetURL)
    params.Set("width", "1440")
    params.Set("height", "900")
    params.Set("format", "png")

    reqURL := "https://api.savepage.io/v1/?" + params.Encode()
    req, err := http.NewRequest("GET", reqURL, nil)
    if err != nil {
        return nil, err
    }
    req.Header.Set("Authorization", "Bearer "+apiKey)

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    var result CaptureResponse
    json.Unmarshal(body, &result)
    return &result, nil
}

func main() {
    result, _ := capture("https://example.com", "YOUR_API_KEY")
    fmt.Printf("Screenshot: %s\n", result.Image)
}