Documentation / API reference

API reference

Single capture endpoint, exhaustive option list, webhook contract, and errors. Values mirror captureSchema in the application source.

Overview

ScreenNabster exposes /api/v1/capture for all capture types. The same option object works for GET and POST; only the encoding differs. Successful sync responses are raw bytes. Errors are JSON with error, code, and status.

Base URL for this environment: https://screennabster.com

All capture modes are also checked by ScreenNabster's prohibited-use policy before quota is consumed or rendering begins. Blocked targets, suspended accounts, or restricted high-risk features return 403 with a policy-specific error code.

ScreenshotOne-style aliases are documented in the migration guide.

Authentication

Header: X-API-Key: pk_…. Required on every call. Keys are created in the dashboard; inactive or unknown keys return 401.

For public GET links such as <img src>, use access_key, expires (Unix seconds), plus signature. The access key is the public ak_live_* identifier from the dashboard, not the private pk_* API key. The signature is HMAC-SHA256 over the exact query string without the signature parameter, using the signing secret shown once when creating the API key. The URL must not be expired: expires must be in the future and within 15 minutes of the server clock when the request arrives.

curl
curl -X POST "https://screennabster.com/api/v1/capture" \
  -H "X-API-Key: pk_live_your_key" \
  -H "Content-Type: application/json" \
  -d "{\"url\":\"https://example.com\"}" \
  --output out.png

Endpoint

POST https://screennabster.com/api/v1/capture

GET https://screennabster.com/api/v1/capture?…

POST body: JSON object. GET: query parameters with comma-separated arrays and JSON strings where noted in the parameter tables. ScreenNabster accepts its native option names and ScreenshotOne-compatible aliases for common migration paths.

Bulk captures

Use POST /api/v1/capture/bulk for up to 20 synchronous captures. Shared options are merged into each request, and per-request values win. The optional optimize flag (body root, options, or per-request) is accepted for ScreenshotOne migration compatibility and is currently a no-op.

bulk-request.json
{
  "execute": true,
  "options": {
    "format": "png",
    "viewport_width": 1440
  },
  "requests": [
    { "url": "https://example.com" },
    { "url": "https://example.org", "format": "webp" }
  ]
}

Set execute=false to generate signed public capture URLs instead of rendering immediately. Generated URLs include access_key, expires, and signature, so they can be embedded without an X-API-Key header.

curl
curl -X POST "https://screennabster.com/api/v1/capture/bulk" \
  -H "X-API-Key: pk_live_your_key" \
  -H "Content-Type: application/json" \
  -d "{\"execute\":false,\"options\":{\"format\":\"png\"},\"requests\":[{\"url\":\"https://example.com\"}]}"

Target

ParameterTypeRequiredDefaultDescription
urlstring (URL)one of url/html/markdownPublic http(s) page to load. Private IPs, localhost, and metadata hosts are rejected.
htmlstringone of url/html/markdownRaw HTML document to render in the browser instead of navigating to url.
markdownstringone of url/html/markdownMarkdown document to render in the browser instead of navigating to url.

Output

ParameterTypeRequiredDefaultDescription
outputpng | jpg | webp | avif | tiff | gif | pdf | html | markdownoptionalpngRendered MIME type / format. Alias: format (jpeg maps to jpg).
response_modebinary | json | emptyoptionalbinaryReturn raw bytes, base64 JSON metadata, or no body. Alias: response_type=by_format|json|empty.
metadata_iconbooleanoptionalfalseWhen response_mode=json, add resolved favicon URL (`metadata.icon`).
metadata_image_sizebooleanoptionalfalseWhen response_mode=json, add og:image width/height if the image loads in-page.
qualitynumber 0–100optional80Lossy image quality; ignored for PNG.
thumb_widthpositive intoptionalResize output to this width.
thumb_heightpositive intoptionalResize output to this height.
formataliasoptionalScreenshotOne-compatible alias for output.
response_typealiasoptionalScreenshotOne-compatible alias for response_mode.
image_qualityaliasoptionalAlias for quality.
image_widthaliasoptionalAlias for thumb_width.
image_heightaliasoptionalAlias for thumb_height.

