Code Examples

Copy-paste examples in cURL, JavaScript, Python, and Go.

Basic Screenshot

Capture a simple PNG screenshot of any URL:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://github.com",
    "format": "png"
  }'
const response = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://github.com",
    format: "png",
  }),
});

const data = await response.json();
console.log(data.url); // CDN URL to your screenshot
import requests

response = requests.post(
    "https://api.getsnap.dev/v1/screenshot",
    headers={
        "X-API-Key": "sk_live_YOUR_KEY",
        "Content-Type": "application/json",
    },
    json={
        "url": "https://github.com",
        "format": "png",
    },
)

data = response.json()
print(data["url"])  # CDN URL to your screenshot
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]interface{}{
        "url":    "https://github.com",
        "format": "png",
    })

    req, _ := http.NewRequest("POST",
        "https://api.getsnap.dev/v1/screenshot",
        bytes.NewBuffer(body))
    req.Header.Set("X-API-Key", "sk_live_YOUR_KEY")
    req.Header.Set("Content-Type", "application/json")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    fmt.Println(result["url"])
}

Full Page Capture

Capture the entire scrollable page, not just the viewport:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://stripe.com/docs",
    "format": "png",
    "full_page": true,
    "remove_popups": true
  }'
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://stripe.com/docs",
    format: "png",
    full_page: true,
    remove_popups: true,
  }),
}).then(r => r.json());

console.log(data.url);
response = requests.post(
    "https://api.getsnap.dev/v1/screenshot",
    headers={"X-API-Key": "sk_live_YOUR_KEY", "Content-Type": "application/json"},
    json={
        "url": "https://stripe.com/docs",
        "format": "png",
        "full_page": True,
        "remove_popups": True,
    },
)
print(response.json()["url"])

PDF Generation

Generate a PDF of any webpage — perfect for invoices, reports, or archival:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://invoice.example.com/inv-001",
    "format": "pdf",
    "full_page": true
  }'
const { url } = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://invoice.example.com/inv-001",
    format: "pdf",
    full_page: true,
  }),
}).then(r => r.json());

// url contains the CDN link to the generated PDF

Mobile Device Emulation

Capture as seen on a mobile or tablet device:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://tailwindcss.com",
    "format": "webp",
    "device": "mobile",
    "quality": 90
  }'
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://tailwindcss.com",
    format: "webp",
    device: "mobile",
    quality: 90,
  }),
}).then(r => r.json());

Element Capture (CSS Selector)

Capture a specific element on the page using a CSS selector:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://getsnap.dev",
    "format": "png",
    "selector": "#pricing .price-card.featured"
  }'
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://getsnap.dev",
    format: "png",
    selector: "#pricing .price-card.featured",
  }),
}).then(r => r.json());

Custom CSS Injection

Inject custom CSS before capture — hide elements, change styles, or highlight sections:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://news.ycombinator.com",
    "format": "png",
    "css": "header { display: none; } body { padding-top: 0; }",
    "full_page": false
  }'

Dark Mode

Trigger dark mode on sites that support prefers-color-scheme:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://github.com",
    "format": "png",
    "dark_mode": true
  }'

Binary Response (Direct Download)

Get the raw image bytes instead of a CDN URL. Useful for processing or immediate display:

# Save directly to a file
curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "format": "png",
    "response_type": "binary"
  }' \
  --output screenshot.png
import { writeFile } from "fs/promises";

const response = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://example.com",
    format: "png",
    response_type: "binary",
  }),
});

const buffer = Buffer.from(await response.arrayBuffer());
await writeFile("screenshot.png", buffer);
console.log("Saved screenshot.png");
response = requests.post(
    "https://api.getsnap.dev/v1/screenshot",
    headers={"X-API-Key": "sk_live_YOUR_KEY", "Content-Type": "application/json"},
    json={
        "url": "https://example.com",
        "format": "png",
        "response_type": "binary",
    },
)

with open("screenshot.png", "wb") as f:
    f.write(response.content)
print("Saved screenshot.png")

Lazy Load (Auto-scroll)

