Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To take a website screenshot in Python, send a GET request to https://shot.screenshotapi.net/v3/screenshot with your API token, target url, output=image, and a file_type. Save the response body as a binary file. The same endpoint can return JSON render information, load custom HTML, inject CSS, apply cookies, emulate a user agent and language, set browser geolocation, add headers, or route traffic through a proxy.

This guide starts with runnable Python, then explains each setting, authenticated and localized captures, failure recovery, and an API alternative when you do not want to manage a browser-rendering setup.

Minimal Python screenshot request

Install the HTTP client first:

python -m pip install requests

Use a parameter dictionary rather than manually concatenating the query string. The client URL-encodes the page URL and other values safely.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import requests

TOKEN = "YOUR_API_KEY"
params = {
    "token": TOKEN,
    "url": "https://example.com",
    "output": "image",
    "file_type": "png",
}

response = requests.get(
    "https://shot.screenshotapi.net/v3/screenshot",
    params=params,
    timeout=60,
)
response.raise_for_status()

with open("screenshot.png", "wb") as image_file:
    image_file.write(response.content)

print(f"Saved {len(response.content)} bytes to screenshot.png")

token authenticates the request and url identifies the page to render. output=image returns the rendered media bytes, so write response.content in binary mode. A timeout prevents a stalled render from hanging your worker indefinitely.

Python without third-party packages

The standard library works when you cannot install requests:

import urllib.parse
import urllib.request

TOKEN = "YOUR_API_KEY"
target = urllib.parse.quote_plus("https://example.com")
query = (
    "https://shot.screenshotapi.net/v3/screenshot"
    f"?token={TOKEN}&url={target}&output=image&file_type=png"
)
urllib.request.urlretrieve(query, "screenshot.png")

Do not omit URL encoding when constructing a URL manually. Query characters in the target page, such as & or ?, otherwise become part of the screenshot API request itself.

Response type and file format

Rendered bytes with output=image

Choose output=image when your program needs a PNG, JPG, WebP, or supported PDF response. The response body is the file; there is no JSON wrapper to decode. Select the format with file_type and use a matching extension in your output filename.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Goal Settings What Python receives
Lossless image for tests or archival output=image, file_type=png PNG bytes
Smaller photographic image output=image, a supported JPG or WebP file_type Encoded image bytes
Printable document output=image, file_type=pdf where supported PDF bytes
Render diagnostics or metadata output=JSON Structured response data rather than an image file

Use output=JSON while debugging a URL or collecting render information. Switch to image in production when the consumer expects a media file. The service documentation should be checked for the currently supported file_type values before relying on a less common format.

Core request options

Authentication and target page

  • token: the API key issued by the service dashboard. Rolling a key revokes the previous key, so update every deployed secret before rotating.
  • url: the public page to render. Pass the complete scheme, such as https://, and keep it as a parameter so Python performs encoding.

Render supplied HTML

Set custom_html to render supplied markup instead of loading the URL. This is useful for generating a receipt, previewing a component, or testing a small page without deploying it. Treat HTML as data: escape user-controlled content before inserting it, and keep large documents within the service’s current request limits.

import requests

html = """<!doctype html>
<html><body><h1>Invoice preview</h1><p>Paid</p></body></html>"""
params = {
    "token": "YOUR_API_KEY",
    "url": "https://example.com",  # required by some client wrappers; custom_html takes precedence
    "custom_html": html,
    "output": "image",
    "file_type": "png",
}
r = requests.get("https://shot.screenshotapi.net/v3/screenshot", params=params, timeout=60)
r.raise_for_status()
with open("invoice.png", "wb") as f:
    f.write(r.content)

Hide elements with injected CSS

The css option injects CSS before capture. Hide cookie notices, navigation, or test-only controls without changing the source page:

params["css"] = ".module-content, .cookie-banner { display: none !important; }"

