ScreenshotNeo
API reference

Screenshot API documentation

One endpoint turns a URL or your own HTML into a PNG, JPEG, WebP or PDF. Cookie banners, popups, chat widgets, ads and trackers are handled by default, and only clean, freshly rendered shots count toward your plan. The machine-readable version of this page is openapi.json.

Quick start

Create a key in the dashboard, then:

curl "https://api.screenshotneo.com/v1/shot?access_key=YOUR_KEY&url=https://stripe.com&format=webp" -o stripe.webp

Add full_page=true for the whole page, device=iphone_15 for a phone, format=pdf for a PDF, or response_type=json for a file URL plus the page’s title, description and Open Graph data.

Authentication

Send your key as access_key in the query or JSON body, as an X-Access-Key header, or as Authorization: Bearer YOUR_KEY. Keys are shown once and stored only as a hash; revoke and replace them from the dashboard. Each key also has a signing secret for signed links and webhook signatures.

Endpoints

Method and pathWhat it does
GET /v1/shotCapture a URL; parameters in the query string.
POST /v1/shotThe same with a JSON (or form) body, needed for html, and handy for headers, cookies and scripts.
GET /v1/jobs/{id}State and result of an async job.
POST /v1/bulkQueue up to 100 captures at once.
GET /v1/bulk/{id}Progress of a batch, with every job’s result.
GET /v1/usagePlan, quota, use and reset date for the key’s account.
GET /v1/files/{name}A stored result from a JSON or async response (no key needed; the name can’t be guessed).
POST /mcpMCP server for AI agents (Streamable HTTP).

Input

ParameterValuesWhat it does
urlstringThe page to capture. https:// is added when missing. Private and internal addresses are refused, including through redirects.
htmlstringRaw HTML to render instead of a URL (POST it in a JSON body). Good for Open Graph images and templates. Up to 2 MB.

Output

ParameterValuesWhat it does
formatpng · jpeg · webp · pdfdefault pngOutput format. jpg is accepted for jpeg.
qualityalso image_quality1–100default 80JPEG and WebP quality.
image_widthalso thumb_width, thumbnail_width16–3840Resize the result to this width (thumbnails). With image_height too, the result is cropped to fill both.
image_heightalso thumb_height16–4320Resize the result to this height.
omit_backgroundalso transparenttrue · falsedefault falseTransparent background (PNG and WebP) where the page sets none.
attachment_namealso downloadstringSend the file as a download with this name.

Viewport

ParameterValuesWhat it does
devicealso viewport_devicedesktop · laptop · full_hd · macbook_air · tablet · ipad_air · ipad_pro · mobile · iphone_15 · iphone_15_pro_max · pixel_8 · galaxy_s24A preset that sets width, height, pixel ratio, mobile mode and touch in one go.
widthalso viewport_width320–3840default 1280Browser width in CSS pixels.
heightalso viewport_height240–4320default 800Browser height in CSS pixels.
scalealso device_scale_factor1–3default 1Device pixel ratio. 2 gives a Retina image twice the size.
mobilealso viewport_mobiletrue · falsedefault falseMobile mode: the page’s meta viewport applies and a mobile browser is reported.
touchalso viewport_has_touchtrue · falsedefault falseReport a touch screen.
landscapealso viewport_landscapetrue · falsedefault falseSwap width and height.

Full page and area

ParameterValuesWhat it does
full_pagetrue · falsedefault falseCapture the whole scrollable page, not just the first screen.
full_page_scrolltrue · falsedefault same as full_pageScroll down first so lazy images and sections load.
full_page_max_heightalso max_height500–16000default 16000Stop a full-page capture at this height (useful for endless feeds).
selectorstringCapture only the first element matching this CSS selector.
clipstringCapture a rectangle: x,y,width,height in CSS pixels. clip_x, clip_y, clip_width and clip_height work too.

Waiting

ParameterValuesWhat it does
wait_untilauto · load · domcontentloaded · networkidle0 · networkidle2default autoWhen the page counts as loaded. auto = the load event plus up to 3 seconds for the network to settle.
wait_for_selectoralso wait_forstringWait until an element matching this selector exists (up to 20 seconds). If it never appears, the call fails and isn’t billed.
delay0–20default 0Extra seconds to wait before the capture.
timeout5–90default 40Give up after this many seconds. A timeout isn’t billed.

Cleaning the page

