How to Use Abstract Screenshot API with Node.js and fetch
Call Abstract’s Screenshot API from Node.js with fetch, save the image as binary data, and handle errors, options, and limits safely.
Use Node.js fetch to send a GET request to Abstract’s Screenshot API, then save the response body as bytes. The endpoint shown in Abstract’s product documentation is https://screenshot.abstractapi.com/v1/; its example uses the api_key and url query parameters. This adaptation converts response.arrayBuffer() to a Node.js Buffer before writing the image to disk. Check Abstract’s current documentation for required parameters, output format, options, and plan limits before deploying.
1. Minimal Node.js example
This example requires Node.js with global fetch and ES module support. Save it as screenshot.mjs, set the API key in the environment, and run node screenshot.mjs. The sample is an adaptation of Abstract’s documented endpoint and GET request pattern; it has not been independently tested as part of the research.
import { writeFile } from 'node:fs/promises';
const apiKey = process.env.ABSTRACT_API_KEY;
const pageUrl = 'https://example.com';
if (!apiKey) {
throw new Error('Set ABSTRACT_API_KEY in the environment');
}
const endpoint = new URL('https://screenshot.abstractapi.com/v1/');
endpoint.search = new URLSearchParams({
api_key: apiKey,
url: pageUrl,
}).toString();
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`Screenshot API returned HTTP ${response.status}`);
}
const image = Buffer.from(await response.arrayBuffer());
await writeFile('screenshot.png', image);
console.log('Saved screenshot.png');
Set the key without putting it in the source file, for example with ABSTRACT_API_KEY=your_key node screenshot.mjs in a shell that supports that syntax. The key is sent in the query string as shown in the vendor example. Keep this request server-side, do not expose the key in browser JavaScript, and avoid logging the full URL.
Why convert to a Buffer?
The API returns image data, not a JSON document. In Node.js, await response.arrayBuffer() reads the response bytes, and Buffer.from(...) makes those bytes convenient to save with writeFile. Do not call response.json() or treat the result as a text string: that would parse or alter binary image data incorrectly.
2. cURL, Python, and Node.js request examples
These examples make the same basic GET request. They assume you have an Abstract API key and use the documented endpoint and parameter names. Consult the live docs for any additional required settings.
cURL
curl -G 'https://screenshot.abstractapi.com/v1/' \
--data-urlencode "api_key=$ABSTRACT_API_KEY" \
--data-urlencode 'url=https://example.com' \
-o screenshot.png
Do not enable verbose request logging in a shared environment if it could print the API key. The output extension here is a filename choice; confirm the actual format returned and any format parameter in the current API documentation.
Python
import os
import requests
api_key = os.environ.get('ABSTRACT_API_KEY')
if not api_key:
raise RuntimeError('Set ABSTRACT_API_KEY in the environment')
response = requests.get(
'https://screenshot.abstractapi.com/v1/',
params={'api_key': api_key, 'url': 'https://example.com'},
timeout=90,
)
response.raise_for_status()
with open('screenshot.png', 'wb') as image_file:
image_file.write(response.content)
Node.js with fetch and an output path argument
For a reusable script, accept the destination path from the command line and ensure HTTP errors are handled before saving:
import { writeFile } from 'node:fs/promises';
const apiKey = process.env.ABSTRACT_API_KEY;
const pageUrl = process.argv[2] ?? 'https://example.com';
const outputPath = process.argv[3] ?? 'screenshot.png';
if (!apiKey) throw new Error('Set ABSTRACT_API_KEY in the environment');
const endpoint = new URL('https://screenshot.abstractapi.com/v1/');
endpoint.search = new URLSearchParams({ api_key: apiKey, url: pageUrl }).toString();
const response = await fetch(endpoint);
if (!response.ok) {
const detail = await response.text();
throw new Error(`Abstract returned HTTP ${response.status}: ${detail}`);
}
const bytes = Buffer.from(await response.arrayBuffer());
await writeFile(outputPath, bytes);
console.log(`Saved ${bytes.length} bytes to ${outputPath}`);
Run it with node screenshot.mjs https://example.com result.png. Error bodies are included only for diagnosis; redact sensitive values before sending logs to another service.
3. Add capture options carefully
Abstract describes capabilities including viewport and dimensions, image formats, custom CSS, capture delay or timing, and device settings. The research sources do not establish all current parameter names or exact supported values. Check the live API documentation before adding these options; do not guess query keys based on another screenshot service.
| Need | What to verify in Abstract’s current docs |
|---|---|
| Control viewport or dimensions | Exact width and height parameter names, valid ranges, and defaults. |
| Choose output format | Whether PNG, JPEG, or GIF is selected by a parameter, and how the returned content type is indicated. |
| Apply custom CSS | How CSS is passed and whether encoding or escaping is required. |
| Wait for a page or delay capture | Timing controls, units, maximum wait, and behavior when the page never becomes ready. |
| Use a device setting | Supported device names and how device emulation affects dimensions and scale. |
Abstract’s product materials describe screenshots from a page URL or raw HTML and list use cases such as device QA, recurring snapshots, embedded previews, monitoring placements, and security preview flows. For raw HTML or other advanced inputs, follow the current endpoint documentation rather than assuming the URL request example applies unchanged.
4. Validate and store the image reliably
- Check the HTTP status.
fetchresolves for HTTP error statuses, so testresponse.okbefore treating the body as an image. - Read the body once. A response body is a stream; after reading it as bytes, do not try to parse that same body again as JSON.
- Inspect the response metadata. Use the response content type, if supplied, and current API docs to choose a truthful file extension. Do not assume the service always returns PNG just because the file is named
.png. - Set a request timeout for production. Use an abort signal with a timeout appropriate to your page and plan. A timeout means your client stopped waiting; it does not establish whether the provider processed the request.
- Write atomically when partial files matter. Write to a temporary file and rename it only after a complete successful response. For object storage, upload the byte buffer and record the content type.
- Bound concurrency. Respect your plan’s request rate and quota. Queue work rather than launching an unbounded number of simultaneous captures.
The sources reviewed do not specify every error response shape, retry rule, or quota response. In production, consult the current API documentation for error bodies and rate-limit behavior. Retry only errors that are plausibly transient, use a bounded exponential backoff with jitter, and avoid automatic repeated retries for invalid parameters or rejected credentials.
5. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Missing key error from the script | ABSTRACT_API_KEY is not set in the process environment. |
Set the environment variable in the runtime or secret manager and restart the process. Do not hard-code it in frontend code. |
| HTTP error from the API | Invalid key, unsupported input, quota or rate limit, or another provider-side rejection. | Check the status and provider error body without logging the complete request URL. Confirm credentials, current parameter requirements, and account limits in Abstract’s docs/dashboard. |
| Saved file is not a viewable image | The response may be an error body, the chosen extension may not match its format, or bytes may have been decoded as text. | Check response.ok, inspect content type and response bytes, and save arrayBuffer() as a Buffer. Do not JSON-parse successful image responses. |
| Request hangs or takes too long | The target page or capture can take longer than expected, or the network is stalled. | Apply a client timeout, check connectivity, and verify supported capture timing controls. Set retries with limits. |
| Screenshot misses content rendered later | Client-side rendering, delayed images, or asynchronous page content may not be ready at capture time. | Use a documented delay or readiness option if available, and tune it for the target page. Confirm the option name and limits first. |
| API key appears in logs | Query strings were logged by application, proxy, or request tracing. | Redact the api_key parameter from logs and telemetry, restrict access to logs, and rotate the key if it was exposed. |
6. Performance, reliability, and cost
Screenshot work depends on both the API request and the target page’s loading and rendering. Keep concurrency within the rate limit for your account, set a bounded timeout, and record status, elapsed time, byte count, and format without recording the secret query value. For recurring snapshots, cache results when freshness requirements allow, and avoid recapturing unchanged pages unnecessarily.
Abstract’s product page presents different limits for monthly and yearly billing views. The reviewed page showed a free plan with 100 requests and 1 request per second; its monthly billing view showed Standard at $99 per month with 60,000 requests per month and 3 requests per second, while the yearly view showed Standard at $99 per month paid annually with 60,000 requests per year and 3 requests per second. These are vendor-listed figures and can change, so verify the current plan view and billing cadence before estimating cost. The product page describes an Enterprise 99.99% uptime SLA; that is a vendor plan statement, not an independently measured uptime figure.
If you need direct control over a browser runtime, a hosted API may not fit every workflow. If you need a managed screenshot request, compare the documented capture controls, request volume and rate limits, output handling, and operational requirements against the current plan details.
7. Or skip the browser setup
For a one-call screenshot API, try ScreenshotNeo. It accepts a URL and returns a screenshot or PDF; its API parameters are designed so names used by other screenshot APIs also work. See the ScreenshotNeo 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(`ScreenshotNeo returned HTTP ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', image));
- Cookie banners are accepted like a visitor and removed along with 60+ known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Responses include
X-Page-VerdictandX-Billedheaders. - An MCP server gives AI agents, including Claude, Cursor, and other MCP clients, the tools
take_screenshot,get_page_info, andcapture_pdf. - The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Every feature is available on every plan.
Sign up free for 1,000 screenshots a month, with no card required.
8. FAQ
Can I use this code in browser JavaScript?
Keep it on a trusted server because the documented request puts the API key in the query string. Browser code would expose that credential.
Does the filename determine the image format?
No. A filename extension does not convert image bytes. Confirm the returned format and any format-selection option in the current API docs.
Can I save the response to cloud storage?
Yes. Read the successful response as bytes and pass the buffer to your storage client, preserving the actual content type when available.
Is the sample guaranteed to match the latest API behavior?
No. It follows the endpoint and GET parameters in the reviewed vendor material. Check Abstract’s current documentation for changes to endpoint, parameters, formats, errors, and plan limits.
Sources
- Abstract: Website Screenshot API — endpoint, query parameters, output types, capture capabilities, use cases, and plan listings.
- Abstract: Best Screenshot API in 2026 for Developers — GET request and saving response bytes example.
- Abstract: Image Compression with ReactJS — JavaScript fetch pattern for a different Abstract API.
- Abstract: How to Send Emails with Node.js — notes global fetch availability in Node.


