Screenshots
Capture a web page, a single element, or HTML you send, in current Chrome. 1 credit per successful render.
GET | POST/v1/screenshot
curl "https://shotlane.dev/v1/screenshot?url=example.com&width=1440&scale=2&format=jpeg" \
-H "X-API-Key: $SHOTLANE_API_KEY" -o example.jpg
The response is the image. Every option below works as a query parameter or a JSON field; booleans accept true/false.
| Parameter | Default | Description |
url | — | Page to capture. https:// is assumed if omitted. One of url, html or markdown is required. |
html | — | HTML to render instead of a URL (POST recommended, up to 2 MB). Relative links resolve against nothing, so use absolute URLs for images and styles. |
markdown | — | Markdown rendered as a clean document (tables, code blocks, lists), for example a report an LLM wrote. Up to 1 MB. |
Viewport and device
| Parameter | Default | Description |
device | — | Preset size, scale, user agent and mobile emulation. Ours: desktop, desktop_hd, laptop, ipad, iphone, iphone_se, pixel, galaxy; plus 200+ real devices such as iphone_15_pro_max or galaxy_s9_plus (full list). Overrides width/height. |
viewport_landscape | false | Turn a device preset sideways (swap width and height). |
viewport_mobile
viewport_has_touch | — | Force mobile emulation or touch on or off. Without them, widths up to 480 are mobile with touch. |
width
height | 1280 / 800 | Viewport in CSS pixels, 240–3840 × 240–2160. Widths up to 480 get a mobile user agent and touch emulation. |
scale | 1 | Device scale factor, 1–5. Use 2 for retina-sharp images. Large viewports at high scales are capped by total pixels. |
dark_mode | false | Emulate prefers-color-scheme: dark. |
reduced_motion | false | Emulate prefers-reduced-motion: reduce. |
media_type | screen | print applies the page's print CSS. |
timezone | — | IANA time zone, e.g. America/New_York. |
locale | en-US | Browser language and Accept-Language, e.g. de-DE. |
latitude
longitude | — | Location reported to the page's geolocation API (optional accuracy in meters). |
user_agent | — | Override the browser's user agent. |
What to capture
| Parameter | Default | Description |
full_page | false | The whole scrollable page. The page is scrolled first so lazy-loaded images appear. Very tall pages are cut at 32,000 device pixels; X-Shotlane-Truncated says where. |
full_page_scroll | true | Scroll through the page before capturing so lazy content loads. false captures it as it is. |
full_page_scroll_by
full_page_scroll_delay | — | Pixels per scroll step, and milliseconds to wait after each step (0–2000), for pages that load content slowly. |
full_page_max_height | — | Stop the capture at this many CSS pixels. |
full_page_slices | false | Cut the full page into slices and return JSON with a link per slice: {"url", "slices": [{"index", "offset_y", "width", "height", "url"}]}. Still 1 credit. Good for vision models, which shrink very tall images. |
full_page_slice_height
full_page_slice_overlap_height | 1080 / 0 | Slice height in CSS pixels (200–10000), and how much consecutive slices overlap. |
selector | — | CSS selector: capture only the first matching element. |
clip_x
clip_y
clip_width
clip_height | — | A rectangle in page coordinates (works with full_page). |
omit_background | false | Transparent background for PNG and WebP (when the page doesn't paint its own). |
Page interaction
These run in order after the page loads and before the capture.
| Parameter | Default | Description |
wait_until | load | load, domcontentloaded, networkidle (no requests for 500 ms) or networkidle2 (at most 2 for 500 ms); several values are waited for in turn. With load, Shotlane also waits up to 2 s for the network to go quiet, so pages that fade in are complete. |
wait_for_selector | — | Wait up to 10 s until this element is visible. Several selectors (comma-separated or repeated) wait for all of them. |
wait_for_selector_algorithm | at_least_by_count | With several selectors: at_least_one continues as soon as any is visible. |
wait_to_leave | — | Wait up to 15 s until this element is gone, e.g. a loading spinner. |
delay | 0 | Extra wait in milliseconds (0–30000). |
click | — | CSS selector to click, e.g. to open a tab or close a modal. |
hover | — | CSS selector to hover (desktop widths). |
scroll_into_view | — | CSS selector to scroll into view. |
css | — | CSS injected into the page. |
js | — | JavaScript run in the page (await allowed). Errors return 422. |
scripts_wait_until | — | If your js navigates (e.g. submits a form), wait for this load state of the new page: load, domcontentloaded, networkidle. |
bypass_csp | false | Ignore the page's Content-Security-Policy, so injected css and js run on strict sites. |
reduce_motion | false | Freeze motion before capture: animations and transitions finish instantly and videos pause. (reduced_motion only sets the CSS preference.) |
error_on_selector_not_found
error_on_click_selector_not_found
error_on_hover_selector_not_found | true | false carries on when the selector, click or hover target is missing, instead of failing with 422. |
hide_selectors | — | Comma-separated selectors (or a JSON array) to hide, e.g. .chat-widget,#promo. |
disable_js | false | Render with JavaScript turned off. |
Blocking and cleanup
| Parameter | Default | Description |
hide_cookie_banners | false | Hide consent dialogs and their dimming backdrops, and undo the scroll lock they set: the big consent managers (OneTrust, Cookiebot, Didomi, Usercentrics, Quantcast, Sourcepoint…), the 30,000+ community rules of Fanboy's Cookiemonster list, and a heuristic for the rest. |
block_ads | false | Block requests to the 50,000+ ad domains on EasyList (the site's own domain is never blocked). |
block_trackers | false | Block requests to the 45,000+ analytics and tracking domains on EasyPrivacy (Google Analytics, Segment, Hotjar…). |
block_chats | false | Block chat widgets (Intercom, Drift, Crisp, Zendesk, HubSpot, Tawk…). |
block_requests | — | Comma-separated URL patterns with * wildcards, e.g. *.mp4,*/ads/*. |
block_resources | — | Resource types: image, media, font, stylesheet, script, xhr, fetch, websocket, eventsource, texttrack, manifest, other. |
Logins and networks
| Parameter | Default | Description |
cookies | — | Cookies for the target, session=abc; theme=dark or a JSON list. Used for that request only, never stored or logged (details). |
authorization | — | Shortcut for an Authorization header, e.g. Bearer eyJ…. Same rule: target host only. |
basic_auth | — | user:password for HTTP basic auth, answered only for the target's origin. |
proxy | — | Your own proxy: http://user:pass@host:port (http, https or socks5), e.g. a residential proxy for sites that block data centers. |
proxy_bypass_hosts | — | Comma-separated hosts that skip the proxy, e.g. cdn.example.com. |
Output
| Parameter | Default | Description |
format | png | png, jpeg, webp, avif, gif, tiff, jp2, heif, pdf, html (the rendered page's HTML, after JavaScript) or mhtml (a single-file web archive with images and styles). |
quality | 80 | JPEG, WebP and AVIF quality, 1–100. |
image_width
image_height | — | Resize after capture, e.g. thumbnails. With one side the aspect ratio is kept; with both, image_fit decides. |
image_fit | cover | cover crops (keeps the top), contain pads, fill stretches. |
download | false | Add Content-Disposition: attachment. |
attachment_name | — | File name for the download, e.g. report.pdf (implies download). |
response_type | file | file (the file itself), json (a hosted link and details, see hosted links) or empty (204 with headers only, e.g. after a storage upload or to warm the cache). |
cache_ttl | 0 | Seconds to cache the result (up to 30 days). Identical requests within the TTL are free (caching). cache=true means 4 hours. |
cache_key | — | Any string: identical options with different keys are cached separately, e.g. to refresh one page early. |
external_identifier | — | Your own ID for this request, echoed in JSON responses, webhooks and the X-Shotlane-External-Identifier header. |
storage_bucket | — | Upload to your own S3-compatible bucket instead of returning the file (storage). |
Reliability
| Parameter | Default | Description |
timeout | 25 | Navigation timeout in seconds (5–60). |
fail_on_status | false | Fail with 422 (not charged) when the page answers 4xx or 5xx. The page's status is always in X-Target-Status. |
fail_if_content_contains | — | Fail with 422 (not charged) when the page text contains this string, e.g. Access denied. Repeat it for several; the error names the matched_string. |
fail_if_content_missing | — | Fail with 422 (not charged) when the page text doesn't contain this string, e.g. a product name you expect. |
fail_if_request_failed | — | URL patterns with * wildcards: fail with 422 (not charged) if a matching request fails or answers 4xx/5xx, e.g. */api/*. |
Sites that answer with a bot wall (Cloudflare, Akamai, DataDome…) get X-Shotlane-Blocked and aren't charged. Self-solving challenges are waited out for up to 12 seconds first.
Ask for details about the page in the same call; the response becomes JSON with the file's link and a metadata object (also on /v1/pdf).
curl "https://shotlane.dev/v1/screenshot?url=github.com&metadata_page_title=true&metadata_open_graph=true&metadata_content=true" -H "X-API-Key: $SHOTLANE_API_KEY"
{"url": "https://shotlane.dev/r/….png", "format": "png", "width": 1280, "height": 800,
"metadata": {"page_title": "GitHub · …", "open_graph": {"og:title": "…", "og:image": "…"},
"content": {"url": "https://shotlane.dev/r/….md", "format": "markdown"}}}
Requests with metadata aren't served from the cache, so the details are always current.
Async renders and webhooks
Add async=true (on /v1/screenshot, /v1/pdf, /v1/markdown and /v1/extract) to get a 202 right away and the result later. Invalid parameters still fail at once with a 400.
curl "https://shotlane.dev/v1/screenshot?url=example.com&full_page=true&async=true&webhook_url=https://you.example/hooks/shotlane" -H "X-API-Key: $SHOTLANE_API_KEY"
{"id": "rnd_ktw3iOORiegbshMW", "status": "processing", "status_url": "https://shotlane.dev/v1/renders/rnd_ktw3iOORiegbshMW", …}
Poll GET /v1/renders/{id}, or wait for the signed webhook render.finished. When done, the job has url (the file, kept 24 hours), format, bytes and target_status; with storage_* it has the upload result instead. Failed jobs have status: "failed", error and error_code, and aren't charged.
| Parameter | Default | Description |
async | false | Answer 202 at once and render in the background. |
webhook_url | — | https URL that receives the signed result. |
webhook_errors | false | Also send a render.failed event when the render fails. |
HEAD requests
Send HEAD instead of GET to render into the cache (or your storage) without downloading the result, for example to warm social-card URLs before a launch. It defaults to a 4-hour cache, costs the same credit, and later GETs within the cache time are free.
Coming from ScreenshotOne
ScreenshotOne's parameter names work as they are, so switching is mostly a host change. These names map to ours; when both are sent, ours wins:
| ScreenshotOne | Shotlane |
viewport_width / viewport_height | width / height |
device_scale_factor | scale |
viewport_device | device |
image_quality | quality |
block_cookie_banners | hide_cookie_banners |
block_banners_by_heuristics | hide_popups |
styles / scripts | css / js |
time_zone | timezone |
geolocation_latitude / _longitude / _accuracy | latitude / longitude / accuracy |
pdf_paper_format / pdf_landscape / pdf_print_background | paper / landscape / print_background |
pdf_margin, pdf_margin_top … | margin, margin_top … |
storage_path | storage_key |
cache=true | cache_ttl=14400 |
access_key | access_key (also X-API-Key) |
Examples
A phone screenshot of the whole page, without the cookie banner
curl "https://shotlane.dev/v1/screenshot?url=theguardian.com&device=iphone&full_page=true&hide_cookie_banners=true" \
-H "X-API-Key: $SHOTLANE_API_KEY" -o guardian.png
One element, at 2x
curl "https://shotlane.dev/v1/screenshot?url=github.com/microsoft/playwright&selector=.BorderGrid&scale=2" \
-H "X-API-Key: $SHOTLANE_API_KEY" -o sidebar.png
Your own HTML as a social card
curl -X POST https://shotlane.dev/v1/screenshot -H "X-API-Key: $SHOTLANE_API_KEY" -H "Content-Type: application/json" \
-d '{"html":"<div style=\"font:64px sans-serif;padding:80px\">Hello</div>","width":1200,"height":630}' -o card.png