ParameterValuesWhat it does
block_popupstrue · falsedefault trueRemove newsletter popups, full-screen overlays and open dialogs, and unlock scrolling.
block_chatstrue · falsedefault trueRemove chat widgets (Intercom, Drift, Crisp, Zendesk, HubSpot, Tawk and others).
block_adsalso no_adstrue · falsedefault trueBlock ad networks.
block_trackersalso no_trackingtrue · falsedefault trueBlock analytics and tracking scripts.
block_requestsarrayBlock URLs matching these patterns, like *.example.com/widget*. Repeat the parameter or separate with commas.
block_resourcesstylesheet · image · media · font · script · texttrack · xhr · fetch · eventsource · websocket · manifest · otherBlock whole kinds of requests.

Your CSS, JS and clicks

ParameterValuesWhat it does
hide_selectorsalso hide_selectorarrayHide elements matching these selectors. Repeat the parameter for several.
stylesalso cssstringCSS to add to the page before the capture.
scriptsalso jsstringJavaScript to run in the page before the capture; await works. If it throws, the call fails and isn’t billed.
clickstringClick the first element matching this selector, then wait for the page to settle.

Identity and location

ParameterValuesWhat it does
dark_modetrue · falsetrue or false sets prefers-color-scheme; leave it out for the site’s default.
reduced_motiontrue · falsedefault falseSet prefers-reduced-motion: reduce.
media_typealso mediascreen · printEmulate screen or print CSS.
user_agentstringA user agent of your own. By default a current Chrome on Windows (or Android on mobile) is reported.
accept_languagealso accept_langstringdefault en-US,en;q=0.9Accept-Language sent to the site.
headersalso headerarrayExtra request headers as “Name: value”, sent only to the page’s own site. Repeat for several.
cookiesalso cookiearrayCookies as name=value, optionally with ; Domain=… ; Path=…. Repeat for several.
authorizationstringAn Authorization header for the page’s own site, like Basic … or Bearer ….
timezonealso time_zone, tzstringIANA time zone, like Europe/Berlin.
latitudealso geolocation_latitude-90–90Geolocation latitude (with longitude).
longitudealso geolocation_longitude-180–180Geolocation longitude.

PDF

ParameterValuesWhat it does
pdf_paperalso pdf_paper_formata3 · a4 · a5 · letter · legal · tabloiddefault a4Paper size for format=pdf.
pdf_landscapetrue · falsedefault falseLandscape pages.
pdf_backgroundalso pdf_print_backgroundtrue · falsedefault truePrint background colours and images.
pdf_marginstringdefault 0.4inMargin on every side, in px, mm, cm or in.
pdf_page_rangesstringOnly these pages, like 1-3,5.

Checks

ParameterValuesWhat it does
fail_if_content_containsarrayFail (not billed) if the page text contains this. Case-insensitive; repeat for several.
fail_if_content_missingarrayFail (not billed) if the page text doesn’t contain this.
fallbackogog: when a site blocks automated browsers, return its own share image instead of an error.
allow_blockedtrue · falsedefault falseReturn the capture even when it shows a bot check (still not billed).

Caching

ParameterValuesWhat it does
cachetrue · falsedefault falseKeep the result for 24 hours; the same request from your account within that time is served from the cache and isn’t billed.
cache_ttlalso ttl0–2592000Cache for this many seconds instead (up to 30 days). Implies cache=true; 0 turns caching off.
cache_keystringKeep separate cached copies of the same request.
freshalso forcetrue · falsedefault falseRender again even when a cached copy exists.

Response and async

ParameterValuesWhat it does
response_typeimage · json · emptydefault imageimage returns the file; json returns a file URL (kept 24 hours) with page metadata; empty returns only headers.
asynctrue · falsedefault falseQueue the render and answer at once with a job id (202). Poll /v1/jobs/{id} or add webhook_url.
webhook_urlalso webhookstringWe POST the result here when the job finishes, signed with your key’s signing secret. Implies async.
external_idalso external_identifierstringYour own id, returned in the job and the webhook.

Response headers

X-Page-Verdictok, og (share image fallback) or blocked (with allow_blocked=true).
X-Billed1 when this shot counted toward your plan, 0 when it didn’t.
X-CacheHIT when served from your cache (never billed), MISS otherwise.
X-Render-MsHow long the render took, in milliseconds.
X-Quota-RemainingClean shots left in this period.
X-RateLimit-Limit / X-RateLimit-RemainingYour requests per minute, and how many are left in the current minute.
X-Page-StatusThe HTTP status the captured page answered with.
X-Request-IdThe id of this render in your request log.
X-Ignored-ParamsParameters we didn’t recognise, so a typo doesn’t go unnoticed.

JSON responses

