ScreenshotAPI

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-to
poetry add screenshotapi-to
uv add screenshotapi-to

The 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)

ParameterTypeDefaultDescription
api_keystr— (required)Your API key
base_urlstrhttps://screenshotapi.toAPI base URL (proxies, tests)
timeoutfloat60.0Request 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        # int

client.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.

OptionTypeDefaultDescription
urlstrRequired unless html is setURL to capture
htmlstrHTML document to render (switches to POST)
widthint1440Viewport width in pixels (max 1920)
heightint900Viewport height in pixels (max 10000)
full_pageboolFalseCapture the full scrollable page
type"png" | "jpeg" | "webp" | "pdf""png"Output format
qualityint100JPEG/WebP quality, 1–100
color_scheme"light" | "dark"Page defaultForce prefers-color-scheme
wait_until"load" | "domcontentloaded" | "networkidle0" | "networkidle2""networkidle2"Page readiness signal
wait_for_selectorstrCSS selector to wait for
delayint0Extra wait after load (ms, max 30000)
block_adsboolFalseBlock common ad networks
remove_cookie_bannersboolFalseAuto-remove cookie consent dialogs
css_injectstrCSS injected before capture
js_injectstrJavaScript evaluated before capture
stealth_modeboolFalseAnti-bot-detection browser fingerprint
device_pixel_ratioint1Retina/HiDPI scale (1, 2, or 3)
timezonestrServer defaultIANA timezone, e.g. America/New_York
localestrServer defaultBCP 47 locale, e.g. en-US
cache_ttlint0Cache identical captures for N seconds
preload_fontsboolFalsePreload Google Fonts before capture
remove_elementslist[str]CSS selectors to remove
remove_popupsboolFalseRemove common modals/overlays
mockup_device"browser" | "iphone" | "macbook"Wrap output in a device frame (PNG)
geo_latitude, geo_longitude, geo_accuracyfloatBrowser 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}")
ExceptionWhen
AuthenticationError401 — API key missing or malformed
InsufficientCreditsError402 — no credits remaining (exposes .balance)
InvalidAPIKeyError403 — API key invalid or revoked
ScreenshotFailedError500 — capture failed server-side
NetworkErrorConnection failure or timeout
ScreenshotAPIErrorBase 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

On this page