Auto-scroll the page to trigger lazy-loaded images and content before capture:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://unsplash.com/t/nature",
    "format": "png",
    "full_page": true,
    "lazy_load": true
  }'
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://unsplash.com/t/nature",
    format: "png",
    full_page: true,
    lazy_load: true, // scrolls page in 300px increments to load all images
  }),
}).then(r => r.json());

Wait for Selector (SPAs)

Wait for a specific element to appear before capturing. Essential for single-page apps and dynamically loaded content:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://app.example.com/dashboard",
    "format": "png",
    "wait_for_selector": ".dashboard-loaded",
    "delay": 500
  }'
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://app.example.com/dashboard",
    format: "png",
    wait_for_selector: ".dashboard-loaded", // waits up to 15s
    delay: 500, // extra delay after element appears
  }),
}).then(r => r.json());

Hide & Remove Elements

Hide elements with CSS (display:none) or completely remove them from the DOM before capture:

# Hide elements (still in DOM, just invisible)
curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "format": "png",
    "hide_selectors": ["header", ".sidebar", "#banner"],
    "remove_selectors": [".cookie-notice", ".chat-widget"]
  }'
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://example.com",
    format: "png",
    hide_selectors: ["header", ".sidebar", "#banner"], // display:none
    remove_selectors: [".cookie-notice", ".chat-widget"], // removed from DOM
  }),
}).then(r => r.json());

Extract Text & HTML

Get the page's visible text or full HTML alongside the screenshot — perfect for scraping and content analysis:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://news.ycombinator.com",
    "format": "png",
    "extract_text": true,
    "extract_html": true
  }'

# Response includes:
# {
#   "url": "https://cdn..../screenshot.png",
#   "extracted_text": "Hacker News\n1. Article title...",
#   "extracted_html": "<html>...</html>"
# }
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://news.ycombinator.com",
    format: "png",
    extract_text: true,
  }),
}).then(r => r.json());

console.log(data.url);            // Screenshot CDN URL
console.log(data.extracted_text); // Page text content
response = requests.post(
    "https://api.getsnap.dev/v1/screenshot",
    headers={"X-API-Key": "sk_live_YOUR_KEY", "Content-Type": "application/json"},
    json={
        "url": "https://news.ycombinator.com",
        "format": "png",
        "extract_text": True,
        "extract_html": True,
    },
)

data = response.json()
print(data["extracted_text"])  # Visible text content
print(len(data["extracted_html"]))  # Full HTML length

Click & Scroll to Element

Click an element (e.g., expand a menu or dismiss a dialog) or scroll to a section before capture:

# Click "Show More" button, then scroll to pricing section
curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "format": "png",
    "click_selector": ".show-more-btn",
    "scroll_to_selector": "#pricing",
    "delay": 1000
  }'
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://example.com",
    format: "png",
    click_selector: ".show-more-btn", // clicks element (5s timeout)
    scroll_to_selector: "#pricing",   // scrolls into view
    delay: 1000, // wait for animations
  }),
}).then(r => r.json());

Generate a signed URL that serves screenshots via GET — embed in <img> tags, OG meta, or emails without exposing your API key:

# Step 1: Generate a render link
curl -X POST https://api.getsnap.dev/v1/render-link \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://github.com/trending",
    "format": "png",
    "viewport_width": 1200,
    "viewport_height": 630
  }'

# Response:
# {
#   "render_url": "https://api.getsnap.dev/v1/render?url=...&signature=...",
#   "message": "Use this URL in <img> tags..."
# }

# Step 2: Use it anywhere!
# <img src="https://api.getsnap.dev/v1/render?url=...&signature=..." />
# <meta property="og:image" content="https://api.getsnap.dev/v1/render?..." />
// Generate a render link
const { render_url } = await fetch("https://api.getsnap.dev/v1/render-link", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://github.com/trending",
    format: "png",
    viewport_width: 1200,
    viewport_height: 630,
  }),
}).then(r => r.json());

// Use in HTML — no API key exposed!
const html = `<img src="${render_url}" alt="Screenshot" />`;
// Or as OG image
const meta = `<meta property="og:image" content="${render_url}" />`;

