Python SDK
The official Python SDK for RenderScreenshot. For asyncio, FastAPI, Django and pytest examples, see the Python screenshot API guide.
Installation
pip install renderscreenshot
The package is on PyPI.
Requirements
- Python 3.9 or higher
Quick Start
from renderscreenshot import Client, TakeOptions client = Client('rs_live_xxxxx') # Take a screenshot image = client.take( TakeOptions.url('https://example.com').preset('og_card') ) # Save to file with open('screenshot.png', 'wb') as f: f.write(image)
Client
Constructor
from renderscreenshot import Client client = Client( api_key, base_url=None, timeout=None, signing_key=None, public_key_id=None, )
| Parameter | Type | Description |
|---|---|---|
api_key |
str | Your live API key (rs_live_*) |
base_url |
str | API base URL (default: https://api.renderscreenshot.com) |
timeout |
float | Request timeout in seconds (default: 30.0) |
signing_key |
str | Secret signing key (rs_secret_*). Only needed for generate_url() |
public_key_id |
str | Public key ID (rs_pub_*). Only needed for generate_url() |
Context Manager
The client can be used as a context manager to automatically close connections:
with Client('rs_live_xxxxx') as client: image = client.take(options)
Methods
take(options)
Take a screenshot and return binary data. The SDK sends a POST /v1/screenshot request with a nested JSON body (for example {"viewport": {"width": 1200}, "output": {"format": "png"}}).
image = client.take( TakeOptions.url('https://example.com').preset('og_card') ) # Save to file with open('screenshot.png', 'wb') as f: f.write(image)
Returns: bytes
take_json(options)
Take a screenshot and return JSON metadata. The SDK sends the Accept: application/json header, so the API returns JSON instead of image bytes.
response = client.take_json( TakeOptions.url('https://example.com').preset('og_card') ) print(response['id']) # req_... print(response['image']['url']) # CDN URL print(response['image']['width']) # 1200 print(response['image']['height']) # 630 print(response['cache']['hit']) # True/False print(response['usage']['remaining']) # Credits left
Returns: ScreenshotResponse (TypedDict) with these keys:
| Key | Description |
|---|---|
id |
Request ID (req_...) |
status |
completed (or processing for a request with a webhook, which returns HTTP 202 with a job_... ID) |
image |
url, width, height, size, format |
metadata |
Optional. title |
cache |
Optional. hit, key, url, expires_at |
usage |
Optional. credits, remaining |
generate_url(options, expires_at, *, signing_key=None, public_key_id=None)
Generate a signed URL for public embedding. A signed URL calls the GET /v1/screenshot render endpoint without an API key. Signing needs your public key ID (rs_pub_*) and your secret signing key (rs_secret_*). Your live API key is not used for signing. Keep the secret key on your server.
from datetime import datetime, timedelta client = Client( 'rs_live_xxxxx', signing_key='rs_secret_xxxxx', public_key_id='rs_pub_xxxxx', ) signed_url = client.generate_url( TakeOptions.url('https://example.com').preset('og_card'), datetime.now() + timedelta(hours=24), # max 30 days ) # Use in HTML: <img src="{signed_url}" /> # Or pass the signing credentials per call signed_url = client.generate_url( TakeOptions.url('https://example.com').preset('og_card'), datetime.now() + timedelta(hours=24), signing_key='rs_secret_xxxxx', public_key_id='rs_pub_xxxxx', )
expires_at is a datetime or a Unix timestamp in seconds. The URL contains key_id, expires, the screenshot options as flat query parameters, and a signature. If signing_key or public_key_id is missing, generate_url() raises RenderScreenshotError with the code invalid_request.
A signed URL only carries the options that the GET endpoint reads: url, html, preset, device, width, height, scale, full_page, element, format, quality, delay, wait_for_timeout, click, hide, remove, block_ads, block_cookie_banners, dark_mode, user_agent, locale, timezone, cache_ttl, cache_refresh, and the pdf_* options. Use take() for all other options.
Returns: str
batch(urls, options) / batch(requests)
Process multiple screenshots in a batch.
# Simple batch with shared options results = client.batch( ['https://example1.com', 'https://example2.com'], TakeOptions.url('').preset('og_card'), ) # Advanced batch with per-URL options results = client.batch([ {'url': 'https://example1.com', 'options': {'preset': 'og_card'}}, {'url': 'https://example2.com', 'options': {'width': 1920}}, ])
Returns: BatchResponse (TypedDict)
get_batch(batch_id)
Get the status of a batch job.
status = client.get_batch('batch_abc123') print(status['completed'], status['total'])
Returns: BatchResponse (TypedDict)
presets() / preset(id)
Get available presets.
presets = client.presets() og_card = client.preset('og_card')
devices()
Get available device presets.
devices = client.devices()
TakeOptions
Fluent builder for screenshot options.
Creating Options
from renderscreenshot import TakeOptions # From URL options = TakeOptions.url('https://example.com') # From HTML options = TakeOptions.html('<h1>Hello World</h1>') # From config dict options = TakeOptions.from_config({'url': '...', 'width': 1200})
Viewport Options
options = ( TakeOptions.url('...') .width(1200) # Viewport width .height(630) # Viewport height .scale(2) # Device scale factor (1-3) .mobile() # Enable mobile emulation )
Capture Options
options = ( TakeOptions.url('...') .full_page() # Capture full scrollable page .element('.hero') # Capture specific element .format('png') # png, jpeg, webp, pdf .quality(90) # JPEG/WebP quality (1-100) )
Wait Options
options = ( TakeOptions.url('...') .wait_for('networkidle') # load, networkidle, domcontentloaded .delay(2000) # Additional delay (ms) .wait_for_selector('.loaded') # Wait for selector .wait_for_timeout(30) # Max wait time (s, 1-60) )
Presets & Devices
options = ( TakeOptions.url('...') .preset('og_card') # Use a preset .device('iphone_14_pro') # Emulate a device )
Content Blocking
options = ( TakeOptions.url('...') .block_ads() # Block ad networks .block_trackers() # Block analytics .block_cookie_banners() # Auto-dismiss cookie popups .block_chat_widgets() # Block chat widgets .block_urls(['*.ads.com/*']) # Block URL patterns .block_resources(['font']) # Block resource types )
Browser Emulation
options = ( TakeOptions.url('...') .dark_mode() # Enable dark mode .reduced_motion() # Prefer reduced motion .media_type('print') # screen or print .user_agent('Custom UA') # Custom user agent .timezone('America/New_York') .locale('en-US') .geolocation(40.7128, -74.006) )
Network Options
options = ( TakeOptions.url('...') .headers({'X-Custom': 'value'}) .cookies([{'name': 'session', 'value': 'abc', 'domain': 'example.com'}]) .auth_basic('user', 'pass') # or .auth_bearer('token'); basic wins if both are set .bypass_csp() )
Cache Options
options = ( TakeOptions.url('...') .cache_ttl(86400) # Cache TTL in seconds .cache_available() # Reuse an identical render inside the TTL (0 credits) .cache_refresh() # Force refresh )
PDF Options
options = ( TakeOptions.url('...') .format('pdf') .pdf_paper_size('a4') # a4, letter, legal, etc. .pdf_landscape() .pdf_margin('1in') .pdf_print_background() .pdf_header('<div>Header</div>') .pdf_footer('<div>Page <span class="pageNumber"></span></div>') )
Storage Options (BYOS)
options = ( TakeOptions.url('...') .storage_enabled() .storage_path('{year}/{month}/{hash}.{ext}') .storage_acl('public-read') )
Cache Management
# Get cached screenshot image = client.cache.get('cache_xyz789') # Delete single entry client.cache.delete('cache_xyz789') # Bulk purge by keys client.cache.purge(['cache_abc', 'cache_def']) # Purge by URL pattern client.cache.purge_url('https://mysite.com/blog/*') # Purge by date from datetime import datetime client.cache.purge_before(datetime(2024, 1, 1))
Webhook Helpers
from renderscreenshot import verify_webhook, parse_webhook # Verify signature is_valid = verify_webhook(payload, signature, timestamp, secret) # Parse event event = parse_webhook(payload) # reads the payload's `event` field into event['type'] if event['type'] == 'screenshot.completed': print(event['data']['response']['url']) elif event['type'] == 'screenshot.failed': print(event['data']['error']['code']) # from data.error_code, e.g. 'timeout' print(event['data']['error']['message']) elif event['type'] in ('batch.completed', 'batch.failed'): print(event['data']['batch_id'], event['data'].get('summary'))
Error Handling
from renderscreenshot import Client, TakeOptions, RenderScreenshotError try: client.take(TakeOptions.url('...')) except RenderScreenshotError as e: print(e.http_status) # 400, 429, etc. print(e.code) # 'invalid_url', 'rate_limited' print(e.message) # Human-readable message print(e.retryable) # True/False print(e.retry_after) # Seconds (for rate limits)
Error Codes
| Code | HTTP | Retryable | Description |
|---|---|---|---|
invalid_request |
400 | No | Malformed request |
invalid_url |
400 | No | Invalid URL provided |
unauthorized |
401 | No | Invalid API key |
forbidden |
403 | No | Access denied |
not_found |
404 | No | Resource not found |
rate_limited |
429 | Yes | Rate limit exceeded |
timeout |
408 | Yes | Screenshot timed out |
render_failed |
500 | Yes | Browser rendering failed |
internal_error |
500 | Yes | Internal server error |
Type Hints
The SDK includes full type hints via py.typed marker and TypedDict definitions:
from renderscreenshot import ( Client, TakeOptions, RenderScreenshotError, ScreenshotResponse, BatchResponse, TakeOptionsConfig, )
Links
- GitHub repository
- Python screenshots: desktop vs web page - PyAutoGUI, mss and headless browsers compared
- API Reference