An automated screenshot that shows half the page under a cookie banner, a chat widget in the corner and grey boxes where lazy images should be is not useful to anyone. Each of these has a specific cause, and each has an option in POST /v1/screenshot.
Start with a clean request#
curl https://rendersbolt.com/v1/screenshot \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://stripe.com","format":"webp","block_ads":true,"block_cookie_banners":true}' \
-o stripe.webp
block_cookie_bannershides consent pop-ups from the common consent platforms and unlocks scrolling that a banner has blocked.block_adsblocks ad and tracker requests using the EasyList, EasyPrivacy and uBlock filter lists. Pages usually load faster without them, too.
Lazy images and full pages#
Many sites load images only when they scroll into view, so a full-page capture taken straight away shows empty frames. With "full_page": true the page is scrolled to the bottom first, so lazy images load, and then captured from the top. Full pages are capped at 16,000 pixels tall.
For pages that keep loading after the load event:
"wait_until": "networkidle"waits until the network has been quiet, for at most 5 seconds."wait_for_selector": ".hero img"waits until a specific element is visible."delay": 1500adds a fixed pause in milliseconds as a last resort.
CSS animations and transitions are stopped before the capture, so you don't catch a menu halfway through sliding in.
Hide what you don't want#
Chat bubbles, promo bars and "back to top" buttons aren't cookie banners, so you hide them yourself:
{
"url": "https://example.com",
"hide_selectors": ["#intercom-container", ".promo-bar", ".back-to-top"],
"css": "header { position: static !important; }"
}
hide_selectors takes up to 50 CSS selectors. css is injected before the capture. The example turns a sticky header back into a normal one, so it doesn't repeat over the content in a full-page shot.
Social images and link previews#
For Open Graph images, set the viewport to 1200×630 and capture only the viewport:
{ "url": "https://example.com/blog/launch", "viewport": { "width": 1200, "height": 630 }, "format": "png" }
Add "device_scale_factor": 2 for a sharp image on high-density screens. That gives a 2400×1260 file, so webp with "quality": 85 keeps it small.
To capture one component, such as a pricing table or a chart, pass a CSS selector:
{ "url": "https://example.com/pricing", "selector": "#plans", "omit_background": true }
omit_background gives a transparent PNG where the page has no background of its own.
Dark mode and locale#
"dark_mode": truesetsprefers-color-scheme: dark, so sites with a dark theme render in it."locale": "tr-TR"and"timezone": "Europe/Istanbul"give you the Turkish version of a site that adapts to the visitor, with local dates.
Using it straight in an image tag#
Every endpoint also accepts GET with query parameters, and the key can go in access_key:
<img src="https://rendersbolt.com/v1/screenshot?url=https://github.com&viewport_width=1200&viewport_height=630&format=webp&access_key=sk_live_...">
Anyone who can see that HTML can read the key. Use this only on pages that you alone see, such as an internal dashboard. For public pages, render on your server and store the image.
When it still doesn't look right#
- Check the
X-Target-Statusresponse header. A 404 or 403 page is still rendered, and the header tells you that is what you got. - Sites with an interactive bot challenge can't be captured.
- If a capture times out, raise
timeout(up to 30,000 ms) or dropnetworkidleon pages that never go quiet, such as pages with live tickers.
Every option is listed in the screenshot reference.