Capture all your client sites on desktop and mobile with one batch call per device, drop the images into the monthly report, and keep a before and after record of every release.
200 renders a month free, no card. Every feature on every plan.
Try it on your URL
Live capture, no signup. You get the screenshot and the exact API call that produced it.
This is the exact API call that made the image above. Swap in your key and it runs anywhere.
200 renders a month free.
You hit the free demo limit here. The full tool can verify you are human and keep going.
Continue in the full toolMonthly reports need current screenshots of each client site, and someone ends up opening thirty sites on two devices, waiting for consent banners, cropping and pasting. It takes an afternoon a month and the images still show the cookie dialog.
Before and after captures around a release are the proof that a redesign shipped as promised, and they are the ones people forget to take. A capture step in the deploy checklist, or a script someone can run in a minute, fixes that.
Clients increasingly want to see their site in a dashboard instead of a PDF. Embedding a live capture means calling the screenshot API from the browser, which normally means exposing your API key. Signed URLs remove that problem.
SnapRender is the capture layer. The schedule and the history stay in your systems, which keeps your data where your policies say it should be.
The batch endpoint takes one device per call, so a desktop and mobile report is two calls. A short script waits for both, downloads every capture, and names the files by client and device.
import os, pathlib, time, datetime, requests
from urllib.parse import urlparse
API = "https://app.snap-render.com"
HEADERS = {"X-API-Key": os.environ["SNAPRENDER_API_KEY"]}
CLIENTS = ["https://client-one.example", "https://client-two.example"] # up to 50 per batch
DEVICES = {"desktop": None, "mobile": "iphone_14"}
month = datetime.date.today().strftime("%Y-%m")
for label, device in DEVICES.items():
body = {"urls": CLIENTS, "format": "png", "full_page": True}
if device:
body["device"] = device
job = requests.post(f"{API}/v1/screenshot/batch", headers=HEADERS, json=body, timeout=30).json()
while True:
status = requests.get(f"{API}/v1/screenshot/batch/{job['jobId']}", headers=HEADERS, timeout=30).json()
if status["status"] in ("completed", "failed"):
break
time.sleep(5)
for item in status["items"]:
if item["status"] != "completed":
print("failed:", item["url"], item.get("error"))
continue
folder = pathlib.Path("reports") / month / urlparse(item["url"]).hostname
folder.mkdir(parents=True, exist_ok=True)
(folder / f"{label}.png").write_bytes(requests.get(item["downloadUrl"], timeout=60).content)
Two batch calls per month cover every client on both devices. Swap the polling loop for a webhook if the script runs on a server.
# Create once on your server; the URL works in an <img> tag without your key.
curl -s -X POST "https://app.snap-render.com/v1/screenshot/sign" \
-H "X-API-Key: $SNAPRENDER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://client-one.example", "format": "jpeg", "expires_in": 2592000}'
# Response contains "signed_url": "https://app.snap-render.com/v1/screenshot/render?url=...&expires=...&key_prefix=...&sig=..."
# <img src="SIGNED_URL" alt="client-one.example homepage" width="640">
The signature covers the URL and options, so nobody can reuse it for another page. expires_in accepts up to 30 days.
# Run before the deploy and again after it; the file names keep the pair together.
for phase in before after; do
read -p "Press enter to capture the $phase state..."
curl -s "https://app.snap-render.com/v1/screenshot?url=https://client-one.example&format=png&full_page=true" \
-H "X-API-Key: $SNAPRENDER_API_KEY" \
--output "client-one-$(date +%Y%m%d)-$phase.png"
done
Two full-page captures around a release are the proof the client sees in the next report.
Every parameter is in the API reference and the OpenAPI spec. Errors come back as { "error": { "code", "message", "status" } }; a 429 with QUOTA_EXCEEDED means the monthly allowance is used.
Forty client sites on desktop and mobile once a month are 80 renders, inside the free plan. Weekly captures of 100 client sites on two devices are about 870 a month, which is Starter at $9. Agencies that capture after every release or monitor client sites daily usually run on Business at $79.
About 0 renders a month
Free
A month counts as 30 days. Failed captures are refunded. Yearly billing on paid plans is ten months for twelve. All plans.
Get a key and run the first recipe today
Every script on this page works with a free key: 200 renders a month, every feature included, no card. Your first capture takes about two minutes.
Paid plans from $9 for 2,000 renders. Yearly billing is ten months for twelve. Failed captures are refunded.
Each batch uses one set of options, so desktop and mobile are two batch calls. Pass a device preset such as iphone_14 in the second call.
No. Cookie and consent banners are removed and ads are blocked by default, so the captures look like the site, not the consent dialog.
Yes. Create a signed URL on your server with POST /v1/screenshot/sign and use it in an img tag. It is tied to that page and those options, and it expires when you choose, up to 30 days.
No. Items that fail in a batch are refunded to your quota and listed with an error, so you can retry or note them in the report.
The images carry no SnapRender branding or watermark, so they drop straight into your own reports. There is no separate white-label dashboard.
200 renders a month free, no card. The API key is on the next screen.