Shotbot Screenshot API (2)

Download OpenAPI specification:

Capture any public URL as JPEG, PNG, WebP, AVIF, or PDF.

Authentication: include your 12-character alphanumeric API key as key in every POST request body. No HTTP headers required.

Result CDN: https://static.shotbot.net/{token[0]}/{token[0..1]}/{token}.{format} Example: token 4XyZaBd2…https://static.shotbot.net/4/4X/4XyZaBd2….jpg

Pro subscription unlocks all formats (PNG / WebP / AVIF / PDF), custom viewport widths (280-3840 px), URLs with custom TCP ports, wait up to 30 s, and advanced options (scroll_before_capture, block_ads, http_auth, crop_height, cookies, selector, autoplay_videos, omit_background, emulate_print_media, non-default render_region). Subscribe at https://shotbot.net/pro/

Typical flow

  1. POST /capture → get token
  2. Poll GET /capture/{token} every ~2 s until status is done or failed
  3. Download image URL from the CDN

Or use POST /capture/callback and let Shotbot push the result to your webhook.

Private captures (private: true): the result is not published on static.shotbot.net. The done response carries a download URL on api.shotbot.net that streams the file; you can fetch it as many times as you like until it auto-expires after a short retention window. Useful when the captured page is sensitive (intranet, account dashboards…).

Single

Submit and poll a single capture

Submit a capture

Submit a URL for screenshot capture. Returns immediately with a token. Poll GET /capture/{token} until status is done or failed.

If the same URL was already submitted within the last 60 seconds by the same account, the existing token is returned (deduplicated: true) without consuming quota.

If quota and credits are both exhausted, the request is queued in a wait list (status: waitlisted) and will be processed at the next monthly quota reset.

Request Body schema: application/json
required
preset
string
Default: ""
Enum: "" "og" "mobile" "youtube_thumbnail" "square" "reel" "pinterest" "tablet" "desktop" "desktop_hd" "twitter_header" "linkedin_banner" "hero_banner"

Named output preset. When set, fills missing viewport_width, output_size, and crop_height with the preset's defaults. Explicit values still win over preset defaults.

Preset Output Tier
og 1200×630 free
mobile 390×844 free
youtube_thumbnail 1280×720 free
square 1080×1080 free
reel 1080×1920 free
pinterest 1000×1500 free
tablet 768×1024 free
desktop 1440×900 Pro
desktop_hd 1920×1080 Pro
twitter_header 1500×500 Pro
linkedin_banner 1584×396 Pro
hero_banner 1920×600 Pro

Omit preset (or pass "") for the default 1280×800 (16:10). crop_height from a preset is always accepted (otherwise Pro-only).

viewport_width
integer [ 280 .. 3840 ]
Default: 1280

Browser viewport width in pixels. Default: 1280. Common labelled widths: 360, 375, 390, 414, 430, 768, 1024, 1200, 1280, 1440, 1920. Non-Pro accounts are limited to 390, 768, 1280. Shotbot Pro may also pass any custom width between 280 and 3840 px, useful for CSS / responsive testing at arbitrary breakpoints. A value outside the allowed set returns 400 invalid_viewport_width. Filled automatically when preset is set and this field is omitted.

output_size
integer
Enum: 120 160 240 320 390 480 640 768 1024 1080 1200 1280 1440 1500 1584 1920

Output image width in pixels. Defaults to viewport_width when omitted. Values not in the enum are replaced with viewport_width. Filled automatically when preset is set and this field is omitted.

ratio
string
Default: "16:9"
Enum: "16:9" "4:3" "16:10" "3:2" "2:1" "1:1" "9:16" "3:4" "10:16" "2:3" "1:2"

Aspect ratio used to compute output height. Ignored when fullpage is true or crop_height is set.

crop_height
integer [ 10 .. 30000 ]

Custom output height in pixels. Overrides ratio. Triggers a full-page capture; the result is cropped from the top to this height. Maximum: 20,000 px. Pro only when set explicitly. Free accounts can use it via the preset parameter (e.g. preset=og provides crop_height=630 without Pro).

fullpage
boolean
Default: false

Capture the full page height (max 30,000 px). Ignores ratio.

format
string
Default: "jpg"
Enum: "jpg" "png" "webp" "webp_lossless" "avif" "pdf"

Output format. Non-Pro accounts are limited to jpg.

hidpi
boolean
Default: false

Render at 2× device pixel ratio (HiDPI / Retina).

color_scheme
string or null
Enum: "dark" "light" null

Force a color scheme before capture. "dark" emits prefers-color-scheme: dark, "light" emits prefers-color-scheme: light. Omit (or pass null) to use the browser default.

render_region
string
Default: "fr-paris"
Enum: "fr-paris" "ca-montreal" "sg-singapore" "au-sydney" "vn-hanoi"

Geographic region the rendering worker exits from. The browser is routed through a SOCKS5 proxy in the chosen region and its locale, timezone, and geolocation are emulated to match.

Region key shape: country-city (ISO 3166 alpha-2 country code, then city name, dash-separated; multi-word cities use dashes too).

