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.
Getting Started
Get your API key and capture your first screenshot in under a minute.
API Reference
Full endpoint documentation with parameters and response examples.
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:
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
/v1/Capture a screenshot of the specified URL. Returns a JSON response with the screenshot URL and metadata.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Required | - | The URL to screenshot. Must be a valid HTTP or HTTPS URL. |
width | integer | Optional | 1440 | Viewport width in pixels. Range: 320-3840. |
height | integer | Optional | 900 | Viewport height in pixels. Range: 240-2160. |
fullpage | boolean | Optional | false | Capture the full scrollable page, not just the viewport. |
format | string | Optional | png | Output format. Accepted values: "png", "jpeg". |
quality | integer | Optional | 80 | JPEG quality. Range: 1-100. Ignored for PNG. |
delay | integer | Optional | 0 | Wait time in milliseconds before capture. Max: 30000 (Pro), 5000 (Free). |
selector | string | Optional | - | CSS selector to capture a specific element instead of the full page. |
scale | number | Optional | 1 | Device scale factor. Range: 0.5-3. Use 2 for retina screenshots. |
Response
Successful requests return a JSON object with the following fields:
{
"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
| Code | Meaning | Description |
|---|---|---|
400 | Bad Request | Missing or invalid parameters. Check the url parameter. |
401 | Unauthorized | Missing or invalid API key. |
403 | Forbidden | API key does not have access to the requested feature. |
429 | Too Many Requests | Rate limit exceeded. Check the Retry-After header. |
500 | Server Error | Internal server error. Retry the request after a few seconds. |
504 | Timeout | The target page took too long to load. |
{
"status": "error",
"code": 400,
"message": "Missing required parameter: url"
}Rate Limits
Rate limits depend on your plan:
| Plan | Monthly Limit | Requests/Minute | Max Delay |
|---|---|---|---|
| Free | 100 | 5 | 5,000ms |
| Pro | 10,000 | 60 | 30,000ms |
| Enterprise | Custom | Custom | 60,000ms |
Rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
Code Examples
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
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
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)
}