Official Python SDK for Rendex — render HTML to images, generate PDFs, and capture screenshots
Project description
rendex
Official Python SDK for Rendex — the HTML-to-image, PDF, and screenshot rendering API. Turn raw HTML or any webpage into an image or PDF with a single function call.
- Full type hints (PEP 561 compatible)
- Single dependency (
httpx) - Sync API with context manager support
- Typed error handling with API error codes
Install
pip install rendex
Quick Start
from pathlib import Path
from rendex import Rendex
rendex = Rendex("your-api-key")
# Render raw HTML straight to a PNG
result = rendex.render_html("<h1>Hello, world</h1>")
Path("hello.png").write_bytes(result.image)
# Or render Markdown (converted to HTML server-side)
md = rendex.render_markdown("# Hello, world\n\nRendered from **Markdown**.")
Path("hello-md.png").write_bytes(md.image)
# Or capture a live URL
shot = rendex.screenshot("https://example.com", format="png", full_page=True)
Path("screenshot.png").write_bytes(shot.image)
print(f"{result.metadata.bytes_size} bytes, loaded in {result.metadata.load_time_ms}ms")
API Reference
Rendex(api_key, *, base_url="https://api.rendex.dev")
Create a new Rendex client.
rendex = Rendex("your-api-key")
# Or with context manager for connection reuse
with Rendex("your-api-key") as rendex:
result = rendex.screenshot("https://example.com")
rendex.screenshot(url, **options)
Capture a screenshot and return the binary image with metadata.
result = rendex.screenshot(
"https://example.com",
format="webp",
width=1920,
height=1080,
dark_mode=True,
)
Path("screenshot.webp").write_bytes(result.image)
print(result.metadata.load_time_ms) # 350
Returns ScreenshotResult:
image—bytesof the captured imagemetadata—ScreenshotMetadatawith url, dimensions, format, bytes_size, load_time_ms, quality, etc.
rendex.render_html(html, **options)
Render raw HTML straight to an image and return the binary result. Convenience wrapper over screenshot(html=...).
result = rendex.render_html("<h1>Hello, world</h1>", format="png", width=1200)
Path("hello.png").write_bytes(result.image)
Returns ScreenshotResult — same shape as screenshot().
You can also pass html directly to screenshot() / screenshot_json():
result = rendex.screenshot(html="<h1>Hello, world</h1>", full_page=True)
HTML rendering is POST-only and accepts up to 5MB. It is not available via
screenshot_url()(the GET endpoint can't carry an HTML body). Provide exactly one ofurl,html, ormarkdown; the SDK raisesRendexErrorlocally if you supply none or more than one.
rendex.render_markdown(markdown, **options)
Render Markdown straight to an image and return the binary result. The server converts the Markdown to HTML before rendering. Convenience wrapper over screenshot(markdown=...).
result = rendex.render_markdown("# Hello, world\n\nRendered from **Markdown**.", format="png", width=1200)
Path("hello.png").write_bytes(result.image)
Returns ScreenshotResult — same shape as screenshot().
You can also pass markdown directly to screenshot() / screenshot_json():
result = rendex.screenshot(markdown="# Hello, world", full_page=True)
Markdown rendering is POST-only and accepts up to 5MB. Like
html, it is not available viascreenshot_url(). Provide exactly one ofurl,html, ormarkdown.
rendex.screenshot_json(url, **options)
Capture a screenshot and return JSON with a base64-encoded image.
result = rendex.screenshot_json("https://example.com")
print(result["data"]["bytesSize"]) # 45823
print(result["meta"]["usage"]["remaining"]) # 499
Returns ScreenshotJsonResponse dict with data (image + metadata) and meta (request ID, usage).
rendex.render_html_json(html, **options)
Render raw HTML and return JSON with a base64-encoded image. Convenience wrapper over screenshot_json(html=...).
result = rendex.render_html_json("<h1>Invoice #1042</h1>", format="pdf", pdf_format="Letter")
print(result["data"]["format"]) # "pdf"
rendex.render_markdown_json(markdown, **options)
Render Markdown and return JSON with a base64-encoded image. The server converts the Markdown to HTML before rendering. Convenience wrapper over screenshot_json(markdown=...).
result = rendex.render_markdown_json("# Invoice #1042", format="pdf", pdf_format="Letter")
print(result["data"]["format"]) # "pdf"
Mustache data templating
Pass a data dict alongside html or markdown to render logic-less Mustache templates before capture. This lets you generate invoices, reports, or any dynamic content without string-formatting Python-side.
from pathlib import Path
from rendex import Rendex
rendex = Rendex("your-api-key")
# Markdown invoice with variable substitution and a loop
template = """
# Invoice \#{{number}}
| Item | Qty | Price |
|------|-----|-------|
{{#items}}
| {{name}} | {{qty}} | {{price}} |
{{/items}}
**Total: {{total}}**
"""
result = rendex.render_markdown(
template,
data={
"number": "1042",
"items": [
{"name": "Screenshot API — Pro", "qty": 1, "price": "€ 49.00"},
{"name": "Overage credits (500)", "qty": 1, "price": "€ 5.00"},
],
"total": "€ 54.00",
},
format="pdf",
pdf_format="A4",
)
Path("invoice-1042.pdf").write_bytes(result.image)
The same data parameter works on render_html, screenshot, screenshot_json, render_html_json, and render_markdown_json.
Template syntax (server-side, logic-less Mustache):
| Syntax | Behaviour |
|---|---|
{{var}} |
HTML-escaped substitution |
{{{var}}} |
Raw (unescaped) substitution |
{{#section}}...{{/section}} |
Render block for each item in a list (or once if truthy) |
{{^section}}...{{/section}} |
Render block when section is falsy / empty |
{{a.b}} |
Nested property access |
datais not valid withurl(the server returns 400). Serialized payload is capped at 256 KB server-side.
rendex.screenshot_url(url, **options)
Generate a GET URL for embedding. No network call — pure URL builder.
url = rendex.screenshot_url("https://example.com", format="png", width=1200)
# Use in <img> tags, OpenGraph, etc.
Note: The API key is included in the URL. Use server-side only.
Async jobs & batches
For long-running captures or many URLs at once, submit work asynchronously and poll for results.
# Single async job: returns immediately, poll for the result
job = rendex.screenshot_json("https://example.com", async_mode=True)
job_id = job["data"]["jobId"]
status = rendex.job_status(job_id)
if status["data"]["status"] == "completed":
print(status["data"]["resultUrl"])
# Batch: 1–500 URLs with shared defaults
batch = rendex.batch(
["https://example.com", "https://github.com"],
defaults={"format": "webp", "full_page": True},
cache_ttl=7200,
)
batch_id = batch["data"]["batchId"]
progress = rendex.batch_status(batch_id)
print(f'{progress["data"]["completedJobs"]}/{progress["data"]["totalJobs"]} done')
rendex.batch(urls, *, defaults=None, webhook_url=None, cache_ttl=None)→BatchCreateResponserendex.job_status(job_id)→JobStatusResponserendex.batch_status(batch_id)→BatchStatusResponse
Batch capture is URL-only (raw HTML is single-request);
defaultsaccepts the same snake_case options asscreenshot().
Screenshot Options
All options are keyword arguments in snake_case. Only url (positional) is required:
| Option | Type | Default | Description |
|---|---|---|---|
format |
str |
"png" |
"png", "jpeg", "webp", or "pdf" |
width |
int |
1280 |
Viewport width (320–3840) |
height |
int |
800 |
Viewport height (240–2160) |
full_page |
bool |
False |
Capture the full scrollable page |
quality |
int |
80 |
JPEG/WebP quality (1–100, default 80) |
delay |
int |
0 |
Delay before capture in ms (0–10000) |
dark_mode |
bool |
False |
Emulate dark mode |
device_scale_factor |
float |
2 |
Device pixel ratio (1–3). 2× Retina by default |
block_ads |
bool |
True |
Block ads and trackers |
block_resource_types |
list |
— | Block: "font", "image", "media", "stylesheet", "other" |
timeout |
int |
30 |
Page load timeout in seconds (5–60) |
wait_until |
str |
"networkidle2" |
"load", "domcontentloaded", "networkidle0", "networkidle2" |
wait_for_selector |
str |
— | CSS selector to wait for |
best_attempt |
bool |
True |
Return best-effort screenshot on timeout |
selector |
str |
— | Capture a specific element by CSS selector |
css / js |
str |
— | Inject custom CSS / JavaScript before capture (max 50KB each) |
cookies / headers |
list / dict |
— | Cookies (max 50) and custom HTTP headers for the request |
user_agent |
str |
— | Override the browser user-agent string |
geo / geo_city / geo_state |
str |
— | Geo-targeted capture (Pro/Enterprise) |
pdf_format |
str |
"A4" |
PDF page size: "A4", "Letter", "Legal", "Tabloid", "A3" (format="pdf") |
pdf_landscape |
bool |
False |
PDF landscape orientation |
pdf_print_background |
bool |
True |
Print background colors/images in the PDF |
pdf_margin |
dict |
— | PDF margins, e.g. {"top": "1cm", "bottom": "1cm"} |
pdf_scale |
float |
1 |
PDF render scale (0.1–2) |
async_mode |
bool |
False |
Return a job ID immediately (sent as async) |
webhook_url |
str |
— | URL to call when an async capture completes |
cache_ttl |
int |
86400 |
Signed result URL TTL in seconds (3600–2592000) |
Error Handling
from rendex import Rendex, RendexApiError, RendexNetworkError
rendex = Rendex("your-api-key")
try:
rendex.screenshot("https://example.com")
except RendexApiError as e:
# API returned an error
print(e.error_code) # "RATE_LIMITED", "VALIDATION_ERROR", etc.
print(e.status_code) # 429, 400, etc.
print(e.request_id) # For debugging with Rendex support
print(e.details) # Validation details (if any)
except RendexNetworkError as e:
# Network failure (DNS, timeout, connection refused)
print(f"Network error: {e}")
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR |
400 | Invalid request parameters |
INVALID_URL |
400 | URL failed SSRF validation |
TIMEOUT |
408 | Page took too long to load |
CAPTURE_FAILED |
500 | Browser rendering error |
RATE_LIMITED |
429 | Rate limit exceeded |
USAGE_EXCEEDED |
429 | Monthly credit limit reached |
MISSING_API_KEY |
401 | No API key provided |
INVALID_API_KEY |
401 | API key verification failed |
License
MIT - Copperline Labs LLC
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rendex-1.4.0.tar.gz.
File metadata
- Download URL: rendex-1.4.0.tar.gz
- Upload date:
- Size: 19.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.5 cpython/3.12.13 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9ed24763d505bfacd9011b9fe6fc5be97c6d482772d160f8b79e72946e45329
|
|
| MD5 |
a1812df0b68d72ba1c77de5cf11b26cd
|
|
| BLAKE2b-256 |
9370fb2793139c9842fdc022c7a4381e3d5e6eed51d6d9d29c275376e1bd5fad
|
File details
Details for the file rendex-1.4.0-py3-none-any.whl.
File metadata
- Download URL: rendex-1.4.0-py3-none-any.whl
- Upload date:
- Size: 13.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.5 cpython/3.12.13 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81f7acad49ca64b9ee6ae81c2c0ce2a84a00f52d257eee55c423d92964fdc25b
|
|
| MD5 |
d4c1facbe2df5d6e16b9aee309ba3a8e
|
|
| BLAKE2b-256 |
9869869702c16bad4dff345f3f62d02e1ea59ae741d4a07def36ab0f669e8c9a
|