Batch Capture (Multiple URLs)

Capture up to 100 URLs in a single request — processed in parallel for maximum speed:

curl -X POST https://api.getsnap.dev/v1/batch \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://github.com",
      "https://stripe.com",
      "https://vercel.com",
      "https://linear.app"
    ],
    "format": "png",
    "full_page": false,
    "remove_popups": true
  }'

# Response:
# {
#   "batch_id": "batch_abc123",
#   "count": 4,
#   "succeeded": 4,
#   "failed": 0,
#   "results": [
#     { "source_url": "https://github.com", "url": "https://cdn.../1.png" },
#     ...
#   ]
# }
const data = await fetch("https://api.getsnap.dev/v1/batch", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    urls: [
      "https://github.com",
      "https://stripe.com",
      "https://vercel.com",
      "https://linear.app",
    ],
    format: "png",
    remove_popups: true,
  }),
}).then(r => r.json());

console.log(`Captured ${data.succeeded}/${data.count} screenshots`);
data.results.forEach(r => console.log(r.source_url, "->", r.url));
response = requests.post(
    "https://api.getsnap.dev/v1/batch",
    headers={"X-API-Key": "sk_live_YOUR_KEY", "Content-Type": "application/json"},
    json={
        "urls": [
            "https://github.com",
            "https://stripe.com",
            "https://vercel.com",
            "https://linear.app",
        ],
        "format": "png",
        "remove_popups": True,
    },
)

data = response.json()
for result in data["results"]:
    print(f"{result['source_url']} -> {result['url']}")

Transparent Background

Capture PNG screenshots with a transparent background — great for embedding in designs or compositing:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<div style=\"padding:40px;font-size:48px;font-weight:bold\">Hello World</div>",
    "format": "png",
    "omit_background": true
  }'

Authenticated Pages (Cookies & Headers)

Capture pages behind authentication by passing cookies or custom headers:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "X-API-Key: sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://app.example.com/dashboard",
    "format": "png",
    "cookies": [
      { "name": "session_id", "value": "abc123", "domain": "app.example.com" }
    ],
    "headers": {
      "Authorization": "Bearer eyJhbGciOi..."
    },
    "wait_for_selector": ".dashboard-content"
  }'
const data = await fetch("https://api.getsnap.dev/v1/screenshot", {
  method: "POST",
  headers: {
    "X-API-Key": "sk_live_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://app.example.com/dashboard",
    format: "png",
    cookies: [
      { name: "session_id", value: "abc123", domain: "app.example.com" },
    ],
    headers: {
      Authorization: "Bearer eyJhbGciOi...",
    },
    wait_for_selector: ".dashboard-content",
  }),
}).then(r => r.json());

Extract Page Metadata

Return page metadata (title, favicon, Open Graph tags, actually-loaded fonts, HTTP status, response headers) alongside the screenshot:

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://stripe.com",
    "format": "png",
    "extract_metadata": true
  }'
import GetSnap from "getsnap";

const snap = new GetSnap("YOUR_KEY");
const r = await snap.screenshot({
  url: "https://stripe.com",
  extract_metadata: true,
});

console.log(r.extracted_metadata?.title);
console.log(r.extracted_metadata?.favicon);
console.log(r.extracted_metadata?.open_graph);       // { "og:title": "...", ... }
console.log(r.extracted_metadata?.fonts);            // ["Inter", "SF Pro Text", ...]
console.log(r.extracted_metadata?.http_status);      // 200
from getsnap import GetSnap

snap = GetSnap("YOUR_KEY")
r = snap.screenshot(
    url="https://stripe.com",
    format="png",
    extract_metadata=True,
)

meta = r["extracted_metadata"]
print(meta["title"], meta["favicon"], meta["http_status"])
print("OG tags:", meta["open_graph"])
print("Fonts:", meta["fonts"])

Clip Region

Capture a specific rectangle of the viewport instead of the full page or an element. Overrides full_page and selector.

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://openai.com",
    "clip": { "x": 0, "y": 0, "width": 1280, "height": 400 }
  }'
