Skip to content
AAPIScreenshot
DOCS/ POST /v1/screenshot

API REFERENCE

POST /v1/screenshot

The one endpoint. POST a JSON body, get the image bytes back. Set only the options you want to change.

Endpoint

The full URL is https://api.apiscreenshot.com/v1/screenshot. Authenticate with a Bearer key (see Authentication) and send a JSON body. The response body is the raw image — content-type: image/png (or image/jpeg / image/webp):

{ "url": "https://example.com" }

Source: url or html

Every request must provide exactly one of url or html — sending both, or neither, returns a 400 bad_request. Pass a live url to navigate to and capture, or send a raw html string and APIScreenshot renders exactly that markup in a real managed browser engine (ideal for receipts, OG images and email previews — no need to host a page first).

{ "url": "https://stripe.com/pricing" }
SSRF-safe by default. A url must be an absolute http/https URL. Targets that resolve to a private, loopback, link-local or cloud-metadata address (e.g. 169.254.169.254) are blocked before the browser ever dials them, returning a 400 bad_request. The html body is capped at ~2 MB.

Full page, element & transparency

By default you get the current viewport. Set fullPage: true to scroll and stitch the entire scrollable page. Pass a CSS selector to capture a single element — a hero, a card, a chart — and nothing else (a selector that matches no element returns 400 selector_not_found). omitBackground: true gives you a transparent PNG where the page has no background of its own.

{ "url": "https://example.com", "fullPage": true }

Clean shots: cookie banners & overlays

By default ( blockCookieBanners: true) APIScreenshot cleans the page before capturing: it clicks the reject-all / decline button on the common consent-management platforms (OneTrust, Cookiebot, Quantcast, Didomi, Usercentrics, TrustArc, Osano, CookieYes, Complianz and more), then hides a curated list of cookie/consent/overlay elements and lifts any scroll-lock the banner added — so the shot shows the page, not the pop-up. A built-in page-health guard reverts the clean-up and captures the original page if hiding ever leaves it near-empty, so you never get a blank image. Set blockCookieBanners: false to keep banners, pass hideSelectors to drop your own extra elements, or blockAds: true to also hide common ad slots.

{ "url": "https://example.com" }
Honest caveats. On consent-or-pay paywalls the wall is visually hidden, not legally consented to. And heavily bot-protected sites (aggressive CAPTCHAs / fingerprinting) are out of scope for now — a stealth/proxy tier is on the roadmap.

Viewport & retina

Set the viewport object to control the browser window the page lays out in: width and height (each 1–10000) and an optional deviceScaleFactor ( 0.1–4, default 1). Bump deviceScaleFactor to 2 or 3 for crisp retina output, or shrink the width for tablet and mobile shots.

{
  "url": "https://example.com",
  "viewport": { "width": 1280, "height": 800, "deviceScaleFactor": 2 }
}

PNG, JPEG or WebP

Output is lossless PNG by default. Switch format to "jpeg" or "webp" for smaller files — WebP gives the best size-for-quality on the web — and tune the quality (1–100). quality applies to the lossy formats only — sending it with format: "png" (or no format) returns a 400 bad_request.

{
  "url": "https://example.com",
  "format": "jpeg",
  "quality": 80
}

Waiting for the page

Control when the capture fires. waitUntil chooses the readiness signal — "networkidle2" (the default, ≤2 in-flight requests for 500 ms), "networkidle0" (no in-flight requests), or "load" (the load event, fastest). For client-rendered content, waitForSelector blocks until a specific element appears before capturing. Both are bounded by the 20-second render budget — exceeding it returns a 504 render_timeout.

{ "url": "https://example.com", "waitUntil": "networkidle0" }

Full option reference

OptionTypeDefaultDescription
urlstringThe page to capture (http/https). EXACTLY ONE of url or html is required. SSRF-checked before navigating; private/loopback/link-local/metadata targets are rejected with 400.
htmlstringRaw HTML to render and capture instead of a URL. EXACTLY ONE of url or html is required. Max 2,000,000 bytes (~2 MB).
fullPagebooleanfalseCapture the entire scrollable page, not just the viewport. Ignored when selector is set.
format"png" | "jpeg" | "webp""png"Output image format. PNG is lossless; JPEG and WebP are smaller for thumbnails/previews (WebP gives the best size-for-quality on the web).
qualitynumber (1–100)Compression quality for the lossy formats. Only valid when format is "jpeg" or "webp" — sending it with PNG returns 400.
viewportobject1280×720 @1xBrowser viewport: { width, height, deviceScaleFactor? }. width/height 1–10000; deviceScaleFactor 0.1–4 (default 1; set 2–3 for retina).
selectorstringCSS selector — capture just that element instead of the page. No match returns 400 selector_not_found.
omitBackgroundbooleanfalseRender a transparent background (PNG) where the page has none, instead of the default white.
waitUntil"load" | "networkidle0" | "networkidle2""networkidle2"When navigation/render is considered done. networkidle2 = ≤2 in-flight requests for 500ms; networkidle0 = 0; load = the load event.
waitForSelectorstringWait for this CSS selector to appear before capturing — useful for client-rendered content. Bounded by the 20s render budget.
blockCookieBannersbooleantrueRemove cookie banners, consent popups and overlays before capturing — clicks "reject all" on common CMPs, hides a curated selector list, lifts scroll-lock, and reverts to the original page if it ever over-hides to near-empty. Set false to keep banners.
hideSelectorsstring[]Extra CSS selectors to hide alongside the curated banner list (body-safe; <html>/<body> never touched). Max 50 entries, 500 chars each.
blockAdsbooleanfalseAlso hide common ad/iframe slots (best-effort) during banner removal.

Unknown fields are ignored (forward-compatible), but a malformed known field is rejected by name with a 400 bad_request — e.g. "viewport.width" must be a number between 1 and 10000.

Response

On success: a 200 whose body is the image, with content-type: image/png, image/jpeg or image/webp (matching format) and a content-disposition: inline filename. There is no JSON envelope — write the bytes straight to a file or pipe them to storage. Each successful capture costs one credit; failed requests (any status ≥ 400) are never billed. On failure you get a JSON { error, message } body instead — see Errors.