How to Use ScreenshotOne with Python to Capture Website Screenshots
Install ScreenshotOne’s Python SDK, authenticate, choose capture options, and save a website screenshot. Includes full-page tips, troubleshooting, and a one-call alternative.
Use ScreenshotOne’s Python SDK to request a capture and save its image stream to a file. Install the screenshotone package, create a client with your access key and secret key, configure a TakeOptions object, then call client.take(options). The examples below use PNG and an explicit viewport so the output is predictable. See the official Python SDK guide and the complete options reference.
1. Install the SDK and set up credentials
Install the package in the same Python environment that will run your script:
python -m pip install screenshotone
Create access and secret keys in your ScreenshotOne account. Keep both keys out of source control. Supply them through environment variables or your deployment’s secret manager rather than writing real keys into a committed script.
2. Capture a website and save the image
This complete script reads credentials from environment variables, captures a URL as PNG, and writes the returned stream to screenshot.png:
import os
import shutil
from screenshotone import Client, TakeOptions
access_key = os.environ["SCREENSHOTONE_ACCESS_KEY"]
secret_key = os.environ["SCREENSHOTONE_SECRET_KEY"]
client = Client(access_key, secret_key)
options = (
TakeOptions.url("https://example.com")
.format("png")
.viewport_width(1024)
.viewport_height(768)
)
image = client.take(options)
with open("screenshot.png", "wb") as output:
shutil.copyfileobj(image, output)
print("Saved screenshot.png")
Set SCREENSHOTONE_ACCESS_KEY and SCREENSHOTONE_SECRET_KEY in your shell or runtime environment before running the script. The SDK’s documented pattern uses Client, TakeOptions.url(), chained options, and client.take().
3. Choose capture options for the page
Start with the smallest configuration that produces the image you need. Add waiting, full-page capture, or cleanup only when the target page calls for it.
| Need | Option or method | What to consider |
|---|---|---|
| Set image format | .format("png") |
The SDK example selects PNG. The API reference lists multiple image formats, while JPG is the documented default. Verify support before relying on a less common format. |
| Control visible browser size | .viewport_width(1024), .viewport_height(768) |
Set both for repeatable output. A viewport is an emulated browser area, not a physical device. |
| Capture the full page | API option full_page=true |
Full-page capture may scroll to trigger lazy-loaded content; a tall page can need site-specific tuning. |
| Capture one element | API option selector |
A selector is usually more robust than fixed clip coordinates when the page layout changes. |
| Wait for page readiness | wait_until, delay, wait_for_selector |
Choose based on how the page loads. Network-idle waits can stall on pages with ongoing requests. |
| Remove overlays | SDK example: .block_cookie_banners(True), .block_chats(True) |
Effects depend on the target page; inspect the result and adjust if needed. |
| Generate a request URL | client.generate_take_url(options) |
Generates a capture URL without executing the request. Treat any URL containing an access key as sensitive. |
The API also accepts HTML or Markdown input as alternatives to a website URL. Its options documentation describes both GET query parameters and POST JSON bodies; use POST for large HTML or Markdown rather than putting the content in a URL. The documented maximum request body is 100 MiB. Send requests over HTTPS because plain HTTP does not protect credentials or other request values in transit. If signing is required for your account, use the supported signature mechanism; a signature is a hash, not the secret key itself. See the options reference and Getting Started.
4. Capture a full page or dynamic content
For a full-page capture, use the API’s full_page=true option. ScreenshotOne documents scrolling as part of full-page capture to help request lazy-loaded content. Long pages, infinite scrolling, sticky elements, animations, and content revealed only by interaction can still require tuning.
Common adjustments include setting a maximum page height for pages that keep growing, changing the scroll step or delay when lazy images are missed, and trying the section-by-section algorithm if the default full-page capture renders a complex page poorly. Smaller viewport heights trigger more scroll sections and may load more viewport-triggered content, at the cost of additional work. Motion reduction can make captures more consistent when animations are involved, but custom canvas or animated image content may still vary. The service’s full-page guide describes these tradeoffs.
For a page that populates content after initial navigation, consider a selector wait for a stable element, or a short delay if the page has no reliable readiness selector. The documented wait events include load, domcontentloaded, networkidle0, and networkidle2. Network-idle conditions are not universally suitable because live updates, analytics, or streaming connections may keep requests active. See wait options.
5. Alternative request examples
The Python SDK is the direct route for a Python application. These examples show the underlying HTTP request pattern for scripts or services that do not use the SDK. They request PNG output at a fixed viewport; consult ScreenshotOne’s options reference for the exact supported option names and values.
cURL
curl -G "https://api.screenshotone.com/take" \
--data-urlencode "access_key=$SCREENSHOTONE_ACCESS_KEY" \
--data-urlencode "url=https://example.com" \
--data-urlencode "format=png" \
--data-urlencode "viewport_width=1024" \
--data-urlencode "viewport_height=768" \
-o screenshot.png
Python with requests
import os
import requests
response = requests.get(
"https://api.screenshotone.com/take",
params={
"access_key": os.environ["SCREENSHOTONE_ACCESS_KEY"],
"url": "https://example.com",
"format": "png",
"viewport_width": 1024,
"viewport_height": 768,
},
timeout=90,
)
response.raise_for_status()
with open("screenshot.png", "wb") as output:
output.write(response.content)
Node.js
const params = new URLSearchParams({
access_key: process.env.SCREENSHOTONE_ACCESS_KEY,
url: 'https://example.com',
format: 'png',
viewport_width: '1024',
viewport_height: '768',
});
const response = await fetch(
`https://api.screenshotone.com/take?${params}`,
{ signal: AbortSignal.timeout(90000) }
);
if (!response.ok) {
throw new Error(`Screenshot request failed: ${response.status} ${await response.text()}`);
}
await import('node:fs/promises').then(({ writeFile }) =>
writeFile('screenshot.png', Buffer.from(await response.arrayBuffer()))
);
For the raw HTTP examples, check the response status before treating the body as an image: an API error response is not a valid PNG. Query-string credentials can appear in logs or URL histories, so protect request logs and use HTTPS. The API also documents access-key authentication in a POST body or the X-Access-Key header.
6. Get a generated capture URL instead
If another system needs a request URL rather than a downloaded stream, use the SDK’s URL-generation method:
url = client.generate_take_url(options)
print(url)
The URL represents a request; generating it does not itself download and save the image. Because it can contain authentication details, do not publish it or include it in public logs unless your signing and access configuration makes that appropriate.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a screenshot or PDF, without installing or maintaining browser automation. Cookie banners, popups, and chat widgets are removed before the shot; each cleanup step can be turned off. Bot checks, blank pages, and failed loads are never billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
See the ScreenshotNeo API documentation for its options. It also offers Python and Node.js integrations, full-page capture, element capture, format and viewport controls, custom waits, headers and cookies, caching, bulk capture, and async jobs. Visit ScreenshotNeo to learn about the service, then create a free account for 1,000 screenshots a month with no card.
Troubleshooting
| Symptom | Likely cause | What to try |
|---|---|---|
| Authentication fails | Missing, incorrect, or swapped credentials; signing may be required by the account. | Check that the access key and secret key are supplied in the correct order. Confirm environment variables are present in the running process. If signing is enforced, use the SDK/API signing flow rather than putting the secret key in a signature field. |
| The output file contains text or is not an image | The API returned an error response. | For raw HTTP calls, inspect the HTTP status and response body before writing bytes. In Python requests, call raise_for_status(). |
| The screenshot is blank or missing page content | The page may render content after navigation, or a wait condition may finish too early. | Wait for a stable selector or use a modest delay. Try a different wait_until event appropriate to the page. |
| Request times out | The destination is slow or a wait condition never becomes true. | Use a less restrictive readiness condition, remove unnecessary waiting, and check that the target URL is reachable. Avoid assuming network idle will occur on a live page. |
| Lazy images are missing from a full-page capture | Images load only as their region enters the viewport. | Use full-page scrolling and tune its step or delay for the site. A smaller viewport height can cause more scroll events, which may help but takes longer. |
| Full-page output is distorted or unexpectedly clipped | The page layout, sticky elements, animation, or capture algorithm may interact poorly with a single tall render. | Try the documented section-by-section full-page algorithm, reduce motion, and adjust the viewport or maximum page height. |
| Different runs look different | Dynamic content, animation, time, locale, or IP-based regional content changed. | Use consistent viewport and wait settings. If the site localizes, align the relevant language header, timezone, and IP region; they control different aspects of localization. |
Python cannot import screenshotone |
The package may have been installed into a different Python environment. | Run python -m pip install screenshotone with the same interpreter used to run the script. |
Performance, reliability, and cost considerations
- Wait only as long as the page needs. Extra delays and overly strict network-idle waits add latency. Start with the default behavior and add a selector wait or delay when you observe missing content.
- Full-page work takes more care. Scrolling and section capture can improve lazy-loaded content, but quality adjustments can reduce performance. Limit maximum height on pages with unbounded scrolling.
- Use stable inputs for repeatability. Specify the viewport and format, and account for locale and time-dependent content when comparing captures.
- Handle failures as failures. Check API errors before writing or forwarding binary data; set an HTTP timeout appropriate to the page and retry only errors that are transient for your application.
- Pricing evidence is not established here. The reviewed official documentation does not establish current ScreenshotOne pricing or plan limits, so check its current account and pricing information before estimating production cost.
- Protect credentials and generated URLs. Use HTTPS, runtime secrets, and careful request logging. The access key is a credential even when carried as a query parameter.
FAQ
Does client.take() return a filename?
No. The documented SDK method returns an image stream. Open a file in binary mode and copy the stream into it, as shown above.
Can I create a URL without capturing immediately?
Yes. client.generate_take_url(options) creates the request URL without executing the capture.
Should I use PNG or JPG?
Use the format that suits your output. PNG is explicit in the SDK example; the API reference says JPG is the default. Confirm support if you depend on a less common format.
Can a full-page capture guarantee every dynamic section appears?
No single setting guarantees that across sites. Lazy loading, infinite scroll, and animations may require site-specific wait and scroll adjustments.