const r = await snap.screenshot({
  url: "https://openai.com",
  clip: { x: 0, y: 0, width: 1280, height: 400 },
});

Full-Page Slices (for AI vision)

Split a tall full_page capture into overlapping vertical strips so downstream vision models (which typically cap at ~8000px height) can process the whole page. Each slice is uploaded as its own object.

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://en.wikipedia.org/wiki/Screenshot",
    "full_page": true,
    "full_page_max_height": 20000,
    "full_page_slices": true,
    "full_page_slice_height": 4000,
    "full_page_slice_overlap_height": 100
  }'
const r = await snap.screenshot({
  url: "https://en.wikipedia.org/wiki/Screenshot",
  full_page: true,
  full_page_max_height: 20000,
  full_page_slices: true,
  full_page_slice_height: 4000,
  full_page_slice_overlap_height: 100,
});

// r.slices = [{ index, offset_y, width, height, url }, ...]
for (const s of r.slices ?? []) {
  console.log(`slice ${s.index} @ y=${s.offset_y}: ${s.url}`);
}

Custom PDF (headers, footers, document metadata)

Render an invoice-style PDF with A4 landscape orientation, per-side margins, a page-number footer, and document metadata that shows up in PDF viewers.

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/invoice/INV-2026-0042",
    "format": "pdf",
    "pdf_page_size": "A4",
    "pdf_orientation": "landscape",
    "pdf_margin_top": "40px",
    "pdf_margin_bottom": "40px",
    "pdf_scale": 0.9,
    "pdf_background": true,
    "pdf_show_footer": true,
    "pdf_footer": "<div style=\"font-size:10px;width:100%;text-align:center;color:#666\">Page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>",
    "pdf_title": "Invoice INV-2026-0042",
    "pdf_subject": "Monthly invoice",
    "pdf_author": "Acme Inc.",
    "pdf_keywords": "invoice,billing,acme",
    "pdf_creator": "getSnap.dev"
  }'
const r = await snap.screenshot({
  url: "https://example.com/invoice/INV-2026-0042",
  format: "pdf",
  pdf_page_size: "A4",
  pdf_orientation: "landscape",
  pdf_margin_top: "40px",
  pdf_margin_bottom: "40px",
  pdf_scale: 0.9,
  pdf_show_footer: true,
  pdf_footer: '<div style="font-size:10px;width:100%;text-align:center;color:#666">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
  pdf_title: "Invoice INV-2026-0042",
  pdf_author: "Acme Inc.",
  pdf_keywords: "invoice,billing,acme",
});

Scrolling Video (MP4/GIF)

Record a smoothly-scrolling capture of any URL. Costs 1 credit per second of video (rounded up, min 1).

# Sync mode - blocks until video is encoded
curl -X POST https://api.getsnap.dev/v1/video \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://stripe.com",
    "format": "mp4",
    "duration_ms": 8000,
    "fps": 20,
    "viewport_width": 1280,
    "viewport_height": 720,
    "quality": 75
  }'

# Async mode - returns 202 + delivers video.completed to your webhook
curl -X POST https://api.getsnap.dev/v1/video \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://stripe.com",
    "format": "gif",
    "duration_ms": 4000,
    "fps": 15,
    "webhook_url": "https://my-app.com/webhooks/getsnap"
  }'
import GetSnap from "getsnap";

const snap = new GetSnap("YOUR_KEY");

// URL mode
const mp4 = await snap.video({
  url: "https://stripe.com",
  format: "mp4",
  duration_ms: 8000,
  fps: 20,
});
console.log(mp4.url, mp4.frame_count, mp4.credits_charged);

// Binary mode - get raw MP4/GIF bytes
const buf = await snap.videoBinary({
  url: "https://stripe.com",
  format: "gif",
  duration_ms: 5000,
});
require("fs").writeFileSync("stripe.gif", Buffer.from(buf));
from getsnap import GetSnap

snap = GetSnap("YOUR_KEY")

# URL mode
r = snap.video(
    url="https://stripe.com",
    format="mp4",
    duration_ms=8000,
    fps=20,
)
print(r["url"], r["frame_count"], r["credits_charged"])

