Browshot API Node.js Setup: How to Capture a Website Screenshot
Set up Browshot in Node.js, capture and save a website screenshot, and choose between its Simple and full API flows. Includes errors, options, and a ScreenshotNeo alternative.
To capture a website screenshot with Browshot in Node.js, install its official browshot package, create a client with your API key, then call either client.simple() for a single request or the full screenshot flow when you need to track status and retrieve the image separately. The examples below use the CommonJS style shown in Browshot’s Node.js documentation.
1. Create a project and protect your API key
Create or retrieve a Browshot API key from your account. Keep it in an environment variable or secret manager; do not commit it to source control or expose it in browser-side code.
mkdir browshot-example
cd browshot-example
npm init -y
npm install browshot
Set the key in your shell before running the examples:
export BROWSHOT_API_KEY='your_api_key'
In other environments, configure the equivalent environment variable through your deployment platform. The examples fail early if it is missing.
2. Capture and save an image with the Simple API
The Simple API is the shortest path: provide the URL and instance, check the returned result, and write its image data to a file. Browshot describes this as a real-time screenshot returned in one request. Its documentation also says the Simple API is easier but slower than the complete API, so use it when simplicity matters more than managing the capture lifecycle yourself. See the [Browshot Node.js library](https://browshot.com/api/libraries/nodejs) and [API documentation](https://api.browshot.com/api/documentation).
const fs = require('node:fs');
const Browshot = require('browshot');
const apiKey = process.env.BROWSHOT_API_KEY;
if (!apiKey) throw new Error('Set BROWSHOT_API_KEY before running this script');
const client = new Browshot(apiKey);
const url = 'https://example.com';
const instanceId = 12; // Browshot documents instance 12 as its default free instance.
client.simple({ url, instance_id: instanceId }, (error, result) => {
if (error) {
console.error('Browshot request failed:', error);
process.exitCode = 1;
return;
}
if (!result || result.code !== 200 || !result.data) {
console.error('Screenshot was not returned successfully:', result);
process.exitCode = 1;
return;
}
fs.writeFileSync('screenshot.png', result.data);
console.log('Saved screenshot.png');
});
Replace https://example.com with the page you need. The official library example writes result.data to a PNG and checks for code 200. If you change the output extension, ensure it matches the format returned by the API; do not assume changing the filename converts the image.
3. Use the full API when you need status and retrieval control
The full flow separates creating a screenshot from retrieving its image. It is useful when you need to observe whether work is still running, handle a reported failure, or control retrieval in your application. Browshot’s documented lifecycle includes in_process, finished, and error statuses. The exact response fields and library method signatures should be checked against the current [API documentation](https://api.browshot.com/api/documentation) and [Node.js library reference](https://browshot.com/api/libraries/nodejs).
This pattern shows the lifecycle as pseudocode around the documented operations; adapt the method arguments and image retrieval call to the current package reference:
const Browshot = require('browshot');
const apiKey = process.env.BROWSHOT_API_KEY;
if (!apiKey) throw new Error('Set BROWSHOT_API_KEY before running this script');
const client = new Browshot(apiKey);
const request = { url: 'https://example.com', instance_id: 12 };
client.screenshotCreate(request, (error, screenshot) => {
if (error) {
console.error('Could not create screenshot:', error);
process.exitCode = 1;
return;
}
if (!screenshot || screenshot.status === 'error') {
console.error('Screenshot failed:', screenshot && screenshot.error);
process.exitCode = 1;
return;
}
if (screenshot.status === 'in_process') {
console.log('Screenshot is still processing. Check its status before retrieving the image.');
return;
}
if (screenshot.status === 'finished') {
console.log('Screenshot finished. Retrieve its image using the retrieval method documented for your package version.');
}
});
Do not treat a created screenshot record as the image itself. In a production implementation, persist the screenshot identifier, poll or otherwise check status according to Browshot’s documented flow, stop after an application-defined deadline, surface the service’s error details, and retrieve the image only after completion. Avoid tight polling loops; use a delay with a bounded retry policy.
4. Choose capture size and request options
| Option | What it controls | When to consider it |
|---|---|---|
url |
The page to open. | Required. Use a complete URL with scheme, such as https://. |
instance_id |
The Browshot browser instance used for capture. | Required for the full screenshot endpoint. Confirm the chosen instance supports the features your capture needs. |
size |
screen captures the screen viewport; page requests a page-sized capture. |
Use screen for what a visitor sees without scrolling, and page when the complete page is needed. |
| Cache lifetime | How long a prior result may be reused. | Useful when repeated captures of a stable page do not need to be fresh. Choose based on how often the page changes. |
| Delay after page load | Extra time before capture. | Use when the page renders important content shortly after its initial load. A longer delay increases waiting time. |
| Maximum wait | How long the capture may wait for the page. | Set a practical bound for slow or unreliable destinations; do not let stalled pages occupy work indefinitely. |
| Custom headers | Headers sent with the page request. | Useful for sites that vary responses by headers. Treat authorization values as secrets. |
| JavaScript and CSS | Custom behavior or styling for the capture. | Use only when needed to reach or present the intended state; verify support for the selected instance. |
| CSS selector targeting | Targets a page element for capture. | Use when only a specific component matters; confirm the selector exists after the page renders. |
These options are documented by Browshot, but availability can depend on the instance and current service behavior. Check the API reference before relying on an advanced option. Browshot also documents automation steps such as clicking, typing, waiting, and navigating, plus pre-capture JavaScript; its script page says the script must finish within the configured delay, with a maximum of 10 seconds on that page. Do not assume every instance supports every advanced feature: see the [automation documentation](https://api.browshot.com/api/login) and [pre-capture script documentation](https://api.browshot.com/api/script).
5. Add the capture to an application safely
- Validate and normalize the input URL before sending it to the screenshot service. If users supply URLs, apply your own allowlist or destination policy to avoid turning your service into an unintended proxy.
- Keep the API key on the server. Return the resulting image or a controlled reference to the client rather than embedding the key in frontend code.
- Set an application timeout and handle network failures. For the full API, separately bound status checks and retrieval.
- Choose screen or page size deliberately. Full page captures can take longer and may produce larger files.
- Store files with an appropriate retention policy. Screenshots can contain private or personalized page content.
- Log request identifiers and failure categories, but redact API keys, authorization headers, and sensitive page data.
Or skip the browser setup
ScreenshotNeo offers a one-call screenshot API and an MCP server for AI agents. Cookie banners, popups, and chat widgets are removed before the shot; each step can be turned off. Bot checks, blank pages, and failed loads are never billed, and response headers identify the page verdict and billing status. The MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. See the ScreenshotNeo website and API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
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(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo includes 1,000 screenshots a month free with no card; paid plans start at $5 for 3,000 screenshots. Sign up free for ScreenshotNeo.
6. Quota, cost, and performance considerations
Browshot’s API documentation says its default free instance is instance 12 and allows 100 free screenshots per month. The same documentation says private and shared instances require a positive balance. Its Node.js examples warn that running them can cost credits. Treat these as Browshot-published terms that may change, and check your account and the [current API documentation](https://api.browshot.com/api/documentation) before running a batch.
- Start with a single known URL and the documented free instance, then confirm the returned result before scaling up.
- Use the Simple API for a compact flow; use the full API when your application needs explicit lifecycle handling. The docs characterize the Simple API as slower, but do not provide a benchmark to predict your workload’s latency.
- Use caching only when a slightly stale image is acceptable. A shorter cache lifetime favors freshness; a longer lifetime may avoid repeating work for unchanged pages.
- Keep page-load waits bounded. More waiting can help delayed rendering, but also increases request latency and ties up application resources.
- For batches, track successful, processing, and failed captures separately. Do not blindly retry every failure: distinguish transient network problems from invalid URLs, unsupported options, or page-level errors.
- Estimate spend from your expected capture volume and selected instance/account terms before scheduling recurring jobs.
7. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Missing API key or authentication failure | The environment variable is unset, misspelled, or the key is invalid. | Check BROWSHOT_API_KEY in the process environment and verify the key in your Browshot account. Never print it into logs. |
| Invalid URL or unexpected page | The URL is malformed, omits its scheme, redirects, or serves different content to the browser instance. | Pass a complete URL, inspect redirect and site behavior, and try a page you control. |
| No image written | The callback reported an error, the result code was not 200, or image data was absent. | Check all three conditions before writing and log safe diagnostic details from the response. |
Screenshot remains in_process |
The page is slow or the capture has not completed yet. | Check status again after a delay, apply a finite deadline, and review the configured maximum wait. |
Status is error |
The screenshot failed; the response may include error information. | Read and surface the documented error field, then correct the URL, options, or instance rather than repeatedly resubmitting unchanged requests. |
| Page is blank or missing late content | Content may require more time or client-side rendering, or the page may block the capture environment. | Try a suitable delay, verify the destination independently, and check instance capabilities and service guidance. |
| Capture is cropped | The request used viewport capture or the page has unusual layout behavior. | Choose size: 'page' when a page-sized image is needed; check the current option format in the API docs. |
| Insufficient balance or request rejected for instance | The selected private or shared instance requires a positive balance, or the account quota/terms do not cover the request. | Check the instance and account billing status before retrying. |
| Advanced option has no effect | The selected instance may not support the feature, or the parameter format may differ from the assumed form. | Confirm the exact option name and instance support in Browshot’s current API reference. |
| Module or method not found | The package is missing, the wrong package name was installed, or the code does not match the installed version. | Run npm install browshot in the project directory and follow the package’s CommonJS examples. The reviewed library page does not establish native ES module support. |
8. Frequently asked questions
Does the Simple API return a file automatically?
The documented Node.js example receives image data in the callback and writes it to disk. Your application must handle the result and save or return the bytes.
Can I use this package with ES modules?
The reviewed Browshot library page demonstrates CommonJS with require(); it does not establish native ES module support. Follow the current package documentation for your installed version.
Is instance 12 always free?
Browshot’s documentation identifies instance 12 as its default free instance and states a 100-per-month allowance. Quotas and terms can change, so verify them before publication or use.
Can I capture a page behind a login?
The API documentation lists custom headers among its options, but authenticated capture depends on the site and supported instance configuration. Keep credentials secret and confirm the current supported approach in Browshot’s documentation.


