Python
Official screenshotapi-to SDK for Python — capture screenshots and PDFs from scripts, FastAPI, Django, and Flask, with sync and async clients.
The official screenshotapi-to SDK is a fully typed Python client with sync and async APIs. It ships py.typed metadata, so editors and type checkers understand every option and return value.
Package: screenshotapi-to on PyPI · Import name: screenshotapi · Source & examples: github.com/miketromba/screenshotapi-python · Python 3.8+.
Installation
pip install screenshotapi-topoetry add screenshotapi-touv add screenshotapi-toThe distribution package is screenshotapi-to; the import package is screenshotapi.
Authentication
Create an API key in the dashboard and keep it in an environment variable. The SDK sends it in the x-api-key header.
export SCREENSHOTAPI_KEY="sk_live_your_key_here"import os
from screenshotapi import ScreenshotAPI
client = ScreenshotAPI(os.environ["SCREENSHOTAPI_KEY"])Keep API keys on the server. Never ship them in browser bundles, mobile apps, or notebooks you share.
Quick Start
Capture a URL and save it to disk
save() captures the screenshot, writes the file, and returns the response metadata.
import os
from screenshotapi import ScreenshotAPI
client = ScreenshotAPI(os.environ["SCREENSHOTAPI_KEY"])
metadata = client.save(
{"url": "https://example.com", "width": 1440, "height": 900},
"screenshot.png",
)
print(f"Screenshot ID: {metadata.screenshot_id}")
print(f"Credits remaining: {metadata.credits_remaining}")Or work with the raw image bytes
screenshot() returns the image as bytes plus metadata.
result = client.screenshot({"url": "https://example.com", "type": "webp", "quality": 85})
print(result.content_type) # "image/webp"
print(len(result.image)) # image size in bytes
print(result.metadata.credits_remaining)You can pass options as a plain dict (shown above) or as a typed ScreenshotOptions dataclass for editor autocomplete:
from screenshotapi import ScreenshotOptions
result = client.screenshot(
ScreenshotOptions(
url="https://example.com",
full_page=True,
type="webp",
quality=90,
color_scheme="dark",
)
)Async
Every method has an async_ counterpart for use inside asyncio event loops, FastAPI endpoints, or background workers.
import asyncio
from screenshotapi import ScreenshotAPI
client = ScreenshotAPI(os.environ["SCREENSHOTAPI_KEY"])
async def main() -> None:
result = await client.async_screenshot({"url": "https://example.com"})
print(f"Captured in {result.metadata.duration_ms}ms")
await client.async_save({"url": "https://example.com"}, "screenshot.png")
asyncio.run(main())Methods
ScreenshotAPI(api_key, *, base_url=..., timeout=60.0)
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key | str | — (required) | Your API key |
base_url | str | https://screenshotapi.to | API base URL (proxies, tests) |
timeout | float | 60.0 | Request timeout in seconds |
client.screenshot(options) · client.async_screenshot(options)
options is a ScreenshotOptions or a dict. Returns a ScreenshotResult:
result.image # bytes — raw image or PDF
result.content_type # "image/png", "image/webp", "application/pdf", …
result.metadata.credits_remaining # int
result.metadata.screenshot_id # str — include this when contacting support
result.metadata.duration_ms # intclient.save(options, path) · client.async_save(options, path)
Captures, writes the bytes to path, and returns the metadata shown above.
Options
Every screenshot parameter is available as a snake_case field.
| Option | Type | Default | Description |
|---|---|---|---|
url | str | Required unless html is set | URL to capture |
html | str | — | HTML document to render (switches to POST) |
width | int | 1440 | Viewport width in pixels (max 1920) |
height | int | 900 | Viewport height in pixels (max 10000) |
full_page | bool | False | Capture the full scrollable page |
type | "png" | "jpeg" | "webp" | "pdf" | "png" | Output format |
quality | int | 100 | JPEG/WebP quality, 1–100 |
color_scheme | "light" | "dark" | Page default | Force prefers-color-scheme |
wait_until | "load" | "domcontentloaded" | "networkidle0" | "networkidle2" | "networkidle2" | Page readiness signal |
wait_for_selector | str | — | CSS selector to wait for |
delay | int | 0 | Extra wait after load (ms, max 30000) |
block_ads | bool | False | Block common ad networks |
remove_cookie_banners | bool | False | Auto-remove cookie consent dialogs |
css_inject | str | — | CSS injected before capture |
js_inject | str | — | JavaScript evaluated before capture |
stealth_mode | bool | False | Anti-bot-detection browser fingerprint |
device_pixel_ratio | int | 1 | Retina/HiDPI scale (1, 2, or 3) |
timezone | str | Server default | IANA timezone, e.g. America/New_York |
locale | str | Server default | BCP 47 locale, e.g. en-US |
cache_ttl | int | 0 | Cache identical captures for N seconds |
preload_fonts | bool | False | Preload Google Fonts before capture |
remove_elements | list[str] | — | CSS selectors to remove |
remove_popups | bool | False | Remove common modals/overlays |
mockup_device | "browser" | "iphone" | "macbook" | — | Wrap output in a device frame (PNG) |
geo_latitude, geo_longitude, geo_accuracy | float | — | Browser geolocation emulation |
result = client.screenshot(
{
"url": "https://example.com/dashboard",
"width": 1280,
"height": 720,
"device_pixel_ratio": 2,
"type": "webp",
"quality": 85,
"color_scheme": "dark",
"wait_until": "networkidle0",
"wait_for_selector": ".ready",
"delay": 500,
"block_ads": True,
"remove_cookie_banners": True,
"remove_elements": [".newsletter", "#cookie-banner"],
"cache_ttl": 3600,
"geo_latitude": 40.7128,
"geo_longitude": -74.0060,
}
)Render HTML & generate PDFs
Pass html to render a raw string — the SDK automatically uses POST /api/v1/screenshot. Combine with type="pdf" for documents.
result = client.screenshot(
{"html": "<html><body><h1>Invoice #123</h1></body></html>", "type": "pdf"}
)
with open("invoice.pdf", "wb") as f:
f.write(result.image)Error Handling
The SDK raises typed exceptions. All inherit from ScreenshotAPIError.
from screenshotapi import (
ScreenshotAPI,
AuthenticationError,
InvalidAPIKeyError,
InsufficientCreditsError,
ScreenshotFailedError,
NetworkError,
ScreenshotAPIError,
)
client = ScreenshotAPI(os.environ["SCREENSHOTAPI_KEY"])
try:
client.screenshot({"url": "https://example.com"})
except AuthenticationError:
print("API key missing or malformed (401)")
except InvalidAPIKeyError:
print("API key invalid or revoked (403)")
except InsufficientCreditsError as exc:
print(f"Out of credits (402). Balance: {exc.balance}")
except ScreenshotFailedError as exc:
print(f"Capture failed server-side (500): {exc}")
except NetworkError as exc:
print(f"Could not reach ScreenshotAPI: {exc}")
except ScreenshotAPIError as exc:
print(f"ScreenshotAPI error {exc.status} ({exc.code}): {exc}")| Exception | When |
|---|---|
AuthenticationError | 401 — API key missing or malformed |
InsufficientCreditsError | 402 — no credits remaining (exposes .balance) |
InvalidAPIKeyError | 403 — API key invalid or revoked |
ScreenshotFailedError | 500 — capture failed server-side |
NetworkError | Connection failure or timeout |
ScreenshotAPIError | Base class (exposes .status and .code) |
Framework Recipes
FastAPI
The async client pairs naturally with FastAPI.
from fastapi import FastAPI, HTTPException, Response
from screenshotapi import ScreenshotAPI, InsufficientCreditsError
app = FastAPI()
client = ScreenshotAPI(os.environ["SCREENSHOTAPI_KEY"])
@app.get("/screenshot")
async def screenshot(url: str):
try:
result = await client.async_screenshot({"url": url, "type": "webp"})
except InsufficientCreditsError:
raise HTTPException(status_code=402, detail="Out of screenshot credits")
return Response(content=result.image, media_type=result.content_type)Django
from django.http import HttpResponse, JsonResponse
from screenshotapi import ScreenshotAPI
client = ScreenshotAPI(os.environ["SCREENSHOTAPI_KEY"])
def screenshot_view(request):
url = request.GET.get("url")
if not url:
return JsonResponse({"error": "url is required"}, status=400)
result = client.screenshot({"url": url, "type": "webp"})
return HttpResponse(result.image, content_type=result.content_type)Flask
from flask import Flask, request, Response, jsonify
from screenshotapi import ScreenshotAPI
app = Flask(__name__)
client = ScreenshotAPI(os.environ["SCREENSHOTAPI_KEY"])
@app.get("/screenshot")
def screenshot():
url = request.args.get("url")
if not url:
return jsonify(error="url is required"), 400
result = client.screenshot({"url": url, "type": "webp"})
return Response(result.image, mimetype=result.content_type)Runnable versions of these ship in the package's examples/ directory (script_usage.py, fastapi_app.py, django_view.py, flask_app.py).
Without the SDK
The endpoint is a single HTTP call, so requests works too:
import requests
response = requests.get(
"https://screenshotapi.to/api/v1/screenshot",
params={"url": "https://example.com"},
headers={"x-api-key": os.environ["SCREENSHOTAPI_KEY"]},
)
response.raise_for_status()
with open("screenshot.png", "wb") as f:
f.write(response.content)Next steps
- Screenshot API reference — every parameter in detail
- Authentication — create and rotate API keys
- Credits — how billing works (200 free screenshots/month)
- Integrations — framework and platform guides
JavaScript / TypeScript
Official screenshotapi-to SDK for JavaScript and TypeScript — capture screenshots from Node.js, Next.js, Vercel, Bun, Deno, and Cloudflare Workers.
Go
Official screenshotapi-go SDK — capture screenshots, PDFs, and rendered HTML from Go with a typed, context-aware, standard-library client.