Originally posted on the Scrapio blog — sharing here too.
Screenshots via API have more use cases than you might expect: visual regression testing, monitoring landing pages for unauthorized changes, generating OG image previews, archiving pages, and building internal dashboards with live page previews.
What you'll need
- A Scrapio API key
- curl or Python
Take a basic screenshot
curl -X POST https://api.scrapio.dev/v1/fetch \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"output": ["screenshot"],
"render_js": true
}'
Screenshot output always requires render_js: true — without it, the request is routed to a non-browser executor that can't capture a screenshot and the call fails.
The response contains a screenshot object with a url field pointing to the captured image:
{
"request_id": "req_abc123",
"mode": "inline",
"status": "completed",
"outputs": {
"screenshot": {
"url": "https://storage.scrapio.dev/screenshots/req_abc123.png"
}
},
"usage": { "credits": 2 }
}
Capture a mobile viewport
Pass device: "mobile" to render the page at a mobile viewport:
import httpx
resp = httpx.post(
"https://api.scrapio.dev/v1/fetch",
headers={"Authorization": "Bearer sk-..."},
json={
"url": "https://example.com",
"output": ["screenshot"],
"render_js": True,
"device": "mobile",
},
timeout=30,
)
screenshot_url = resp.json()["outputs"]["screenshot"]["url"]
print(screenshot_url)
device accepts "desktop" (default), "mobile", or "tablet".
Wait for JavaScript content to finish loading
render_js: true is required for every screenshot request. For pages that load content asynchronously, pair it with wait_for:
resp = httpx.post(
"https://api.scrapio.dev/v1/fetch",
headers={"Authorization": "Bearer sk-..."},
json={
"url": "https://example.com/dashboard",
"output": ["screenshot"],
"render_js": True,
"wait_for": {"network_idle": True},
},
timeout=30,
)
screenshot_url = resp.json()["outputs"]["screenshot"]["url"]
wait_for: {network_idle: true} tells Scrapio to hold until all network requests settle before capturing — useful for charts and dashboards that load data asynchronously.
Combine screenshot with markdown
You can request multiple outputs in a single call:
resp = httpx.post(
"https://api.scrapio.dev/v1/fetch",
headers={"Authorization": "Bearer sk-..."},
json={
"url": "https://example.com/article",
"output": ["screenshot", "markdown"],
"render_js": True,
},
timeout=30,
)
outputs = resp.json()["outputs"]
screenshot_url = outputs["screenshot"]["url"]
text = outputs["markdown"]
Visual monitoring workflow
Download the screenshot and diff against a baseline using Pillow:
import httpx
from PIL import Image, ImageChops
import io
def screenshot_url(url: str) -> Image.Image:
resp = httpx.post(
"https://api.scrapio.dev/v1/fetch",
headers={"Authorization": "Bearer sk-..."},
json={"url": url, "output": ["screenshot"], "render_js": True},
timeout=30,
)
img_url = resp.json()["outputs"]["screenshot"]["url"]
img_bytes = httpx.get(img_url).content
return Image.open(io.BytesIO(img_bytes))
def has_visual_change(baseline: Image.Image, current: Image.Image) -> bool:
diff = ImageChops.difference(baseline, current)
return diff.getbbox() is not None
Next steps
- Read the Fetch API docs for all options
- See Website Change Detector for content-based monitoring
Top comments (0)