Site-Shot

Tutorial ·Published ·Updated ·7 min read

How to Take a Website Screenshot with Python

Save a web page as an image with Python, then use it in a report, preview or monitoring workflow. Start with the official Site-Shot SDK below; use plain HTTP if you already work with requests.

For a one-off screenshot without code, try the free browser tool. To automate several pages, jump to the CSV-to-HTML report example.

Prerequisites

  • Python 3.9+ for the SDK; Python 3.10+ for the current requests release
  • A Site-Shot account with confirmed email, an active paid API plan and its API key. Plans start at $5/mo for 2,000 screenshots (pricing, checked September 10, 2026). The browser tool is not a free API tier

Keep your API key in SITESHOT_API_KEY, never in shared code or logs. Captures consume your plan's allowance; run only the examples you need.

The Official Python SDK

In Bash on macOS/Linux, create a virtual environment and enter your key at the hidden prompt. If your secret manager already sets SITESHOT_API_KEY, skip the prompt:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install site-shot

read -r -s -p 'Site-Shot API key: ' SITESHOT_API_KEY
printf '\n'
export SITESHOT_API_KEY
from site_shot import SiteShot

client = SiteShot()  # reads SITESHOT_API_KEY from the environment
client.capture_to_file("https://example.com/", "screenshot.png")

Open screenshot.png in your current directory and check that it shows the page you intended. The package installs as site-shot and imports as site_shot; the SDK has no runtime dependencies.

Full Page Screenshot

Use full_size=True for a full-page capture and max_height to cap its height (up to 20,000 pixels):

client.capture_to_file(
    "https://example.com/", "full-page.png", full_size=True, max_height=15000,
)

Longer pages can be clipped at max_height. Scrolling can help load lazy content, but inspect the result rather than assuming every section loaded. See full page vs viewport screenshots for the trade-off.

Mobile Device Screenshot

Set a narrow viewport and a mobile user agent; this is not a real iPhone or Safari session:

client.capture_to_file(
    "https://example.com/", "mobile.png", width=375, height=812,
    user_agent="Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) "
               "AppleWebKit/605.1.15 (KHTML, like Gecko) "
               "Version/16.0 Mobile/15E148 Safari/604.1",
)

Screenshot from a Specific Country

Use a two-letter ISO country code and strict mode when the capture's location matters:

from site_shot import SiteShot

client = SiteShot()
client.capture_to_file(
    "https://example.com/", "germany.png", country="DE", strict_country=True,
)

Site-Shot routes the capture through that country, with matching language, time zone and geolocation. If capacity is unavailable, strict_country=True raises CountryUnavailableError rather than returning a US capture. Without strict mode, an unresolved country or unavailable capacity can silently use the US. Use ISO codes, not country names. Country routing is included with any paid plan; see the geo guide.

Without the SDK: One Plain GET

Prefer requests? Install it with pip install requests, set SITESHOT_API_KEY as above, then run:

import os

import requests

try:
    response = requests.get("https://api.site-shot.com/", params={
        "url": "https://example.com/",
        "userkey": os.environ["SITESHOT_API_KEY"],
        "width": 1280,
        "height": 1024,
        "format": "png",
    }, timeout=70, allow_redirects=False)
except requests.RequestException:
    raise RuntimeError("Site-Shot request failed; no image was saved.") from None

if response.status_code != 200:
    raise RuntimeError(f"Site-Shot returned HTTP {response.status_code}; no image was saved.")

png = response.content
content_type = response.headers.get("Content-Type", "").split(";", 1)[0].lower()
if content_type != "image/png" or not png.startswith(b"\x89PNG\r\n\x1a\n"):
    raise RuntimeError("Site-Shot did not return a PNG; no image was saved.")

with open("screenshot.png", "wb") as f:
    f.write(png)

This checks HTTP status, content type and the PNG signature; it does not fully decode the image or verify its page content. Open the result. Errors omit sensitive URLs and response bodies, and redirects are disabled. The requests timeout is a connect/read timeout, not a whole-download deadline.

Four Return Modes

The SDK offers capture() for bytes, capture_to_file() for a file, capture_base64() for a string and capture_json() for metadata. Use the SDK return-mode reference for their contracts instead of maintaining separate decoding code.

JSON, Metadata and Rendered HTML

Need the target's HTTP status or rendered HTML as well as the image?

meta = client.capture_json("https://example.com/", source_code=True)
print(meta["response"]["status_code"])

Rendered HTML is in meta["source_code"]. The SDK checks API errors, including errors inside HTTP 200 JSON responses, and raises a SiteShotError subclass. Keep target headers and HTML private when they contain sensitive data. The API documentation defines the response fields.

Batch Screenshots: CSV to a Reviewable Report

The CSV-to-report example saves screenshots and a local HTML index. Start with the supplied five public Site-Shot pages, or edit its id,url rows before running:

git clone https://github.com/site-shot/site-shot-python.git
cd site-shot-python
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[examples]'

The optional example adds Pillow for full PNG decoding. Review the input URLs and your budget, set SITESHOT_API_KEY, then run:

python examples/csv_report.py examples/report_urls.csv --output reports

Open index.html in the new run directory under reports/. It links the PNGs; manifest.json records each row's result. Later runs get separate directories. Failed rows stay visible, and any failed row produces a non-zero exit code.

The example defaults to one worker and zero client retries. A successful run means the images decoded, not that the page content is correct: check for blanks, login screens, challenges and clipping. Keep the directory private until you approve sharing it.

Input restrictions, capture settings and error codes live in the example README; use it from the same checkout as the script.

Rather not run this on a schedule yourself? Site-Shot's own scheduled captures repeat a capture daily, on weekdays or weekly with no code, filing every dated image in your library. To deliver the images into Google Drive or another app instead, see website screenshots in Make.

Where the honest limits are

  • The SDK is synchronous; in asyncio applications, run captures in a worker thread (asyncio.to_thread).
  • Output is PNG, JPEG or WebP, not PDF or video. Saved images are not automatic change detection or visual regression tests.
  • For AI image-input examples, see LangChain, LlamaIndex, CrewAI or AutoGen. For a connected assistant, start with Site-Shot MCP.

Parameter Reference

Use the SDK options or full API documentation. SDK booleans use True/False; HTTP query parameters use 1/0.

FAQ

Is there an official Python SDK for Site-Shot?

Yes. Install site-shot and import site_shot. The official Site-Shot SDK supports Python 3.9+, has no runtime dependencies and reads SITESHOT_API_KEY from the environment.

Do I need an API key to take website screenshots with Python?

The Site-Shot API requires a confirmed account, an active paid plan and an API key. The free Site-Shot browser tool needs no signup, but it is not a free API tier.

How do I capture a full-page screenshot in Python?

With the Site-Shot SDK, use full_size=True and set max_height to cap the image height. Pages can be clipped at that cap; inspect the result for missing or unloaded content.

Can Python capture a screenshot as seen from another country?

Yes. With the Site-Shot SDK, use a two-letter ISO country code, such as country="DE", and strict_country=True. If that country has no capacity, the SDK raises CountryUnavailableError instead of returning a US capture. Country routing is included with any paid plan.

Try a screenshot free in your browser, or choose an API plan to automate it with Python.

← All articles