# Binary mode
with open("stripe.gif", "wb") as f:
    f.write(snap.video_binary(
        url="https://stripe.com",
        format="gif",
        duration_ms=5000,
    ))

Scheduled Captures

Cron-driven recurring captures with optional HMAC-signed webhook delivery. Great for daily dashboards, hourly competitor snapshots, or weekly compliance archives.

# Create - runs every weekday at 09:00 Berlin time
curl -X POST https://api.getsnap.dev/v1/schedules \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "morning traffic dashboard",
    "cron": "0 9 * * MON-FRI",
    "timezone": "Europe/Berlin",
    "options": {
      "url": "https://dash.example.com",
      "format": "png",
      "full_page": true,
      "viewport_width": 1600
    },
    "webhook_url": "https://my-app.com/webhooks/getsnap",
    "webhook_secret": "a-strong-shared-secret-abcd1234"
  }'

# Trigger immediately (for testing)
curl -X POST https://api.getsnap.dev/v1/schedules/sched_ABC123/run \
  -H "x-api-key: YOUR_KEY"

# List runs
curl https://api.getsnap.dev/v1/schedules/sched_ABC123/runs \
  -H "x-api-key: YOUR_KEY"

# Pause
curl -X PATCH https://api.getsnap.dev/v1/schedules/sched_ABC123 \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"is_active": false}'
import GetSnap from "getsnap";

const snap = new GetSnap("YOUR_KEY");

// Create
const s = await snap.schedules.create({
  name: "morning traffic dashboard",
  cron: "0 9 * * MON-FRI",
  timezone: "Europe/Berlin",
  options: {
    url: "https://dash.example.com",
    full_page: true,
    viewport_width: 1600,
  },
  webhook_url: "https://my-app.com/webhooks/getsnap",
  webhook_secret: process.env.WEBHOOK_SECRET,
});

// Trigger it now (returns immediately, worker runs in background)
await snap.schedules.runNow(s.id);

// Poll history
const { runs } = await snap.schedules.runs(s.id);
console.log(runs[0]?.status, runs[0]?.result_url);

// Pause / resume / delete
await snap.schedules.update(s.id, { is_active: false });
await snap.schedules.update(s.id, { is_active: true });
await snap.schedules.remove(s.id);
from getsnap import GetSnap

snap = GetSnap("YOUR_KEY")

s = snap.create_schedule(
    name="morning traffic dashboard",
    cron="0 9 * * MON-FRI",
    timezone="Europe/Berlin",
    options={
        "url": "https://dash.example.com",
        "full_page": True,
        "viewport_width": 1600,
    },
    webhook_url="https://my-app.com/webhooks/getsnap",
    webhook_secret="a-strong-shared-secret-abcd1234",
)

# Trigger it now
snap.run_schedule_now(s["id"])

# Poll history
for run in snap.list_schedule_runs(s["id"])["runs"]:
    print(run["status"], run.get("result_url"), run.get("error"))

# Update / delete
snap.update_schedule(s["id"], is_active=False)
snap.delete_schedule(s["id"])

Verify HMAC-signed webhooks

When you set webhook_secret, every delivery includes X-Webhook-Timestamp (seconds since epoch) and X-Webhook-Signature: sha256=<hex> where the HMAC is computed over timestamp + "." + raw_body. Verify server-side:

// Node.js webhook receiver
import crypto from "node:crypto";

app.post("/webhooks/getsnap", express.raw({ type: "application/json" }), (req, res) => {
  const ts   = req.header("X-Webhook-Timestamp") ?? "";
  const sig  = req.header("X-Webhook-Signature") ?? "";
  const body = req.body.toString("utf8");

  const expected = "sha256=" + crypto
    .createHmac("sha256", process.env.WEBHOOK_SECRET)
    .update(ts + "." + body)
    .digest("hex");

  const ok = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
  if (!ok) return res.sendStatus(401);

  // Also reject deliveries older than 5 minutes to defeat replay
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);

  const event = JSON.parse(body);
  console.log(event.event, event.schedule_id, event.url);
  res.sendStatus(200);
});