Viewport & device

ParameterTypeRequiredDefaultDescription
screen_widthpositive intoptional1280Viewport width in CSS pixels.
screen_heightpositive intoptional800Viewport height in CSS pixels.
viewport_widthaliasoptionalAlias for screen_width.
viewport_heightaliasoptionalAlias for screen_height.
screen_landscapebooleanoptionalfalseSwap width/height for landscape layout.
devicestringoptionalPlaywright device preset name (see worker device catalog) or legacy aliases iPad, Galaxy S21.
viewport_devicealiasoptionalScreenshotOne-compatible alias for device.
device_scale_factornumber 0.5–4optionalOverride device pixel ratio when emulating.

Page behaviour

ParameterTypeRequiredDefaultDescription
page_fullbooleanoptionalfalseCapture the full scrollable page.
full_pagealiasoptionalAlias for page_full.
page_full_scrollbooleanoptionalScroll through the page before a full-page capture to trigger lazy loading.
full_page_scrollaliasoptionalAlias for page_full_scroll.
page_full_scroll_delayint msoptionalDelay between lazy-scroll steps.
full_page_scroll_delayaliasoptionalAlias for page_full_scroll_delay.
page_full_scroll_bypositive intoptionalPixels per lazy-scroll step.
full_page_scroll_byaliasoptionalAlias for page_full_scroll_by.
page_full_max_heightpositive intoptionalCap full-page height for long or infinite pages.
full_page_max_heightaliasoptionalAlias for page_full_max_height.
full_page_algorithmdefault | by_sectionsoptionaldefaultCompatibility flag. by_sections is accepted; current worker still uses Playwright full-page capture.
waitint ms 0–10000optional0Extra sleep before screenshot.
delayaliasoptionalScreenshotOne-compatible alias for wait.
wait_untilload | domcontentloaded | networkidle | commitoptionalloadPlaywright navigation wait condition.
wait_for_selectorstring (CSS)optionalWait until this selector matches before capture.
scroll_tonumberoptionalScroll vertically to this Y offset before capture.
selectorstring (CSS)optionalClip capture to the first matching element’s bounding box.
selector_algorithmdefault | clipoptionaldefaultUse element screenshot or page clip around the element.
selector_scroll_into_viewbooleanoptionaltrueScroll selected element into view before capture.
capture_beyond_viewportbooleanoptionalPass through to Playwright screenshot captureBeyondViewport.
clip_xnumberoptionalManual clip rectangle origin X (viewport coords).
clip_ynumberoptionalManual clip rectangle origin Y.
clip_wnumberoptionalManual clip width.
clip_hnumberoptionalManual clip height.
click_selectorstring (CSS)optionalClick element before capture.
clickaliasoptionalAlias for click_selector.
hover_selectorstring (CSS)optionalHover element before capture.
hoveraliasoptionalAlias for hover_selector.
error_on_click_not_foundbooleanoptionaltrueFail if click_selector missing.
error_on_hover_not_foundbooleanoptionaltrueFail if hover_selector missing.
hide_selectorsstring[]optional[]Selectors to hide (display:none) before capture. GET: comma-separated list.

Appearance & scripting

ParameterTypeRequiredDefaultDescription
theme_darkbooleanoptionalfalsePrefer dark color scheme.
dark_modealiasoptionalAlias for theme_dark.
transparentbooleanoptionalfalseTransparent background where supported (e.g. PNG).
inject_cssstringoptionalCSS injected before capture.
stylesaliasoptionalAlias for inject_css.
inject_jsstringoptionalJavaScript executed in page before capture.
scriptsaliasoptionalAlias for inject_js.

PDF options

