How to Use ScreenshotAPI.net in a Node.js App
Call ScreenshotAPI.net from Node.js, save image or JSON responses, protect your token, and handle capture options, errors, limits, and caching.
Use ScreenshotAPI.net’s v3 screenshot endpoint with a server-side API token and an encoded target URL. In Node.js, send a GET request, check the HTTP status, then save the response bytes as an image or parse JSON if you requested JSON output. Keep the token in an environment variable; do not put it in browser JavaScript or source control.
This guide uses the currently documented v3 route, https://shot.screenshotapi.net/v3/screenshot. The older getting-started material has a legacy route, so verify parameter names and response behavior in the current render documentation before deploying.
1. Get a token and prepare a Node.js project
- Create or access a ScreenshotAPI.net account and obtain the API token from its dashboard.
- Store the token as a server-side secret. For local development, put it in an environment variable; in production, use your hosting provider’s secret configuration.
- Use a supported Node.js release with the built-in
fetchAPI, or use the Axios option below.
ScreenshotAPI.net says credentials must remain secret. If a token is exposed, roll the API key in Dashboard settings; the old key is revoked. See the terms and the render docs.
# macOS or Linux
export SCREENSHOTAPI_TOKEN="YOUR_API_TOKEN"
# Windows PowerShell
$env:SCREENSHOTAPI_TOKEN="YOUR_API_TOKEN"
Do not commit a populated .env file. If using a dotenv package, add that file to .gitignore and use your deployment platform’s secret manager outside development.
2. Make a screenshot request with Node.js
This runnable example uses built-in Node.js modules. It requests a PNG image, checks for an unsuccessful HTTP response, and writes the response body to shot.png. Query parameters are assembled with URL and searchParams, which safely encode the target URL.
// save as screenshot.mjs
import { writeFile } from 'node:fs/promises';
const token = process.env.SCREENSHOTAPI_TOKEN;
if (!token) throw new Error('Set SCREENSHOTAPI_TOKEN before running this script.');
const endpoint = new URL('https://shot.screenshotapi.net/v3/screenshot');
endpoint.searchParams.set('token', token);
endpoint.searchParams.set('url', 'https://example.com');
endpoint.searchParams.set('output', 'image');
endpoint.searchParams.set('file_type', 'png');
const response = await fetch(endpoint, { signal: AbortSignal.timeout(90_000) });
if (!response.ok) {
const detail = await response.text();
throw new Error(`ScreenshotAPI.net returned HTTP ${response.status}: ${detail}`);
}
const image = Buffer.from(await response.arrayBuffer());
await writeFile('shot.png', image);
console.log(`Saved ${image.length} bytes to shot.png`);
node screenshot.mjs
The endpoint returns an image by default in the documented example. The code explicitly requests output=image and file_type=png so the intended response is clear. If you select a different output mode, adapt response handling accordingly. The API docs describe image and JSON output and formats including PNG, JPG/JPEG, WebP, and PDF.
Axios version
If the application already uses Axios, install it with npm install axios. Set responseType: 'arraybuffer' for binary image output; otherwise the client may decode or transform the body in ways that are unsuitable for writing an image file.
import axios from 'axios';
import { writeFile } from 'node:fs/promises';
const token = process.env.SCREENSHOTAPI_TOKEN;
if (!token) throw new Error('Set SCREENSHOTAPI_TOKEN before running this script.');
const response = await axios.get('https://shot.screenshotapi.net/v3/screenshot', {
params: {
token,
url: 'https://example.com',
output: 'image',
file_type: 'png',
},
responseType: 'arraybuffer',
timeout: 90_000,
validateStatus: () => true,
});
if (response.status < 200 || response.status >= 300) {
throw new Error(`ScreenshotAPI.net returned HTTP ${response.status}: ${Buffer.from(response.data).toString('utf8')}`);
}
await writeFile('shot.png', Buffer.from(response.data));
Use either example, not both. The v3 API and its options are documented in the ScreenshotAPI.net render docs.
3. Choose the response mode and output format
| Need | Request choice | Node.js handling |
|---|---|---|
| Save an image | Image output and a file type such as PNG, JPG/JPEG, or WebP | Read bytes with arrayBuffer() or Axios responseType: 'arraybuffer', then write or stream them. |
| Consume structured result data | JSON output, using the documented parameter values | Call response.json() after checking status and content type. Follow the current schema in the docs. |
| Create a document | PDF file type and applicable PDF options | Treat the response as binary bytes, as with an image; use a .pdf extension. |
Do not assume a URL inside a JSON response or a binary body shape without checking the current documentation for the selected output mode. If returning the result from your own API, send the matching Content-Type and avoid converting binary data to a UTF-8 string.
4. Set capture options for the page
The basic call needs a token and target URL. Add options only where they solve a real capture requirement. ScreenshotAPI.net documents controls for output type, viewport and full-page or scrolling capture, and additional render behavior. Exact parameter names and availability can change, so use the live parameter reference when adding them.
| Decision | When to use it | Things to check |
|---|---|---|
| Viewport dimensions | Match a desktop or mobile layout, or create repeatable visual checks. | Use the same dimensions on every run; responsive breakpoints can change layout. |
| Full-page or scrolling capture | Capture content beyond the initial viewport, including long pages. | Long pages can take longer and produce larger files. Lazy-loaded content may need additional loading behavior. |
| Image format | PNG for crisp UI and text, JPEG for photographic pages, WebP where supported by your consumers. | Confirm the actual response content type and name the saved file accordingly. |
| Generate a printable or shareable document rather than a raster image. | Check the PDF rendering options and response mode; save the body as binary. | |
| Wait or delay | Allow a single-page app, animation, or late-loading content to settle. | Use the shortest sufficient wait. A fixed delay adds latency to every request. |
| Freshness | Use a fresh render when current page state matters; allow cache where a recent prior result is acceptable. | The docs describe fresh=true to request a current screenshot instead of a cached result. See cached and fresh screenshots. |
Other documented capture workflows include element screenshots, CSS and JavaScript injection, lazy-loading support, and browser emulation. These are useful when a full default-page capture is not enough; see the docs for element screenshots, CSS and JavaScript injection, lazy loading and delay, and browser emulation.
5. Add timeouts, retries, and safe failure handling
A capture depends on both your network and the target website. Give the request a finite timeout, classify failures, and retry only transient errors. A retry can create another API request and may consume quota; do not blindly retry invalid parameters, authentication failures, or usage-limit errors.
- Timeout: choose a deadline suitable for your app. Full-page captures and slow pages may need longer than a basic screenshot.
- Retry: for network interruption or a transient server error, retry a small bounded number of times with backoff and jitter. Avoid synchronized retries across many workers.
- Idempotency: screenshots are read operations, but repeated calls still consume request capacity and may count against plan limits. Cache your own result when its age is acceptable.
- Logging: record status, duration, target host, and a request correlation identifier if available. Redact the token and sensitive query values.
- Input validation: validate that the target is an allowed HTTP or HTTPS URL. If users supply URLs, apply an allowlist or network protections to prevent your service from becoming an SSRF proxy.
The SSRF safeguard is especially important when your Node service accepts arbitrary user URLs: your own server should not fetch internal addresses, cloud metadata endpoints, or local services. Validate hostnames and redirects according to your application’s threat model before forwarding a URL to a screenshot provider.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Unauthorized or invalid-token response | Missing, expired, mistyped, or revoked token; environment variable not loaded. | Check SCREENSHOTAPI_TOKEN in the server process. If the key leaked, roll it in dashboard settings and update the secret configuration. |
| Target URL error | Malformed URL, unsupported scheme, or query string assembled without encoding. | Use URL.searchParams or the client’s params option. Pass a complete https:// or http:// URL. |
| Image file contains text or JSON | The API returned an error body or JSON output, but the code saved it with an image extension. | Check the HTTP status and response content type before writing. Log a bounded error body, not credentials. |
| Blank, incomplete, or stale capture | The target app renders after initial load, lazy content has not appeared, or a cached capture was returned. | Use the documented wait/lazy-loading options; request a fresh capture with fresh=true when current content is required. |
| Request times out | Slow target, large full-page render, long wait setting, or network issue. | Increase the client timeout within your request deadline, reduce unnecessary waits or page area, and retry transient failures with a bounded backoff. |
| Rate or monthly usage limit reached | Plan quota or request-per-minute capacity was exceeded. | Reduce parallel requests, queue work, monitor usage, and confirm the account’s current plan limits and overage behavior. |
| Unexpected layout | Viewport, device emulation, fonts, or late content differs from the expected environment. | Set the needed viewport/emulation options explicitly and wait for the relevant page content before capture. |
7. Performance, reliability, and cost
Screenshot generation is slower and more resource-intensive than fetching a static image because the target page must render. Keep parallelism within your plan’s request-per-minute limit, put bulk work behind a queue, and set an application deadline. A cache can reduce repeated work when the page is unchanged; use a fresh capture only when freshness matters.
The pricing page currently lists a seven-day trial with 100 screenshots, Essential at 1,000 screenshots and 20 requests per minute, Startup at 10,000 and 40 per minute, and Business at 100,000 and 80 per minute. These amounts, prices, and promotions can change; verify the current pricing page before choosing a plan. The terms say unused monthly calls do not carry over and over-limit calls may be blocked or charged per screenshot depending on plan terms, so monitor usage and handle limit errors explicitly.
Or skip the browser setup
If you want an API call without managing browser rendering infrastructure, ScreenshotNeo is a website screenshot API and MCP server for developers. Its one-call API returns an image or PDF; the same parameter names other screenshot APIs use also work, which can make switching straightforward. See the ScreenshotNeo API documentation.
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned HTTP ${res.status}`);
const bytes = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', bytes));
- Cookie banners are accepted like a visitor and more than 60 known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed, and the response identifies the page verdict and billing status.
- An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
- The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for ScreenshotNeo free: 1,000 screenshots a month, no card required.
FAQ
Does ScreenshotAPI.net require Axios?
No. The request is a standard HTTP GET. Node.js built-in fetch works; Axios is an optional client if your project already uses it.
Can I call the API directly from a browser?
A browser call would expose the token to visitors. Make the request from a server you control and return only the screenshot result your application needs.
Should every request bypass the cache?
No. Use a fresh render when the latest page state is required. For repeat captures where a recent result is acceptable, caching can reduce latency and API usage.
Can I capture a PDF instead of an image?
Yes. The service documents PDF output. Use the current PDF options and save the response as binary with a .pdf filename.