Value Egress Timezone Locale
fr-paris Paris, France Europe/Paris fr-FR
ca-montreal Montreal, Canada America/Montreal en-CA
sg-singapore Singapore Asia/Singapore en-SG
au-sydney Sydney, Australia Australia/Sydney en-AU
vn-hanoi Hanoi, Vietnam Asia/Ho_Chi_Minh vi-VN

Use to capture geo-restricted content, regionally localised pages, currency or banner variants, or to verify what a page looks like from a given market. Pro only for non-fr-paris values; non-Pro accounts may omit the field or pass "fr-paris".

nojs
boolean
Default: false

Disable JavaScript execution before capture.

autoplay_videos
boolean
Default: false

Launch Chromium with --autoplay-policy=no-user-gesture-required so <video autoplay> elements start playing (including unmuted videos) without requiring a user gesture. Useful for capturing pages with hero videos that would otherwise show a static poster frame. Default Chromium policy blocks unmuted autoplay; this flag overrides it.

No effect on PDF captures (no playback) or when the page itself has no <video autoplay>. Pro only.

prefers_reduced_motion
boolean
Default: false

Emulate the prefers-reduced-motion: reduce CSS media feature. Well-built sites use this to skip or shorten their animations (framer-motion, GSAP, AOS, IntersectionObserver reveals), which makes captures cleaner | no half-played transitions, no mid-animation frames. No effect on sites that don't honour the media query. Available to all accounts.

omit_background
boolean
Default: false

Render with a transparent background (omitBackground: true on the underlying Chromium screenshot). The page's own background colour is preserved; only the default white viewport backdrop becomes transparent. Useful when capturing components or pages designed to sit on a host page's background.

Visible on png / webp / avif. jpg has no alpha channel so transparency flattens to black on conversion (silent no-op). Has no effect on PDF output. Pro only.

emulate_print_media
boolean
Default: false

Call page.emulateMediaType('print') before capture so the page renders with its print stylesheet (@media print rules apply). Useful for capturing print-only layouts as an image. Has no additional effect on PDF output (PDFs already render in print mode). Pro only.

wait_time
integer [ 0 .. 30 ]
Default: 5

Seconds to wait after page load before capturing (0 = capture immediately after page load). Free accounts: 0-5. Shotbot Pro: 0-30 (longer waits help JavaScript-heavy / slow pages). A free request above 5 s is rejected with pro_required (or clamped to 5 s on the wait_time alias path). Alias: wait (accepted for backward compatibility).

dismiss_cookies
string
Default: ""
Enum: "" "accept" "reject"

Auto-interact with cookie consent banners. Pro only. "" (default) = leave the banner visible, "accept" = click accept, "reject" = click reject.

frame
string
Default: ""
Enum: "" "rounded" "shadow" "browser_chrome" "browser_chrome_dark" "mobile" "mobile_light" "tablet" "tablet_light" "laptop" "polaroid" "gradient" "shotbot_brand"

Decorative frame composited around the rendered image (image formats only, silently ignored for PDF).