ParameterTypeRequiredDefaultDescription
pdf_formatA0 | A1 | A2 | A3 | A4 | A5 | A6 | Letter | Legal | TabloidoptionalA4Printed page size. Lowercase values and pdf_paper_format alias are accepted.
pdf_landscapebooleanoptionalfalseLandscape orientation.
pdf_print_backgroundbooleanoptionaltrueInclude background graphics in PDF.
pdf_fit_one_pagebooleanoptionalfalseFit document dimensions into one PDF page when possible.
media_typescreen | printoptionalprintCSS media emulation before PDF generation.
pdf_marginstringoptionalShorthand margin (CSS length).
pdf_margin_topstringoptionalTop margin override.
pdf_margin_rightstringoptionalRight margin override.
pdf_margin_bottomstringoptionalBottom margin override.
pdf_margin_leftstringoptionalLeft margin override.
pdf_scalenumber 0.1–2optionalScale factor for PDF output.

Cookies

ParameterTypeRequiredDefaultDescription
cookiesobject[] { name, value, domain?, path? }optional[]Cookies set before navigation. GET: JSON string of the array.

Blocking & filters

ParameterTypeRequiredDefaultDescription
strip_adsbooleanoptionalfalseBlock common ad network hosts.
block_adsaliasoptionalScreenshotOne-compatible alias for strip_ads.
filterscookie_banners | ads | popups | chats | trackersoptional[]Content filters applied by the worker. GET: comma-separated.
block_cookie_bannersbooleanoptionalfalseScreenshotOne-style: append cookie_banners to filters when true.
block_chatsbooleanoptionalfalseAppend chats to filters when true.
block_trackersbooleanoptionalfalseAppend trackers to filters when true.
block_banners_by_heuristicsbooleanoptionalfalseHeuristic banner blocking; sets strip_ads when true (native strip_ads still wins if set).
block_resourcesimage | stylesheet | font | media | script | xhr | fetchoptional[]Playwright resource types to abort. GET: comma-separated.

Geolocation

ParameterTypeRequiredDefaultDescription
geo_latnumber −90…90optionalEmulated latitude.
geo_lngnumber −180…180optionalEmulated longitude.
geolocation_latitudealiasoptionalScreenshotOne-compatible alias for geo_lat.
geolocation_longitudealiasoptionalScreenshotOne-compatible alias for geo_lng.
geo_accuracypositive numberoptionalAccuracy in meters.

Browser & HTTP

ParameterTypeRequiredDefaultDescription
localestringoptionalPlaywright context locale (en-US). If both locale and timezone_id are omitted on a URL capture, the server infers them from hostname (apple.de → Germany, paypal.com → en-US).
timezone_idstring (IANA)optionalBrowser timezone; inferred together with locale from URL hostname patterns when omitted.
dismiss_geo_promptsbooleanoptionaltrueWhen true (default), the worker dismisses notable first‑party overlays: Apple geo storefront ribbons on apple.com, and on google.com / www.google.* clicks through Google’s consent interstitial (“Before you continue…” — CMP often loads in a consent.google iframe). That screen is triggered by egress IP/geo; query params like ?hl=en&gl=us tune language/UI copy but do **not** remove the curtain—as your screenshot illustrates. Prefer US egress (`proxy_region=us` when US_PROXY_* is set) to reduce EU-style overlays, or Growth+ filters for many third‑party CMPs.
egress_alignmentdefault | calleroptionalcaller: derive proxy_region per request from CDN geo headers (Vercel x-vercel-ip-country, Cloudflare cf-ipcountry)—EU-ish → eu, rest-of-world → us. Ignored if proxy_region is set. Stripped before the worker receives the payload.
proxy_regionus | eu | autooptionalStarter+: route egress through proxies set as US_PROXY_* / EU_PROXY_* on the worker. auto picks US egress for generic english-commercial hostnames (.com etc.) when env is configured.
browser_agentstringoptionalCustom User-Agent header.
auth_userstringoptionalHTTP Basic username (not stored on async jobs).
auth_passstringoptionalHTTP Basic password (not stored on async jobs).
headersRecord<string, string>optionalExtra request headers. Authorization, Cookie, Host, X-Forwarded-For, and worker secrets are rejected. GET: JSON object string.

Caching & async

