Page options

How the browser loads the page before the capture: the device, what to wait for, what to click, what to hide, logins, and when to give up. They work the same on every endpoint that renders a page.

That is /v1/screenshot and /v1/screenshots, /v1/pdf, /v1/markdown and /v1/extract, /v1/animate, /v1/check, /v1/scrape and each URL of a bulk job. Send them as query parameters or JSON fields; booleans take true or false, and a list is comma-separated or a JSON array.

Device and viewport

The screen the page sees: its size and pixel density, phone or desktop, and the visitor's settings.

GET/v1/screenshot
curl -G https://shotlane.dev/v1/screenshot \
  -H "X-API-Key: $SHOTLANE_API_KEY" \
  -d url=developer.mozilla.org \
  -d device=iphone \
  -d dark_mode=true \
  -o mdn-iphone.png
Response200 OK
MDN Web Docs on an iPhone in dark mode: Resources for Developers, by Developers

Parameters

devicestring
A phone, tablet or desktop: its screen size, pixel density, user agent and touch. Ours are desktop, desktop_hd, laptop, ipad, iphone, iphone_se, pixel, galaxy, iphone_duo (Apple's foldable, open) and iphone_duo_cover, plus 200+ real devices such as iphone_17_pro_max or pixel_11_pro (the catalog). A width, height or scale you send overrides its own.
width / heightintegerDefault 1280 / 800
The viewport in CSS pixels, 240–3840 wide and 240–2160 tall. Up to 480 wide, the page gets a phone: mobile emulation and touch.
scalenumberDefault 1
Device pixels per CSS pixel, 1–5 (a device brings its own). 2 gives retina-sharp images. One viewport is at most 74.6 million device pixels (3840 × 2160 at 3).
viewport_landscapebooleanDefault false
Turn a device sideways.
Mobile emulation and touch on or off, whatever the width.
dark_modebooleanDefault false
The visitor prefers a dark theme (prefers-color-scheme: dark).
reduced_motionbooleanDefault true
The visitor has turned on "reduce motion" (prefers-reduced-motion: reduce). Most sites then skip intro animations and moving backgrounds, so the capture doesn't wait for them: stripe.com renders in half the time. false shows the page as a visitor without the setting sees it. Videos have it off.
media_typeenumDefault screen
screen or print, which applies the page's print styles.
timezonestring
An IANA time zone, e.g. America/New_York.
localestringDefault en-US
The browser's language, also sent as Accept-Language, e.g. de-DE.
A location for the page's geolocation API; send both. accuracy is in meters (default 50).
Replace the browser's user agent.

Waiting for the page

By default the capture starts once the page has loaded and what it still loads to show has arrived, at most 2 s later. For pages that fill themselves in later, wait for what you need.

GET/v1/screenshot
curl -G https://shotlane.dev/v1/screenshot \
  -H "X-API-Key: $SHOTLANE_API_KEY" \
  -d url=github.com/microsoft/playwright \
  -d wait_for_selector=article.markdown-body \
  -d timeout=30 \
  -o readme.png
Response200 OK
The Playwright repository on GitHub, captured once its README had rendered

Parameters

wait_untilenum or listDefault load
load, domcontentloaded, networkidle (no requests for 500 ms) or networkidle2 (at most 2 for 500 ms); several are waited for in turn. After load it also waits up to 2 s for what the page still loads to show (scripts, styles, images, videos, fonts and data, not analytics beacons or prefetches), so pages that fade in are complete.
wait_for_selectorstring or list
Wait up to 10 s until this element is visible. Up to 20 selectors; with several, any one of them is enough (see wait_for_selector_algorithm).
wait_for_selector_algorithmenumDefault at_least_one
With several selectors: at_least_one goes on when any of them is visible, at_least_by_count waits for all of them.
Wait up to 15 s until this element is gone, e.g. a loading spinner.
delayintegerDefault 0
Wait this many more milliseconds before the capture, 0–30000.
timeoutintegerDefault 25
Seconds the page may take to load, 5–60.

Interacting with the page

After the page has loaded, these run in this order: hide_selectors (after the clean-up options), css, js, click, hover, delay, then scroll_into_view. The clean-up options run once more before that last step, for dialogs that open late.

GET/v1/screenshot
curl -G https://shotlane.dev/v1/screenshot \
  -H "X-API-Key: $SHOTLANE_API_KEY" \
  -d url=shotlane.dev/pricing \
  --data-urlencode "click=.faq details summary" \
  -d selector=.faq \
  -o faq.png
Response200 OK
The FAQ of shotlane.dev/pricing with its first question opened by the click

Parameters

clickstring
Click the first element this selector matches, e.g. to open a tab or close a modal. A hidden match fails after 8 s, so make the selector match only the one you mean, e.g. .faq details:nth-of-type(3) summary.
hoverstring
Hover the first element this selector matches (desktop widths).
Scroll the first element this selector matches into view.
hide_selectorsstring or list
Hide these elements, e.g. .chat-widget,#promo.
cssstring
CSS added to the page, up to 100,000 characters.
jsstring
JavaScript run in the page, up to 100,000 characters; await works. An error in it fails the render with a 422.
If your js navigates (submits a form, say), wait for the new page: load, domcontentloaded or networkidle.
bypass_cspbooleanDefault false
Ignore the page's Content-Security-Policy, for js that adds inline scripts or styles, uses eval or loads from hosts the policy blocks. css, hide_selectors and the clean-up options work on strict sites without it.
reduce_motionbooleanDefault false
Freeze what still moves: animations and transitions jump to their end and videos pause. reduced_motion, on by default, only tells the page the visitor prefers less motion, and some pages ignore that.
disable_jsbooleanDefault false
Render with JavaScript turned off.
false carries on when the click or hover target is missing, instead of failing with a 422.

Cleaning up the page

Remove what covers the content: consent dialogs, sign-up nags, ads, chat widgets. The lists behind them are updated every week.

GET/v1/screenshot
curl -G https://shotlane.dev/v1/screenshot \
  -H "X-API-Key: $SHOTLANE_API_KEY" \
  -d url=airbnb.com \
  -d hide_cookie_banners=true \
  -d hide_popups=true \
  -d block_ads=true \
  -d block_trackers=true \
  -o airbnb.png
Response200 OK
Airbnb's home page without the cookie dialog it shows visitors in Europe

Parameters

hide_popupsbooleanDefault false
Close sign-in nags and newsletter and app-download modals, with their own close button when there is one. Floating popups, notification prompts and newsletter boxes on Fanboy's Annoyance list are hidden too; signup forms that are part of the page stay.
block_adsbooleanDefault false
Block requests to the 43,000+ ad domains on EasyList (never the site's own domain), hide the ad containers its element rules name, and collapse the empty boxes ads leave.
block_trackersbooleanDefault false
Block requests to the 45,000+ analytics and tracking domains on EasyPrivacy (Google Analytics, Segment, Hotjar…).
block_chatsbooleanDefault false
Block chat widgets: Intercom, Drift, Crisp, Zendesk, HubSpot, Tawk and others.
block_requestsstring or list
Up to 50 URL patterns with * wildcards, e.g. *.mp4,*/ads/*.
block_resourcesstring or list
Resource types to block: image, media, font, stylesheet, script, xhr, fetch, websocket, eventsource, texttrack, manifest, other.

Logins, headers and proxies

For pages behind a login, a firewall or a bot wall. Cookies, headers and passwords go only to the page's own host, never to the third-party resources it loads, and are used for that one request: never stored or logged (details).

GET/v1/markdown
curl -G https://shotlane.dev/v1/markdown \
  -H "X-API-Key: $SHOTLANE_API_KEY" \
  -d url=https://fixtures.shotlane.dev/headers \
  --data-urlencode "authorization=Bearer demo-token" \
  --data-urlencode "cookies=session=abc123"
Response200 OK
```
{
  "headers": {
    "Host": "fixtures.shotlane.dev",
    "Accept-Language": "en-US",
    "Authorization": "Bearer demo-token",
    "Cookie": "session=abc123",
    …
  }
}
```

Parameters

cookiesstring
Cookies for the page as name=value pairs, e.g. session=abc; theme=dark, up to 8,000 characters. They are sent to the page's own host.
headersobject
Extra request headers as a JSON object, e.g. {"Authorization": "Bearer …"}.
Shorthand for an Authorization header, e.g. Bearer eyJ….
user:password for HTTP basic auth.
proxystring
Your own proxy, http://user:pass@host:port (http, https or socks5), or ours for sites that block data centers:

auto loads the page directly, for 1 credit, and only when a bot wall answers tries again through a residential IP, for 10 paid credits instead. Use this one: a residential IP doesn't get past every wall, and a site that lets us in directly can block it.

residential sends every request through a residential IP, 10 paid credits a render (free credits don't cover it).

In a test of 12 sites that block our server (October 2026), a residential IP got through on 6, among them Cloudflare's walls on allrecipes.com, ikea.com and medium.com; DataDome (nytimes.com, etsy.com) and reddit.com blocked it too. A wall isn't charged, within the usual allowance.

Ours works on /v1/screenshot, /v1/pdf, /v1/markdown and /v1/extract. It doesn't load audio or video, and a render through it may move up to 10 MB: past that the page stops loading more, and X-Shotlane-Proxy-Capped: true says so. X-Shotlane-Proxy: residential tells you it was used.

With proxy=auto or residential: the exit's country as a two-letter code, e.g. de or gb. Without it the exit is almost always in the US, so set it for sites that serve by country: from the US, zalando.com shows only its country picker.
proxy_bypass_hostsstring or list
Up to 50 hosts that skip your proxy, e.g. cdn.example.com or *.example.com.

Failing on purpose

Turn a page that isn't what you expect into an error instead of a picture of it. These fail with a 422, and a failed render isn't charged.

GET/v1/screenshot
curl -G https://shotlane.dev/v1/screenshot \
  -H "X-API-Key: $SHOTLANE_API_KEY" \
  -d url=https://fixtures.shotlane.dev/status/404 \
  -d fail_on_status=true
Response422
{
  "error": "The page answered HTTP 404 (fail_on_status is on, so this was not charged).",
  "error_code": "host_returned_error",
  "documentation_url": "https://shotlane.dev/docs/errors#host_returned_error",
  "target_status": 404
}

Parameters

fail_on_statusbooleanDefault false
Fail when the page answers 4xx or 5xx. The page's status is always in the X-Target-Status header.
Fail when the page's text contains this, e.g. Access denied. Up to 20 strings; the error names the matched_string.
Fail when the page's text doesn't contain this, e.g. a product name you expect. Up to 20 strings.
Up to 50 URL patterns with * wildcards: fail when a matching request fails or answers 4xx or 5xx, e.g. */api/*.

Bot walls (Cloudflare, Akamai, DataDome…) aren't charged either, within an allowance: see what isn't charged.

© 2026 Shotlane · Support · Terms · Privacy · Legal notice