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.

Input

ParameterDefaultDescription
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

ParameterDefaultDescription
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_landscapefalseTurn 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 / 800Viewport in CSS pixels, 240–3840 × 240–2160. Widths up to 480 get a mobile user agent and touch emulation.
scale1Device scale factor, 1–5. Use 2 for retina-sharp images. Large viewports at high scales are capped by total pixels.
dark_modefalseEmulate prefers-color-scheme: dark.
reduced_motionfalseEmulate prefers-reduced-motion: reduce.
media_typescreenprint applies the page's print CSS.
timezone—IANA time zone, e.g. America/New_York.
localeen-USBrowser 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

ParameterDefaultDescription
full_pagefalseThe 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_scrolltrueScroll 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_slicesfalseCut 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 / 0Slice 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_backgroundfalseTransparent 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.

ParameterDefaultDescription
wait_untilloadload, 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_algorithmat_least_by_countWith 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.
delay0Extra 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_cspfalseIgnore the page's Content-Security-Policy, so injected css and js run on strict sites.
reduce_motionfalseFreeze 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
truefalse 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_jsfalseRender with JavaScript turned off.

Blocking and cleanup

ParameterDefaultDescription
block_adsfalseBlock requests to the 50,000+ ad domains on EasyList (the site's own domain is never blocked).
block_trackersfalseBlock requests to the 45,000+ analytics and tracking domains on EasyPrivacy (Google Analytics, Segment, Hotjar…).
block_chatsfalseBlock chat widgets (Intercom, Drift, Crisp, Zendesk, HubSpot, Tawk…).
hide_popupsfalseClose sign-in nags, newsletter and app-download modals, using their own close button when there is one.
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

ParameterDefaultDescription
cookies—Cookies for the target, session=abc; theme=dark or a JSON list. Used for that request only, never stored or logged (details).
headers—Extra HTTP headers as JSON, e.g. {"Authorization":"Bearer …"}. Sent only to the target's host, never to third-party resources.
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

ParameterDefaultDescription
formatpngpng, 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).
quality80JPEG, 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_fitcovercover crops (keeps the top), contain pads, fill stretches.
downloadfalseAdd Content-Disposition: attachment.
attachment_name—File name for the download, e.g. report.pdf (implies download).
response_typefilefile (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_ttl0Seconds 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

ParameterDefaultDescription
timeout25Navigation timeout in seconds (5–60).
fail_on_statusfalseFail 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.

Metadata with the screenshot

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).

ParameterDefaultDescription
metadata_page_titlefalseThe page's <title>.
metadata_open_graphfalseOpen Graph and Twitter card tags.
metadata_iconfalseThe favicon URL.
metadata_fontsfalseFonts used for visible text: [{"first", "fallback", "loaded"}].
metadata_http_response_status_code
metadata_http_response_headers
falseThe page's own HTTP status and response headers.
metadata_image_sizefalseWidth and height of the image in pixels.
metadata_contentfalseThe page's content as a hosted link: Markdown of the main content by default, or the rendered HTML with metadata_content_format=html.
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.

ParameterDefaultDescription
asyncfalseAnswer 202 at once and render in the background.
webhook_url—https URL that receives the signed result.
webhook_errorsfalseAlso send a render.failed event when the render fails.

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:

ScreenshotOneShotlane
viewport_width / viewport_heightwidth / height
device_scale_factorscale
viewport_devicedevice
image_qualityquality
block_cookie_bannershide_cookie_banners
block_banners_by_heuristicshide_popups
styles / scriptscss / js
time_zonetimezone
geolocation_latitude / _longitude / _accuracylatitude / longitude / accuracy
pdf_paper_format / pdf_landscape / pdf_print_backgroundpaper / landscape / print_background
pdf_margin, pdf_margin_top …margin, margin_top …
storage_pathstorage_key
cache=truecache_ttl=14400
access_keyaccess_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