JavaScript / TypeScript
Official screenshotapi-to SDK for JavaScript and TypeScript — capture screenshots from Node.js, Next.js, Vercel, Bun, Deno, and Cloudflare Workers.
The official screenshotapi-to SDK is a fully typed client with zero runtime dependencies. It works anywhere native fetch is available — Node.js 18+, Next.js, Vercel Functions, Bun, Deno, and Cloudflare Workers.
Package: screenshotapi-to on npm · Source & examples: github.com/miketromba/screenshotapi-js · Prefer raw HTTP? See Without the SDK.
Installation
npm install screenshotapi-topnpm add screenshotapi-toyarn add screenshotapi-tobun add screenshotapi-toAuthentication
Create an API key in the dashboard and keep it in a server-side environment variable.
export SCREENSHOTAPI_KEY="sk_live_your_key_here"import { ScreenshotAPI } from 'screenshotapi-to'
const client = new ScreenshotAPI({
apiKey: process.env.SCREENSHOTAPI_KEY!
})Never expose your API key in browser JavaScript. For client-side apps, call your own backend route and let that route use the SDK. See Browser usage.
Quick Start
Capture a URL and save it to disk
save() captures the screenshot and writes the file in one call. It returns the response metadata.
import { ScreenshotAPI } from 'screenshotapi-to'
const client = new ScreenshotAPI({ apiKey: process.env.SCREENSHOTAPI_KEY! })
const metadata = await client.save({
url: 'https://example.com',
path: './example.png',
type: 'png'
})
console.log(`Screenshot ID: ${metadata.screenshotId}`)
console.log(`Credits remaining: ${metadata.creditsRemaining}`)
console.log(`Captured in ${metadata.durationMs}ms`)Or work with the raw image bytes
screenshot() returns the image as an ArrayBuffer so you can stream it, upload it, or transform it. It runs in any runtime, including edge.
const result = await client.screenshot({
url: 'https://example.com',
type: 'webp',
quality: 85
})
console.log(result.contentType) // "image/webp"
console.log(result.image.byteLength) // image size in bytes
console.log(result.metadata.creditsRemaining)save() writes files with Node.js APIs and is only available in Node-compatible runtimes. In edge runtimes (Cloudflare Workers, Vercel Edge), use screenshot() and return or store the ArrayBuffer yourself.
Methods
new ScreenshotAPI(config)
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | — (required) | Your API key |
baseUrl | string | https://screenshotapi.to | API base URL (proxies, tests) |
timeout | number | 60000 | Request timeout in milliseconds |
client.screenshot(options)
Returns Promise<ScreenshotResult>:
interface ScreenshotResult {
image: ArrayBuffer // raw image (or PDF) bytes
contentType: string // "image/png", "image/webp", "application/pdf", …
metadata: {
creditsRemaining: number
screenshotId: string // include this when contacting support
durationMs: number
}
}client.save(options)
Takes the same options as screenshot() plus path: string. Writes the file to path and returns Promise<ScreenshotMetadata> (the metadata shape above). Node-only.
Options
Every screenshot parameter is available as a camelCase option on screenshot() and save().
| Option | Type | Default | Description |
|---|---|---|---|
url | string | Required unless html is set | URL to capture |
html | string | — | HTML document to render (switches to POST) |
width | number | 1440 | Viewport width in pixels (max 1920) |
height | number | 900 | Viewport height in pixels (max 10000) |
fullPage | boolean | false | Capture the full scrollable page |
type | 'png' | 'jpeg' | 'webp' | 'pdf' | 'png' | Output format |
quality | number | 100 | JPEG/WebP quality, 1–100 |
colorScheme | 'light' | 'dark' | Page default | Force prefers-color-scheme |
waitUntil | 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2' | 'networkidle2' | Page readiness signal |
waitForSelector | string | — | CSS selector to wait for |
delay | number | 0 | Extra wait after load (ms, max 30000) |
blockAds | boolean | false | Block common ad networks |
removeCookieBanners | boolean | false | Auto-remove cookie consent dialogs |
cssInject | string | — | CSS injected before capture |
jsInject | string | — | JavaScript evaluated before capture |
stealthMode | boolean | false | Anti-bot-detection browser fingerprint |
devicePixelRatio | 1 | 2 | 3 | 1 | Retina/HiDPI scale |
timezone | string | Server default | IANA timezone, e.g. America/New_York |
locale | string | Server default | BCP 47 locale, e.g. en-US |
cacheTtl | number | 0 | Cache identical captures for N seconds |
preloadFonts | boolean | false | Preload Google Fonts before capture |
removeElements | string[] | — | CSS selectors to remove |
removePopups | boolean | false | Remove common modals/overlays |
mockupDevice | 'browser' | 'iphone' | 'macbook' | — | Wrap output in a device frame (PNG) |
geoLocation | { latitude: number; longitude: number; accuracy?: number } | — | Browser geolocation emulation |
const result = await client.screenshot({
url: 'https://example.com/dashboard',
width: 1440,
height: 1200,
fullPage: true,
type: 'webp',
quality: 90,
colorScheme: 'dark',
waitUntil: 'networkidle0',
waitForSelector: '[data-ready="true"]',
delay: 500,
blockAds: true,
removeCookieBanners: true,
devicePixelRatio: 2,
timezone: 'America/New_York',
locale: 'en-US',
cacheTtl: 300,
removeElements: ['.modal', '#promo'],
geoLocation: { latitude: 40.7128, longitude: -74.006, accuracy: 25 }
})Render HTML & generate PDFs
Pass html instead of url to render a raw HTML string — the SDK automatically switches to POST /api/v1/screenshot. Combine with type: 'pdf' to produce documents like invoices or reports.
const pdf = await client.screenshot({
html: '<main><h1>Invoice #1024</h1><p>Thank you for your business.</p></main>',
type: 'pdf',
width: 1200
})
// pdf.image is an ArrayBuffer of the PDF bytesError Handling
The SDK throws typed errors for API, network, and timeout failures. Every error extends ScreenshotAPIError.
import {
ScreenshotAPI,
AuthenticationError,
InvalidAPIKeyError,
InsufficientCreditsError,
ScreenshotFailedError,
ScreenshotTimeoutError,
ScreenshotNetworkError
} from 'screenshotapi-to'
const client = new ScreenshotAPI({
apiKey: process.env.SCREENSHOTAPI_KEY!,
timeout: 30_000
})
try {
await client.screenshot({ url: 'https://example.com' })
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Missing or malformed API key (401)')
} else if (error instanceof InvalidAPIKeyError) {
console.error('API key is revoked or invalid (403)')
} else if (error instanceof InsufficientCreditsError) {
console.error(`Out of credits (402). Balance: ${error.balance}`)
} else if (error instanceof ScreenshotFailedError) {
console.error(`Capture failed server-side (500): ${error.message}`)
} else if (error instanceof ScreenshotTimeoutError) {
console.error(`Timed out after ${error.timeoutMs}ms`)
} else if (error instanceof ScreenshotNetworkError) {
console.error('Could not reach ScreenshotAPI')
} else {
throw error
}
}| Error | When |
|---|---|
AuthenticationError | 401 — API key missing or malformed |
InsufficientCreditsError | 402 — no credits remaining (exposes .balance) |
InvalidAPIKeyError | 403 — API key revoked or invalid |
ScreenshotFailedError | 500 — capture failed server-side |
ScreenshotTimeoutError | Request exceeded timeout (exposes .timeoutMs) |
ScreenshotNetworkError | Network/connection failure |
ScreenshotAPIError | Base class for all of the above |
Framework Recipes
Next.js (App Router)
Proxy screenshots through a route handler so your key stays on the server.
// app/api/screenshot/route.ts
import { ScreenshotAPI } from 'screenshotapi-to'
const client = new ScreenshotAPI({ apiKey: process.env.SCREENSHOTAPI_KEY! })
export async function GET(request: Request) {
const url = new URL(request.url).searchParams.get('url')
if (!url) {
return Response.json({ error: 'url is required' }, { status: 400 })
}
try {
const { image, contentType } = await client.screenshot({ url, type: 'webp' })
return new Response(image, {
headers: {
'Content-Type': contentType,
'Cache-Control': 'public, max-age=3600'
}
})
} catch {
return Response.json({ error: 'Screenshot failed' }, { status: 500 })
}
}Express
import express from 'express'
import { ScreenshotAPI } from 'screenshotapi-to'
const app = express()
const client = new ScreenshotAPI({ apiKey: process.env.SCREENSHOTAPI_KEY! })
app.get('/screenshot', async (req, res) => {
const url = req.query.url as string
if (!url) return res.status(400).json({ error: 'url is required' })
try {
const { image, contentType } = await client.screenshot({ url, type: 'webp', quality: 80 })
res.set('Content-Type', contentType)
res.set('Cache-Control', 'public, max-age=3600')
res.send(Buffer.from(image))
} catch {
res.status(500).json({ error: 'Screenshot failed' })
}
})Cloudflare Workers
save() isn't available at the edge — use screenshot() and return the ArrayBuffer directly.
import { ScreenshotAPI } from 'screenshotapi-to'
export default {
async fetch(request: Request, env: { SCREENSHOTAPI_KEY: string }): Promise<Response> {
const client = new ScreenshotAPI({ apiKey: env.SCREENSHOTAPI_KEY })
const url = new URL(request.url).searchParams.get('url') ?? 'https://example.com'
const { image, contentType } = await client.screenshot({ url, type: 'webp' })
return new Response(image, { headers: { 'Content-Type': contentType } })
}
}Batch captures
screenshot() is a normal promise, so use Promise.allSettled for resilient parallel captures.
const urls = ['https://example.com', 'https://github.com', 'https://news.ycombinator.com']
const results = await Promise.allSettled(urls.map(url => client.save({ url, path: `./out/${new URL(url).hostname}.png` })))
results.forEach((result, i) => {
if (result.status === 'fulfilled') console.log(`✓ ${urls[i]}`)
else console.error(`✗ ${urls[i]}: ${result.reason.message}`)
})More runnable examples ship with the package: Node.js, Next.js, Vercel Function, and Cloudflare Worker.
Browser usage
// Frontend — calls your own proxy, not ScreenshotAPI
const response = await fetch(`/api/screenshot?url=${encodeURIComponent(url)}`)
const blob = await response.blob()
const imageUrl = URL.createObjectURL(blob)Without the SDK
The SDK is a thin wrapper over a single HTTP endpoint, so you can always call it with native fetch and no dependencies:
const params = new URLSearchParams({ url: 'https://example.com' })
const response = await fetch(`https://screenshotapi.to/api/v1/screenshot?${params}`, {
headers: { 'x-api-key': process.env.SCREENSHOTAPI_KEY! }
})
if (!response.ok) throw new Error((await response.json()).error)
const image = Buffer.from(await response.arrayBuffer())See the Screenshot API reference for the full endpoint contract.
Requirements
- Node.js 18+ (or any runtime with native
fetch) - Zero runtime dependencies
Next steps
- Screenshot API reference — every parameter in detail
- Authentication — create and rotate API keys
- Credits — how billing works (200 free screenshots/month)
- Integrations — framework and platform guides
SDKs & Libraries
Official ScreenshotAPI SDKs for JavaScript, Python, Go, Ruby, and PHP — plus a CLI and copy-paste HTTP examples for every other language.
Python
Official screenshotapi-to SDK for Python — capture screenshots and PDFs from scripts, FastAPI, Django, and Flask, with sync and async clients.