With response_type=json you get a link to the file (kept for 24 hours, or your cache time if longer) and what we read from the page:

{
  "id": "1843", "status": "done", "verdict": "ok", "billed": true, "cached": false, "render_ms": 1843,
  "url": "https://github.com",
  "image": { "url": "https://api.screenshotneo.com/v1/files/c5b1…fd.webp", "format": "webp", "width": 1280, "height": 800, "bytes": 41210, "expires_at": "…" },
  "metadata": { "title": "GitHub · Build and ship software…", "description": "…", "language": "en",
    "canonical": "https://github.com/", "favicon": "https://github.githubassets.com/favicons/favicon.svg",
    "final_url": "https://github.com/", "status": 200,
    "og": { "title": "…", "description": "…", "image": "https://…", "site_name": "GitHub", "type": "object" } }
}

Errors

Errors are JSON with an error code and a plain message. Anything that isn’t a clean screenshot is never billed.

StatuserrorMeaning
400bad_requestA parameter is missing or out of range. param names it.
400url_not_allowedNot http(s), or the address is private, local or unresolvable.
401missing_or_invalid_keyNo key, or a revoked one.
402quota_exceededThis period’s clean shots are used up. Upgrade, or wait for the reset date in the message.
403signature_required / bad_signatureThe key only takes signed requests, or the signature doesn’t match.
403email_not_verified / account_disabledConfirm your e-mail in the dashboard, or write to us.
422bot_checkThe site showed a bot check even after a retry. Not billed.
422blank_pageThe page rendered empty. Not billed.
422selector_not_found / script_error / content_check_failedYour selector, script or content check failed. Not billed.
422url_not_allowedThe page redirected to a private address. Not billed.
429rate_limited / concurrency_limitOver your requests per minute, or too many renders at once. Retry-After says when.
502navigation_failed / render_failedThe site couldn’t be loaded or rendered. Not billed.
504timeoutThe page didn’t finish within timeout. Not billed.

Limits and billing

Put a screenshot straight into an <img> without exposing a usable key: sign the query string with your key’s signing secret (HMAC-SHA256, hex) and add it as signature. Change any parameter and the signature stops matching. In the dashboard you can make a key accept signed requests only.

const qs = new URLSearchParams({ access_key: KEY, url: 'https://example.com', format: 'webp' }).toString();
const signature = crypto.createHmac('sha256', SIGNING_SECRET).update(qs).digest('hex');
const src = `https://api.screenshotneo.com/v1/shot?${qs}&signature=${signature}`; // safe to put in an <img>

Async and webhooks

Add async=true (or a webhook_url) and the call returns 202 with a job id at once. Poll /v1/jobs/{id}, or let us POST the result to your webhook. Deliveries retry after 2 s, 15 s and 60 s and carry the same X-ScreenshotNeo-Delivery id each time; X-ScreenshotNeo-Signature is t=timestamp,v1=HMAC-SHA256(secret, timestamp + "." + body).

// Express: check the X-ScreenshotNeo-Signature header before trusting a webhook
const [t, v1] = req.get('x-screenshotneo-signature').split(',').map((p) => p.split('=')[1]);
const want = crypto.createHmac('sha256', SIGNING_SECRET).update(`${t}.${rawBody}`).digest('hex');
if (want !== v1 || Date.now() / 1000 - Number(t) > 300) return res.sendStatus(400);
// X-ScreenshotNeo-Delivery is the same on every retry: store it and drop repeats.

Bulk

curl -X POST https://api.screenshotneo.com/v1/bulk -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" -d '{
  "defaults": { "format": "webp", "image_width": 600 },
  "webhook_url": "https://your.app/hooks/shots",
  "requests": [ { "url": "https://stripe.com" }, { "url": "https://linear.app", "full_page": true } ]
}'

Each request becomes a job in one batch; follow it at /v1/bulk/{batch_id}. Every job is billed like a single call.

MCP for AI agents

Point any MCP client at https://api.screenshotneo.com/mcp with your key as a Bearer token. Tools: take_screenshot, get_page_info and capture_pdf.

{ "mcpServers": { "screenshotneo": { "url": "https://api.screenshotneo.com/mcp", "headers": { "Authorization": "Bearer YOUR_KEY" } } } }

Coming from another API

Most parameter names that other screenshot APIs use work here as they are: viewport_width, device_scale_factor, image_quality, thumbnail_width, css, js, wait_for, no_ads, no_cookie_banners, ttl, time_zone and more (listed under each parameter above). Change the host and the key, and check X-Ignored-Params for anything we don’t know yet.