ParameterTypeRequiredDefaultDescription
cachedbooleanoptionalfalseUse cached render when available. Alias: cache.
cache_ttlint seconds 14400–2592000optionalSigned cache URL lifetime; defaults to 4 hours.
cache_keystringoptionalCustom key component for distinct cached variants.
backgroundbooleanoptionalfalseQueue job; respond with job_id immediately.
callback_urlstring (URL)optionalHTTPS URL for webhook when background job completes. Failed events require webhook_errors=true.
webhook_errorsbooleanoptionalfalseSend capture.failed webhook payloads when worker rendering fails.
external_identifierstringoptionalAlphanumeric tracking value included in webhook body and X-ScreenNabster-External-Identifier header.

Internal

ParameterTypeRequiredDefaultDescription
storage_bucketstringoptionalReserved for platform use. Do not depend on it in customer integrations.

Async jobs & webhooks

Set background: true. The API responds immediately with:

queue-response.json
{
  "job_id": "uuid",
  "status": "queued",
  "message": "Render queued. Results will be sent to your callback_url."
}

Basic auth credentials are stripped before the job is persisted — only the running worker session receives them. When rendering finishes, our backend uploads the binary to private storage, creates a time-limited signed URL, and POSTs to your callback_url if provided. Failed render events are sent only when webhook_errors is true. If a job cannot be persisted or accepted by the worker after quota is consumed, quota is released.

Webhook headers:

  • Content-Type: application/json
  • X-ScreenNabster-Signature: sha256=<hex> — HMAC-SHA256 of the raw body using SCREENNABSTER_WEBHOOK_SIGNING_SECRET on our side; verify with the same secret on yours (timing-safe compare).
  • X-ScreenNabster-External-Identifier — present when you set external_identifier.

Success payload shape:

webhook-completed.json
{
  "event": "capture.completed",
  "job_id": "uuid",
  "created_at": "2026-04-11T12:00:00.000Z",
  "result_url": "https://…signed…",
  "external_identifier": "customer-job-7"
}

Failure payload shape:

webhook-failed.json
{
  "event": "capture.failed",
  "job_id": "uuid",
  "created_at": "2026-04-11T12:00:00.000Z",
  "error": "Worker error message",
  "error_code": "RENDER_ERROR",
  "external_identifier": "customer-job-7"
}

Webhook delivery is attempted once. Only 2xx responses mark callback_sent_at; non-2xx responses and network failures count as attempts but are not retried automatically yet.

Error codes

JSON body: { "error": string, "code": string, "status": number }. The HTTP status code matches status.

HTTPCodeMeaning
401MISSING_API_KEYNo X-API-Key header was sent.
401INVALID_API_KEY_FORMATKey must start with pk_.
401INVALID_API_KEYKey not found, revoked, or inactive.
401SIGNATURE_REQUIREDPublic access_key GET request is missing a signature.
401SIGNATURE_INVALIDSignature does not match the request query string.
401EXPIRES_REQUIREDSigned GET URLs must include a valid Unix expires parameter covered by the signature.
401SIGNATURE_EXPIREDThe signed URL expires value is in the past (with small clock skew).
401EXPIRES_INVALIDThe expires value is too far in the future; regenerate the URL.
401SIGNATURE_NOT_CONFIGUREDThe API key predates signed URLs; create a new key to get a signing secret.
400CALLBACK_URL_BLOCKEDThe callback URL failed SSRF checks or must use HTTPS.
400INVALID_BODYPOST body is not valid JSON.
400VALIDATION_ERROROptions failed validation (see error text for Zod paths).
403PLAN_REQUIREDThe requested option requires a higher plan tier.
403POLICY_VIOLATIONThe request uses a feature or pattern disallowed by account policy.
403PROHIBITED_TARGETThe target URL or domain is blocked by the prohibited-use policy.
403ACCOUNT_REVIEW_REQUIREDThe account must be reviewed before more captures can be processed.
403ACCOUNT_SUSPENDEDThe account is suspended due to abuse, billing, or policy reasons.
429RATE_LIMIT_EXCEEDEDMonthly request quota for this key/user is exhausted.
500QUEUE_ERRORBackground job could not be written to the queue.
502QUEUE_ERRORWorker rejected or could not accept a background job.
500RENDER_ERRORThe render worker failed or timed out for this capture.