Variant Effect
"" (default) No frame
rounded Rounded screenshot corners (~12 px radius), no padding, dimensions unchanged
shadow Drop shadow + rounded corners, edge-sampled padding
browser_chrome Simulated browser window with address bar + traffic lights
browser_chrome_dark Same browser window, dark palette
mobile Generic smartphone mockup with dark bezel (pair with the mobile preset)
mobile_light Smartphone mockup with a light (silver) bezel
tablet Generic tablet mockup with dark bezel (pair with the tablet preset)
tablet_light Tablet mockup with a light (silver) bezel
laptop Laptop mockup (dark screen bezel + silver base)
polaroid White border, thick bottom, square corners, soft drop shadow
gradient Rounded screenshot floated on a lime-accent gradient backdrop
shotbot_brand Lime-green corner brackets (free tier integrates the `shotbot.fr

Most variants extend OUTSIDE the requested output_size (final image is larger by ~20-100 px depending on variant). rounded is the exception | dimensions stay the same, only the corner pixels are clipped. Padding around shadow/shotbot_brand is edge-sampled from the rendered image so dark themes get dark padding.

Free accounts get a small shotbot.fr / shotbot.net wordmark on any non-empty frame (domain picked per the captured page's language). For shotbot_brand the wordmark is integrated into the bottom-right bracket itself rather than overlaid. Pro accounts get a clean frame on ALL variants, including shotbot_brand (brackets only, no wordmark). No Pro gating on the choice of variant itself | all values are available to everyone.

PNG/WebP/AVIF formats render transparent pixels outside the mockup bezel (real see-through corners). JPG has no alpha channel so those areas flatten to black.

scroll_before_capture
boolean
Default: false

Scroll the page before capturing (triggers lazy-loaded images). Pro only.

scroll_offset_px
integer [ 0 .. 30000 ]
Default: 0

Scroll the page down by this many pixels before capturing (no scroll back), so the viewport frame starts at Y=N. Runs after scroll_before_capture. Mutually exclusive with scroll_to (sending both returns 400 invalid_scroll_combo). No-op for fullpage, PDF, and selector captures. Out of range returns 400 invalid_scroll_offset. Not available on the web form. Pro only.

scroll_to
string <= 500 characters

CSS selector to scrollIntoView before capturing, so the matched element sits at the top of the viewport frame. Unlike selector (which clips output to the element), scroll_to only positions the page, then captures the normal viewport. Runs after scroll_before_capture. Mutually exclusive with scroll_offset_px (400 invalid_scroll_combo). If the selector matches no element it is a no-op (the job still succeeds). No-op for fullpage, PDF, and selector captures. Not available on the web form. Pro only.

block_ads
boolean
Default: false

Block ad network requests during capture. Pro only.

object

HTTP Basic Auth credentials for password-protected pages. Pro only.

pdf_page_size
string
Default: "A4"
Enum: "A4" "A3" "A5" "Letter" "Legal" "Tabloid"

PDF page size. Only used when format is pdf.

pdf_margin_mm
integer [ 0 .. 50 ]
Default: 10

PDF page margin in mm. Only used when format is pdf.

pdf_scale
number [ 0.1 .. 2 ]
Default: 1

PDF rendering scale factor. Only used when format is pdf.

pdf_landscape
boolean
Default: false

PDF landscape orientation. Only used when format is pdf.

selector
string <= 500 characters

CSS selector of the DOM element to screenshot. Only the matched element is captured and resized to output_size. Ignored when format is pdf. The job fails with nav_error if the selector matches no element or if the matched element exceeds 30,000 px in height. Not available on the web form. Pro only.

private
boolean
Default: false

Private capture. When true, the result is not uploaded to static.shotbot.net. Instead, the response from GET /capture/{token} includes a download URL pointing at https://api.shotbot.net/capture/{token}/file, which streams the bytes. The file is not deleted on read: you can fetch it as many times as you like until it auto-expires after a short retention window. There is no public CDN URL.

The web preview ({token}_p.webp) is also skipped - the response has no preview field for private captures.

Deduplication is disabled for private captures (each call produces a fresh token with its own file).

Available to all accounts (not Pro-gated).

Array of objects <= 50 items

Cookies to inject before navigation. Useful for capturing authenticated pages without HTTP Basic Auth. Each entry must include name and value. If domain is omitted, the cookie is scoped to the target URL's domain. Maximum 50 cookies. Pro only.

key
required
string^[0-9A-Za-z]{12}$

Your 12-character alphanumeric API key.

url
required
string <uri>

Target URL. Must be a public http/https URL (no private IPs, no localhost). URLs with a non-standard TCP port (e.g. http://staging.example.com:8080/) require a Pro subscription; submitting one without Pro returns 403 pro_required with fields: ["url"].

Responses

Request samples

Content type
application/json
Example
{}

Response samples

Content type
application/json
Example
{
  • "job_id": 1843221,
  • "token": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  • "status": "queued",
  • "eta_seconds": 17
}

Submit a capture with webhook callback

Submit a URL for capture with webhook delivery of the result. No polling required - Shotbot POSTs the result image (multipart) to your callback_url when the capture is complete.

If callback_secret is set, the worker echoes it back in the callback POST. Verify authenticity on your side with hash_equals($secret, $received_secret).

On failure the worker POSTs status=ERR to your callback URL.

The callback_url must use HTTPS and resolve to a public IP (SSRF protection). DNS rebinding is mitigated by re-validation on the worker side.

Request Body schema: application/json
required
preset
string
Default: ""
Enum: "" "og" "mobile" "youtube_thumbnail" "square" "reel" "pinterest" "tablet" "desktop" "desktop_hd" "twitter_header" "linkedin_banner" "hero_banner"

Named output preset. When set, fills missing viewport_width, output_size, and crop_height with the preset's defaults. Explicit values still win over preset defaults.

Preset Output Tier
og 1200×630 free
mobile 390×844 free
youtube_thumbnail 1280×720 free
square 1080×1080 free
reel 1080×1920 free
pinterest 1000×1500 free
tablet 768×1024 free
desktop 1440×900 Pro
desktop_hd 1920×1080 Pro
twitter_header 1500×500 Pro
linkedin_banner 1584×396 Pro
hero_banner 1920×600 Pro

Omit preset (or pass "") for the default 1280×800 (16:10). crop_height from a preset is always accepted (otherwise Pro-only).

viewport_width
integer [ 280 .. 3840 ]
Default: 1280

Browser viewport width in pixels. Default: 1280. Common labelled widths: 360, 375, 390, 414, 430, 768, 1024, 1200, 1280, 1440, 1920. Non-Pro accounts are limited to 390, 768, 1280. Shotbot Pro may also pass any custom width between 280 and 3840 px, useful for CSS / responsive testing at arbitrary breakpoints. A value outside the allowed set returns 400 invalid_viewport_width. Filled automatically when preset is set and this field is omitted.

output_size
integer
Enum: 120 160 240 320 390 480 640 768 1024 1080 1200 1280 1440 1500 1584 1920

Output image width in pixels. Defaults to viewport_width when omitted. Values not in the enum are replaced with viewport_width. Filled automatically when preset is set and this field is omitted.

ratio
string
Default: "16:9"
Enum: "16:9" "4:3" "16:10" "3:2" "2:1" "1:1" "9:16" "3:4" "10:16" "2:3" "1:2"

Aspect ratio used to compute output height. Ignored when fullpage is true or crop_height is set.

crop_height
integer [ 10 .. 30000 ]

Custom output height in pixels. Overrides ratio. Triggers a full-page capture; the result is cropped from the top to this height. Maximum: 20,000 px. Pro only when set explicitly. Free accounts can use it via the preset parameter (e.g. preset=og provides crop_height=630 without Pro).

fullpage
boolean
Default: false

Capture the full page height (max 30,000 px). Ignores ratio.

format
string
Default: "jpg"
Enum: "jpg" "png" "webp" "webp_lossless" "avif" "pdf"

Output format. Non-Pro accounts are limited to jpg.

hidpi
boolean
Default: false

Render at 2× device pixel ratio (HiDPI / Retina).

color_scheme
string or null
Enum: "dark" "light" null

Force a color scheme before capture. "dark" emits prefers-color-scheme: dark, "light" emits prefers-color-scheme: light. Omit (or pass null) to use the browser default.

render_region
string
Default: "fr-paris"
Enum: "fr-paris" "ca-montreal" "sg-singapore" "au-sydney" "vn-hanoi"

Geographic region the rendering worker exits from. The browser is routed through a SOCKS5 proxy in the chosen region and its locale, timezone, and geolocation are emulated to match.

Region key shape: country-city (ISO 3166 alpha-2 country code, then city name, dash-separated; multi-word cities use dashes too).

Value Egress Timezone Locale
fr-paris Paris, France Europe/Paris fr-FR
ca-montreal Montreal, Canada America/Montreal en-CA
sg-singapore Singapore Asia/Singapore en-SG
au-sydney Sydney, Australia Australia/Sydney en-AU
vn-hanoi Hanoi, Vietnam Asia/Ho_Chi_Minh vi-VN

Use to capture geo-restricted content, regionally localised pages, currency or banner variants, or to verify what a page looks like from a given market. Pro only for non-fr-paris values; non-Pro accounts may omit the field or pass "fr-paris".

nojs
boolean
Default: false

Disable JavaScript execution before capture.

autoplay_videos
boolean
Default: false

Launch Chromium with --autoplay-policy=no-user-gesture-required so <video autoplay> elements start playing (including unmuted videos) without requiring a user gesture. Useful for capturing pages with hero videos that would otherwise show a static poster frame. Default Chromium policy blocks unmuted autoplay; this flag overrides it.

No effect on PDF captures (no playback) or when the page itself has no <video autoplay>. Pro only.

prefers_reduced_motion
boolean
Default: false

Emulate the prefers-reduced-motion: reduce CSS media feature. Well-built sites use this to skip or shorten their animations (framer-motion, GSAP, AOS, IntersectionObserver reveals), which makes captures cleaner | no half-played transitions, no mid-animation frames. No effect on sites that don't honour the media query. Available to all accounts.

omit_background
boolean
Default: false

Render with a transparent background (omitBackground: true on the underlying Chromium screenshot). The page's own background colour is preserved; only the default white viewport backdrop becomes transparent. Useful when capturing components or pages designed to sit on a host page's background.

Visible on png / webp / avif. jpg has no alpha channel so transparency flattens to black on conversion (silent no-op). Has no effect on PDF output. Pro only.

emulate_print_media
boolean
Default: false

Call page.emulateMediaType('print') before capture so the page renders with its print stylesheet (@media print rules apply). Useful for capturing print-only layouts as an image. Has no additional effect on PDF output (PDFs already render in print mode). Pro only.

wait_time
integer [ 0 .. 30 ]
Default: 5

Seconds to wait after page load before capturing (0 = capture immediately after page load). Free accounts: 0-5. Shotbot Pro: 0-30 (longer waits help JavaScript-heavy / slow pages). A free request above 5 s is rejected with pro_required (or clamped to 5 s on the wait_time alias path). Alias: wait (accepted for backward compatibility).

dismiss_cookies
string
Default: ""
Enum: "" "accept" "reject"

Auto-interact with cookie consent banners. Pro only. "" (default) = leave the banner visible, "accept" = click accept, "reject" = click reject.

frame
string
Default: ""
Enum: "" "rounded" "shadow" "browser_chrome" "browser_chrome_dark" "mobile" "mobile_light" "tablet" "tablet_light" "laptop" "polaroid" "gradient" "shotbot_brand"

Decorative frame composited around the rendered image (image formats only, silently ignored for PDF).

Variant Effect
"" (default) No frame
rounded Rounded screenshot corners (~12 px radius), no padding, dimensions unchanged
shadow Drop shadow + rounded corners, edge-sampled padding
browser_chrome Simulated browser window with address bar + traffic lights
browser_chrome_dark Same browser window, dark palette
mobile Generic smartphone mockup with dark bezel (pair with the mobile preset)
mobile_light Smartphone mockup with a light (silver) bezel
tablet Generic tablet mockup with dark bezel (pair with the tablet preset)
tablet_light Tablet mockup with a light (silver) bezel
laptop Laptop mockup (dark screen bezel + silver base)
polaroid White border, thick bottom, square corners, soft drop shadow
gradient Rounded screenshot floated on a lime-accent gradient backdrop
shotbot_brand Lime-green corner brackets (free tier integrates the `shotbot.fr

Most variants extend OUTSIDE the requested output_size (final image is larger by ~20-100 px depending on variant). rounded is the exception | dimensions stay the same, only the corner pixels are clipped. Padding around shadow/shotbot_brand is edge-sampled from the rendered image so dark themes get dark padding.

Free accounts get a small shotbot.fr / shotbot.net wordmark on any non-empty frame (domain picked per the captured page's language). For shotbot_brand the wordmark is integrated into the bottom-right bracket itself rather than overlaid. Pro accounts get a clean frame on ALL variants, including shotbot_brand (brackets only, no wordmark). No Pro gating on the choice of variant itself | all values are available to everyone.

PNG/WebP/AVIF formats render transparent pixels outside the mockup bezel (real see-through corners). JPG has no alpha channel so those areas flatten to black.

scroll_before_capture
boolean
Default: false

Scroll the page before capturing (triggers lazy-loaded images). Pro only.

scroll_offset_px
integer [ 0 .. 30000 ]
Default: 0

Scroll the page down by this many pixels before capturing (no scroll back), so the viewport frame starts at Y=N. Runs after scroll_before_capture. Mutually exclusive with scroll_to (sending both returns 400 invalid_scroll_combo). No-op for fullpage, PDF, and selector captures. Out of range returns 400 invalid_scroll_offset. Not available on the web form. Pro only.

scroll_to
string <= 500 characters

CSS selector to scrollIntoView before capturing, so the matched element sits at the top of the viewport frame. Unlike selector (which clips output to the element), scroll_to only positions the page, then captures the normal viewport. Runs after scroll_before_capture. Mutually exclusive with scroll_offset_px (400 invalid_scroll_combo). If the selector matches no element it is a no-op (the job still succeeds). No-op for fullpage, PDF, and selector captures. Not available on the web form. Pro only.

block_ads
boolean
Default: false

Block ad network requests during capture. Pro only.

object

HTTP Basic Auth credentials for password-protected pages. Pro only.

pdf_page_size
string
Default: "A4"
Enum: "A4" "A3" "A5" "Letter" "Legal" "Tabloid"

PDF page size. Only used when format is pdf.

pdf_margin_mm
integer [ 0 .. 50 ]
Default: 10

PDF page margin in mm. Only used when format is pdf.

pdf_scale
number [ 0.1 .. 2 ]
Default: 1

PDF rendering scale factor. Only used when format is pdf.

pdf_landscape
boolean
Default: false

PDF landscape orientation. Only used when format is pdf.

selector
string <= 500 characters

CSS selector of the DOM element to screenshot. Only the matched element is captured and resized to output_size. Ignored when format is pdf. The job fails with nav_error if the selector matches no element or if the matched element exceeds 30,000 px in height. Not available on the web form. Pro only.

private
boolean
Default: false

Private capture. When true, the result is not uploaded to static.shotbot.net. Instead, the response from GET /capture/{token} includes a download URL pointing at https://api.shotbot.net/capture/{token}/file, which streams the bytes. The file is not deleted on read: you can fetch it as many times as you like until it auto-expires after a short retention window. There is no public CDN URL.

The web preview ({token}_p.webp) is also skipped - the response has no preview field for private captures.

Deduplication is disabled for private captures (each call produces a fresh token with its own file).

Available to all accounts (not Pro-gated).

Array of objects <= 50 items

Cookies to inject before navigation. Useful for capturing authenticated pages without HTTP Basic Auth. Each entry must include name and value. If domain is omitted, the cookie is scoped to the target URL's domain. Maximum 50 cookies. Pro only.

key
required
string^[0-9A-Za-z]{12}$

Your 12-character alphanumeric API key.

url
required
string <uri>

Target URL. Must be a public http/https URL (no private IPs, no localhost). URLs with a non-standard TCP port (e.g. http://staging.example.com:8080/) require a Pro subscription; submitting one without Pro returns 403 pro_required with fields: ["url"].

callback_url
required
string <uri>

HTTPS endpoint where Shotbot will POST the result (multipart image). Must use HTTPS and resolve to a public IP address.

callback_secret
string <= 255 characters

Optional shared secret. Shotbot echoes it back in the callback POST body. Compare with hash_equals to verify webhook authenticity.

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{
  • "job_id": 1843222,
  • "token": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  • "status": "queued",
  • "eta_seconds": 17
}

Poll capture status

Poll the status of a submitted capture. No API key required - the 32-character token is a bearer: anyone who holds it can read the status and download the result.

Poll every ~2 seconds. A queued response includes eta_seconds as a hint.

Result image URLs follow the pattern: https://static.shotbot.net/{token[0]}/{token[0..1]}/{token}.{format}

path Parameters
token
required
string^[A-Za-z0-9]{32}$
Example: 4XyZaBd2E1lk39PQ7m8r5wN0c6f4H2g1

32-character alphanumeric token returned by POST /capture

Responses

Response samples

Content type
application/json
Example
{
  • "token": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
  • "status": "queued",
  • "format": "jpg",
  • "viewport_width": 1280,
  • "output_size": 1280,
  • "output_height": 720,
  • "ratio": "16:9",
  • "fullpage": false,
  • "eta_seconds": 18
}

Download a private capture

Download the binary result of a private capture (private: true on submission). The file is not deleted on read: you can fetch it as many times as you like until it auto-expires after a short retention window, after which you get 410 Gone.

This endpoint is the only way to retrieve a private capture: the bytes are not on static.shotbot.net, and there is no other URL.

Authentication is by token: the 32-character alphanumeric token returned at submission acts as a bearer credential. Anyone holding it can read the file.

path Parameters
token
required
string^[A-Za-z0-9]{32}$

32-character alphanumeric token from POST /capture (with private: true).

Responses

Response samples

Content type
application/json
Example
{
  • "error": "not_found"
}

Batch

Submit up to 500 (Pro 5000) captures in one request

Submit a batch of captures

Submit up to 500 URLs (Pro accounts: up to 5000) in a single request.

Global options (top-level) apply to all jobs. Per-job options override globals for that specific job.

Quota is allocated atomically in a single transaction. If quota runs out mid-batch, remaining jobs go to the wait list. Deduplication (60 s window, same account + URL) is applied before quota consumption.

The response contains a per-job status for each submitted URL: queued, waitlisted, or error.

To receive results via webhook instead of polling, include a global callback_url. All jobs in the batch then become callback jobs.

Idempotency

Batch submission is expensive: large batches with slow DNS can exceed transport timeouts and produce 504 responses on the client side, while server-side processing continues. Naive retry then creates duplicate jobs.

Send an idempotency_key (16-128 chars [A-Za-z0-9_.-]) to make retries safe: a second batch with the same key from the same account, within 24 h, returns the original response (X-Idempotent-Replay: true header) without creating new jobs or deducting quota.

Recommended pattern: generate a UUID before the first call, retry with the same UUID on transport/parse errors, drop it on success.

Request Body schema: application/json
required
preset
string
Default: ""
Enum: "" "og" "mobile" "youtube_thumbnail" "square" "reel" "pinterest" "tablet" "desktop" "desktop_hd" "twitter_header" "linkedin_banner" "hero_banner"

Named output preset. When set, fills missing viewport_width, output_size, and crop_height with the preset's defaults. Explicit values still win over preset defaults.

Preset Output Tier
og 1200×630 free
mobile 390×844 free
youtube_thumbnail 1280×720 free
square 1080×1080 free
reel 1080×1920 free
pinterest 1000×1500 free
tablet 768×1024 free
desktop 1440×900 Pro
desktop_hd 1920×1080 Pro
twitter_header 1500×500 Pro
linkedin_banner 1584×396 Pro
hero_banner 1920×600 Pro

Omit preset (or pass "") for the default 1280×800 (16:10). crop_height from a preset is always accepted (otherwise Pro-only).

viewport_width
integer [ 280 .. 3840 ]
Default: 1280

Browser viewport width in pixels. Default: 1280. Common labelled widths: 360, 375, 390, 414, 430, 768, 1024, 1200, 1280, 1440, 1920. Non-Pro accounts are limited to 390, 768, 1280. Shotbot Pro may also pass any custom width between 280 and 3840 px, useful for CSS / responsive testing at arbitrary breakpoints. A value outside the allowed set returns 400 invalid_viewport_width. Filled automatically when preset is set and this field is omitted.

output_size
integer
Enum: 120 160 240 320 390 480 640 768 1024 1080 1200 1280 1440 1500 1584 1920

Output image width in pixels. Defaults to viewport_width when omitted. Values not in the enum are replaced with viewport_width. Filled automatically when preset is set and this field is omitted.

ratio
string
Default: "16:9"
Enum: "16:9" "4:3" "16:10" "3:2" "2:1" "1:1" "9:16" "3:4" "10:16" "2:3" "1:2"

Aspect ratio used to compute output height. Ignored when fullpage is true or crop_height is set.

crop_height
integer [ 10 .. 30000 ]

Custom output height in pixels. Overrides ratio. Triggers a full-page capture; the result is cropped from the top to this height. Maximum: 20,000 px. Pro only when set explicitly. Free accounts can use it via the preset parameter (e.g. preset=og provides crop_height=630 without Pro).

fullpage
boolean
Default: false

Capture the full page height (max 30,000 px). Ignores ratio.

format
string
Default: "jpg"
Enum: "jpg" "png" "webp" "webp_lossless" "avif" "pdf"

Output format. Non-Pro accounts are limited to jpg.

hidpi
boolean
Default: false

Render at 2× device pixel ratio (HiDPI / Retina).

color_scheme
string or null
Enum: "dark" "light" null

Force a color scheme before capture. "dark" emits prefers-color-scheme: dark, "light" emits prefers-color-scheme: light. Omit (or pass null) to use the browser default.

render_region
string
Default: "fr-paris"
Enum: "fr-paris" "ca-montreal" "sg-singapore" "au-sydney" "vn-hanoi"

Geographic region the rendering worker exits from. The browser is routed through a SOCKS5 proxy in the chosen region and its locale, timezone, and geolocation are emulated to match.

Region key shape: country-city (ISO 3166 alpha-2 country code, then city name, dash-separated; multi-word cities use dashes too).

Value Egress Timezone Locale
fr-paris Paris, France Europe/Paris fr-FR
ca-montreal Montreal, Canada America/Montreal en-CA
sg-singapore Singapore Asia/Singapore en-SG
au-sydney Sydney, Australia Australia/Sydney en-AU
vn-hanoi Hanoi, Vietnam Asia/Ho_Chi_Minh vi-VN

Use to capture geo-restricted content, regionally localised pages, currency or banner variants, or to verify what a page looks like from a given market. Pro only for non-fr-paris values; non-Pro accounts may omit the field or pass "fr-paris".

nojs
boolean
Default: false

Disable JavaScript execution before capture.

autoplay_videos
boolean
Default: false

Launch Chromium with --autoplay-policy=no-user-gesture-required so <video autoplay> elements start playing (including unmuted videos) without requiring a user gesture. Useful for capturing pages with hero videos that would otherwise show a static poster frame. Default Chromium policy blocks unmuted autoplay; this flag overrides it.

No effect on PDF captures (no playback) or when the page itself has no <video autoplay>. Pro only.

prefers_reduced_motion
boolean
Default: false

Emulate the prefers-reduced-motion: reduce CSS media feature. Well-built sites use this to skip or shorten their animations (framer-motion, GSAP, AOS, IntersectionObserver reveals), which makes captures cleaner | no half-played transitions, no mid-animation frames. No effect on sites that don't honour the media query. Available to all accounts.

omit_background
boolean
Default: false

Render with a transparent background (omitBackground: true on the underlying Chromium screenshot). The page's own background colour is preserved; only the default white viewport backdrop becomes transparent. Useful when capturing components or pages designed to sit on a host page's background.

Visible on png / webp / avif. jpg has no alpha channel so transparency flattens to black on conversion (silent no-op). Has no effect on PDF output. Pro only.

emulate_print_media
boolean
Default: false

Call page.emulateMediaType('print') before capture so the page renders with its print stylesheet (@media print rules apply). Useful for capturing print-only layouts as an image. Has no additional effect on PDF output (PDFs already render in print mode). Pro only.

wait_time
integer [ 0 .. 30 ]
Default: 5

Seconds to wait after page load before capturing (0 = capture immediately after page load). Free accounts: 0-5. Shotbot Pro: 0-30 (longer waits help JavaScript-heavy / slow pages). A free request above 5 s is rejected with pro_required (or clamped to 5 s on the wait_time alias path). Alias: wait (accepted for backward compatibility).

dismiss_cookies
string
Default: ""
Enum: "" "accept" "reject"

Auto-interact with cookie consent banners. Pro only. "" (default) = leave the banner visible, "accept" = click accept, "reject" = click reject.

frame
string
Default: ""
Enum: "" "rounded" "shadow" "browser_chrome" "browser_chrome_dark" "mobile" "mobile_light" "tablet" "tablet_light" "laptop" "polaroid" "gradient" "shotbot_brand"

Decorative frame composited around the rendered image (image formats only, silently ignored for PDF).

Variant Effect
"" (default) No frame
rounded Rounded screenshot corners (~12 px radius), no padding, dimensions unchanged
shadow Drop shadow + rounded corners, edge-sampled padding
browser_chrome Simulated browser window with address bar + traffic lights
browser_chrome_dark Same browser window, dark palette
mobile Generic smartphone mockup with dark bezel (pair with the mobile preset)
mobile_light Smartphone mockup with a light (silver) bezel
tablet Generic tablet mockup with dark bezel (pair with the tablet preset)
tablet_light Tablet mockup with a light (silver) bezel
laptop Laptop mockup (dark screen bezel + silver base)
polaroid White border, thick bottom, square corners, soft drop shadow
gradient Rounded screenshot floated on a lime-accent gradient backdrop
shotbot_brand Lime-green corner brackets (free tier integrates the `shotbot.fr

Most variants extend OUTSIDE the requested output_size (final image is larger by ~20-100 px depending on variant). rounded is the exception | dimensions stay the same, only the corner pixels are clipped. Padding around shadow/shotbot_brand is edge-sampled from the rendered image so dark themes get dark padding.

Free accounts get a small shotbot.fr / shotbot.net wordmark on any non-empty frame (domain picked per the captured page's language). For shotbot_brand the wordmark is integrated into the bottom-right bracket itself rather than overlaid. Pro accounts get a clean frame on ALL variants, including shotbot_brand (brackets only, no wordmark). No Pro gating on the choice of variant itself | all values are available to everyone.

PNG/WebP/AVIF formats render transparent pixels outside the mockup bezel (real see-through corners). JPG has no alpha channel so those areas flatten to black.

scroll_before_capture
boolean
Default: false

Scroll the page before capturing (triggers lazy-loaded images). Pro only.

scroll_offset_px
integer [ 0 .. 30000 ]
Default: 0

Scroll the page down by this many pixels before capturing (no scroll back), so the viewport frame starts at Y=N. Runs after scroll_before_capture. Mutually exclusive with scroll_to (sending both returns 400 invalid_scroll_combo). No-op for fullpage, PDF, and selector captures. Out of range returns 400 invalid_scroll_offset. Not available on the web form. Pro only.

scroll_to
string <= 500 characters

CSS selector to scrollIntoView before capturing, so the matched element sits at the top of the viewport frame. Unlike selector (which clips output to the element), scroll_to only positions the page, then captures the normal viewport. Runs after scroll_before_capture. Mutually exclusive with scroll_offset_px (400 invalid_scroll_combo). If the selector matches no element it is a no-op (the job still succeeds). No-op for fullpage, PDF, and selector captures. Not available on the web form. Pro only.

block_ads
boolean
Default: false

Block ad network requests during capture. Pro only.

object

HTTP Basic Auth credentials for password-protected pages. Pro only.

pdf_page_size
string
Default: "A4"
Enum: "A4" "A3" "A5" "Letter" "Legal" "Tabloid"

PDF page size. Only used when format is pdf.

pdf_margin_mm
integer [ 0 .. 50 ]
Default: 10

PDF page margin in mm. Only used when format is pdf.

pdf_scale
number [ 0.1 .. 2 ]
Default: 1

PDF rendering scale factor. Only used when format is pdf.

pdf_landscape
boolean
Default: false

PDF landscape orientation. Only used when format is pdf.

selector
string <= 500 characters

CSS selector of the DOM element to screenshot. Only the matched element is captured and resized to output_size. Ignored when format is pdf. The job fails with nav_error if the selector matches no element or if the matched element exceeds 30,000 px in height. Not available on the web form. Pro only.

private
boolean
Default: false

Private capture. When true, the result is not uploaded to static.shotbot.net. Instead, the response from GET /capture/{token} includes a download URL pointing at https://api.shotbot.net/capture/{token}/file, which streams the bytes. The file is not deleted on read: you can fetch it as many times as you like until it auto-expires after a short retention window. There is no public CDN URL.

The web preview ({token}_p.webp) is also skipped - the response has no preview field for private captures.

Deduplication is disabled for private captures (each call produces a fresh token with its own file).

Available to all accounts (not Pro-gated).

Array of objects <= 50 items

Cookies to inject before navigation. Useful for capturing authenticated pages without HTTP Basic Auth. Each entry must include name and value. If domain is omitted, the cookie is scoped to the target URL's domain. Maximum 50 cookies. Pro only.

key
required
string^[0-9A-Za-z]{12}$

Your 12-character alphanumeric API key.

required
Array of objects (BatchJobInput) [ 1 .. 5000 ] items

Array of capture jobs. Each entry must include a url and may override any global option. Non-Pro accounts are limited to their batch_limit (default 500); Pro accounts may submit up to 5000.

callback_url
string <uri>

Global webhook URL. When set, all jobs in the batch become callback jobs. Must use HTTPS and resolve to a public IP.

callback_secret
string <= 255 characters

Global HMAC secret echoed back in every callback POST.

idempotency_key
string^[A-Za-z0-9_.\-]{16,128}$

Client-supplied retry-safety key. Replaying the same key within 24 h from the same account returns the original response (X-Idempotent-Replay: true) instead of creating new jobs or deducting quota. Generate a UUID before the first call, reuse on retries, drop on success.

Responses

Request samples

Content type
application/json
Example
{}

Response samples

Content type
application/json
{
  • "submitted": 2,
  • "waitlisted": 0,
  • "deduplicated": 1,
  • "errors": 1,
  • "eta_seconds": 25,
  • "jobs": [
    ]
}

Account

Account info (plan, credits, quota)

Get account status

Returns the current plan, credit balance, monthly quota usage, and number of captures in flight for the authenticated account.

Authentication: pass the 12-character alphanumeric API key as ?key= query parameter or as an Authorization: Bearer <key> header.

query Parameters
key
string^[0-9A-Za-z]{12}$

12-character alphanumeric API key (required if no Bearer header).

Responses

Response samples

Content type
application/json
{
  • "plan": "free",
  • "pro_until": null,
  • "credit": 50,
  • "quota_used": 12,
  • "quota_total": 200,
  • "quota_remaining": 188,
  • "inflight": 1,
  • "inflight_cap": 3
}