Use selectors that are stable across deployments. A selector matching nothing is not an API error; it simply leaves the page unchanged. If a site renders the element late, CSS alone may not remove a flash that occurs before the final capture.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Preserve login or other session state with cookies

Send cookies through the cookies option. The documented syntax is semicolon-separated, for example:

params = {
    "token": "YOUR_API_KEY",
    "url": "https://example.com/account",
    "cookies": "session_id=abc123; region=us",
    "output": "image",
    "file_type": "png",
}

Use a short-lived, least-privileged session where possible. Never commit real session values to source control or log the complete query string. A cookie can expire, be scoped to another domain, or require additional anti-forgery state; a screenshot API cannot repair an invalid login.

Set browser geolocation

Supply numeric latitude and longitude values to establish the browser geolocation context. A page must actually request and use geolocation for the visual result to change; IP-based localization and server-side region checks are separate mechanisms.

params.update({
    "latitude": "40.7128",
    "longitude": "-74.0060",
})

Emulate client, language, and network origin

The following options shape what the destination sees:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • user_agent represents a browser or device client.
  • accept_languages supplies the preferred language list.
  • headers sends custom HTTP headers before rendering.
  • proxy routes the request through an address, with optional authentication, for regional or network-origin testing.
params.update({
    "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)",
    "accept_languages": "fr-FR,fr;q=0.9",
    "headers": "X-Preview: true",
    "proxy": "http://user:[email protected]:8080",
})

These settings are independent. A French accept_languages value does not guarantee a French page if the application uses account settings or IP location; a proxy does not automatically set browser geolocation.

Putting options together

This example captures a logged-in, French-language page, hides a panel, sets coordinates, and saves WebP:

import requests

params = {
    "token": "YOUR_API_KEY",
    "url": "https://example.com/dashboard",
    "output": "image",
    "file_type": "webp",
    "cookies": "session_id=REDACTED; consent=yes",
    "css": ".sidebar, .newsletter-modal { display: none !important; }",
    "latitude": "48.8566",
    "longitude": "2.3522",
    "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120 Safari/537.36",
    "accept_languages": "fr-FR,fr;q=0.9",
    "headers": "X-Screenshot-Run: nightly",
}

r = requests.get("https://shot.screenshotapi.net/v3/screenshot", params=params, timeout=60)
r.raise_for_status()
with open("dashboard.webp", "wb") as f:
    f.write(r.content)

For repeatable tests, keep this configuration in version-controlled, non-secret data and inject the token, cookie, and proxy credentials through environment variables or a secret manager.

Equivalent calls in cURL and Node.js

cURL is useful for isolating Python code from API behavior:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://shot.screenshotapi.net/v3/screenshot" 
  --data-urlencode "token=YOUR_API_KEY" 
  --data-urlencode "url=https://example.com" 
  --data-urlencode "output=image" 
  --data-urlencode "file_type=png" 
  -o screenshot.png

In Node.js, use URLSearchParams so the target URL is encoded correctly:

const q = new URLSearchParams({
  token: 'YOUR_API_KEY',
  url: 'https://example.com',
  output: 'image',
  file_type: 'png'
});
const res = await fetch(`https://shot.screenshotapi.net/v3/screenshot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('screenshot.png', buffer));

Choosing settings for common jobs

Job Recommended configuration Important caveat
Visual regression Fixed user_agent, language, cookies, CSS, and format Changing any of these can create intentional pixel differences.
Authenticated dashboard Short-lived cookies, output=image Expired or domain-mismatched cookies produce a logged-out page.
Localized landing page accept_languages, optional proxy, and coordinates if the page requests geolocation Language, IP region, and browser location can disagree.
Component prototype custom_html, css, PNG External fonts or assets may not load unless reachable by the renderer.
Machine-readable diagnostics output=JSON Do not write the JSON response directly to an image filename.

Troubleshooting and reliable operation

401 or authentication errors

Check that the token is present, has no surrounding whitespace, and belongs to the account making the request. If a key was rolled, the previous key is revoked. Replace it in your secret store and redeploy.

400-level parameter errors

Verify spelling and capitalization, especially output=JSON, file_type, and the URL encoding. Start with only token, url, output=image, and file_type=png; add one option at a time.

The saved file is not a valid image

Inspect the HTTP status before writing bytes and temporarily request output=JSON for render information. An error document saved as .png is still just an error document. Keep the response headers and status in your application logs, but redact tokens, cookies, and proxy credentials.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Blank or partially rendered page

Confirm the URL is reachable from the service, not only from your laptop or private network. Check that required cookies and headers are included, and increase the client timeout for slow pages. If content appears after JavaScript runs, verify that the target page itself reaches a stable state; CSS cannot create content that never loads.

Wrong language, region, or account

Separate the causes: accept_languages affects language negotiation, proxy affects network origin, coordinates affect browser geolocation, and cookies affect session state. Test each in isolation and record the complete non-secret configuration.

Intermittent failures

Use bounded timeouts, retry only transient network or server responses, and apply exponential backoff with a limit. Do not blindly retry invalid credentials or malformed parameters. Store the URL, selected options, status, and a request identifier if supplied by the service so a failed capture can be reproduced.

Performance, security, and cost considerations

Rendering a full browser page is slower and heavier than downloading HTML. Reuse an HTTP session when making many Python requests, set a realistic timeout, and queue captures rather than launching unlimited concurrent calls. Smaller output formats reduce storage and transfer; PNG is preferable when exact pixels matter.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep API keys, cookies, authorization headers, and proxy credentials outside source code and logs. Grant a capture account only the access it needs, use expiring sessions, and delete captured files that contain personal or confidential data. The documented material specifies request options and examples but does not establish a universal latency, quota, uptime, or price figure; check your account’s current terms before budgeting a production workload.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo provides a single-call website screenshot API and MCP server. Its clean-shot pipeline accepts cookie and consent banners, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.

With an API key, this cURL request returns a WebP capture:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python and Node.js equivalents are:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', data));

See the ScreenshotNeo documentation for the full option set. It includes full-page and selector captures, dark mode, device presets and custom viewports, retina scale, PDFs, HTML/CSS rendering, custom JavaScript, clicks, waits, request blocking, headers, cookies, user agents, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify migration. AI agents can use its MCP tools take_screenshot, get_page_info, and capture_pdf.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Plan Allowance and price
Free 1,000 shots/month, no card
Starter $5 for 3,000 shots
Growth $15 for 15,000 shots
Pro $39 for 60,000 shots
Scale $99 for 250,000 shots
Business $249 for 1,000,000 shots

Every feature is included on every plan, and yearly billing gives two months free. Start with 1,000 free screenshots a month with no card, then move to a paid plan starting at $5 for 3,000 shots if your volume requires it.

FAQ

Does Python need a browser installed?

No. The Python program sends HTTP parameters to the hosted rendering endpoint; the browser work happens in the service.

Can I keep the response in memory?

Yes. Use response.content for image or PDF bytes, then upload or process those bytes instead of writing a local file.

Which option changes the page source?

custom_html renders supplied markup and takes precedence over loading the target URL.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can geolocation alone bypass regional restrictions?

No. Coordinates set browser geolocation. A site may instead use IP location, account settings, or another server-side rule; use the relevant proxy, cookies, or headers as well.

Frequently Asked Questions

Does Python need a browser installed?

No. The Python program sends HTTP parameters to the hosted rendering endpoint; the browser work happens in the service.

Can I keep the response in memory?

Yes. Use response.content for image or PDF bytes, then upload or process those bytes instead of writing a local file.

Which option changes the page source?

custom_html renders supplied markup and takes precedence over loading the target URL.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can geolocation alone bypass regional restrictions?

No. Coordinates set browser geolocation. A site may instead use IP location, account settings, or another server-side rule; use the relevant proxy, cookies, or headers as well.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.