Proxy / Geo Routing

Route any capture through your own proxy (BYOP) or a managed geo pool. Works on both /v1/screenshot and /v1/video.

# BYOP - creds embedded in the URL
curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "proxy_url": "http://user:pass@proxy.mycompany.com:8080"
  }'

# BYOP - creds split (safer to log)
curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "proxy_url": "socks5://proxy.mycompany.com:1080",
    "proxy_username": "alice",
    "proxy_password": "secret"
  }'

# Managed geo pool - capture from a US IP
curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://us-only.example.com",
    "proxy_country": "US"
  }'
// BYOP
await snap.screenshot({
  url: "https://example.com",
  proxy_url: "http://proxy.mycompany.com:8080",
  proxy_username: "alice",
  proxy_password: process.env.PROXY_PASSWORD,
});

// Managed geo pool
await snap.screenshot({
  url: "https://us-only.example.com",
  proxy_country: "US",
});

// Works on video too
await snap.video({
  url: "https://us-only.example.com",
  format: "mp4",
  duration_ms: 5000,
  proxy_country: "US",
});
# BYOP
snap.screenshot(
    url="https://example.com",
    proxy_url="http://proxy.mycompany.com:8080",
    proxy_username="alice",
    proxy_password=os.environ["PROXY_PASSWORD"],
)

# Managed geo pool
snap.screenshot(
    url="https://us-only.example.com",
    proxy_country="US",
)

# Works on video too
snap.video(
    url="https://us-only.example.com",
    format="mp4",
    duration_ms=5000,
    proxy_country="US",
)

Granular Request Blocking

Cut page load time (and bandwidth) by aborting requests you don't need. Combine with bypass_csp when a site's Content-Security-Policy blocks your injected CSS/JS.

curl -X POST https://api.getsnap.dev/v1/screenshot \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://news-heavy-site.com/article/123",
    "block_images": true,
    "block_fonts": true,
    "block_scripts": true,
    "block_frames": true,
    "block_urls": ["*/analytics/*", "*/beacon/*", "chartbeat"],
    "click_accept": true,
    "press_escape": true
  }'
await snap.screenshot({
  url: "https://news-heavy-site.com/article/123",
  block_images: true,
  block_fonts: true,
  block_scripts: true,
  block_frames: true,
  block_urls: ["*/analytics/*", "*/beacon/*", "chartbeat"],
  click_accept: true,
  press_escape: true,
});

Node.js SDK

Use the official SDK for a cleaner developer experience with full TypeScript support:

import GetSnap from "getsnap";

const snap = new GetSnap("sk_live_YOUR_KEY");

// Simple screenshot
const { url } = await snap.screenshot({
  url: "https://github.com",
  format: "png",
  full_page: true,
});
console.log(url);

// Binary download
const buffer = await snap.screenshotBinary({
  url: "https://example.com",
  format: "webp",
  quality: 90,
});
await writeFile("screenshot.webp", Buffer.from(buffer));

// Batch capture
const batch = await snap.batch({
  urls: ["https://github.com", "https://stripe.com"],
  format: "png",
});
console.log(`${batch.succeeded} screenshots captured`);

// Check usage
const usage = await snap.usage();
console.log(`${usage.used}/${usage.limit} screenshots used`);

Python SDK

Zero-dependency Python SDK using only the standard library:

from getsnap import GetSnap

snap = GetSnap("sk_live_YOUR_KEY")

# Simple screenshot
result = snap.screenshot(url="https://github.com", format="png")
print(result["url"])

# Binary download
binary = snap.screenshot_binary(url="https://example.com", format="webp")
with open("screenshot.webp", "wb") as f:
    f.write(binary)

# Batch capture
batch = snap.batch(
    urls=["https://github.com", "https://stripe.com"],
    format="png",
    remove_popups=True,
)
for r in batch["results"]:
    print(f"{r['source_url']} -> {r['url']}")

# Check usage
usage = snap.usage()
print(f"{usage['used']}/{usage['limit']} screenshots used")