What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To add a screenshot API to Express, create a server-side route that validates a requested URL, calls a screenshot provider with your API key, then returns the provider’s image or PDF bytes with the correct Content-Type. Use GET for a few simple options and POST with JSON for advanced settings such as custom CSS, PDF configuration, or geolocation. Keep credentials on the server and limit which URLs your route will capture.

What the Express route does

An Express screenshot endpoint is a small proxy between your application and a rendering service. A caller sends your route a target URL and permitted capture options. Your server validates the request, authenticates to the provider, waits for the rendered output, and relays the bytes and response type.

This keeps the provider key out of browser code, lets you enforce an allowlist and usage limits, and gives your application one stable endpoint even if provider details change. The examples below use Screenshot API’s documented REST endpoints and Node.js SDK options. The provider’s documentation describes API-key authentication and GET and POST screenshot requests at Screenshot API documentation. Check the current endpoint paths and SDK method signatures there before deploying.

Set up Express and your API key

  1. Create an API key with the screenshot provider, then store it in a server-side environment variable such as SCREENSHOTAPI_KEY. Do not put it in frontend JavaScript, a public repository, or a URL query string.

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  2. Install the packages. The provider’s framework materials list @screenshot-api/js with Express; its Express-specific guide instead uses screenshotapi-to. Choose one client and follow its current package documentation:

    npm install express @screenshot-api/js

    Alternative package shown in the Express guide:

    npm install express screenshotapi-to
  3. Start Express only after configuring the environment variable. For local development, load environment variables using your deployment’s secret management or a local environment-file loader, and ensure secret files are excluded from version control.

The provider documentation recommends sending the key in an Authorization: Bearer header or an X-API-Key header. The SDK may handle that header when initialized with the key. Use whichever authentication method the chosen client documents.

A simple Express screenshot route

The route below illustrates the essential request flow using the provider’s REST API. It accepts a URL, optionally chooses an output format, validates the target, calls the documented GET endpoint, then passes the provider response body through. Replace the API base URL and response handling with the exact values in the current provider documentation if they change.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import express from 'express';

const app = express();
const apiKey = process.env.SCREENSHOTAPI_KEY;
const providerBase = 'https://api.screenshot-api.com/api/v1/screenshot';

if (!apiKey) {
  throw new Error('SCREENSHOTAPI_KEY is required');
}

const allowedFormats = new Set(['png', 'jpeg', 'webp', 'pdf']);

app.get('/api/screenshot', async (req, res) => {
  const { url } = req.query;
  const format = typeof req.query.format === 'string' ? req.query.format : 'png';

  if (typeof url !== 'string' || url.length === 0) {
    return res.status(400).json({ error: 'A single url query parameter is required.' });
  }
  if (!allowedFormats.has(format)) {
    return res.status(400).json({ error: 'format must be png, jpeg, webp, or pdf.' });
  }

  let target;
  try {
    target = new URL(url);
  } catch {
    return res.status(400).json({ error: 'url must be a valid absolute URL.' });
  }
  if (!['http:', 'https:'].includes(target.protocol)) {
    return res.status(400).json({ error: 'Only HTTP and HTTPS URLs are allowed.' });
  }

  try {
    const upstreamUrl = new URL(providerBase);
    upstreamUrl.searchParams.set('url', target.href);
    upstreamUrl.searchParams.set('format', format);

    const upstream = await fetch(upstreamUrl, {
      headers: { Authorization: `Bearer ${apiKey}` },
      signal: AbortSignal.timeout(90000)
    });

    if (!upstream.ok) {
      const text = await upstream.text();
      return res.status(upstream.status).json({
        error: 'Screenshot provider request failed.',
        providerStatus: upstream.status,
        detail: text.slice(0, 1000)
      });
    }

    const bytes = Buffer.from(await upstream.arrayBuffer());
    res.set('Content-Type', upstream.headers.get('content-type') || 'application/octet-stream');
    res.set('Cache-Control', 'private, max-age=60');
    return res.send(bytes);
  } catch (error) {
    if (error.name === 'TimeoutError' || error.name === 'AbortError') {
      return res.status(504).json({ error: 'Screenshot request timed out.' });
    }
    console.error('Screenshot request failed:', error);
    return res.status(500).json({ error: 'Unable to capture the requested page.' });
  }
});

app.listen(process.env.PORT || 3000);

This is a REST-flow example, not a guarantee of identical hostnames, error payloads, or SDK signatures across provider editions. Confirm the provider’s active API base URL and request schema before using it. The API documentation supports GET /api/v1/screenshot for query-string parameters; it returns JSON by default, and documents redirect=1 when you want a redirect to the resulting image or PDF instead of a JSON response.

Important production URL controls

Accepting arbitrary URLs from an unauthenticated route creates a server-side request forgery and cost-abuse risk. Validate more than URL syntax:

Send advanced settings with POST

For a handful of simple values, GET query parameters are convenient. For numerous settings or options that can contain CSS and JavaScript, use the documented POST endpoint with a JSON body. The provider identifies custom CSS, JavaScript, hidden selectors, geolocation, locale, timezone, and PDF controls as POST-only options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const response = await fetch('https://api.screenshot-api.com/api/v1/screenshot', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://example.com',
    format: 'webp',
    viewport: { width: 1440, height: 1000 },
    fullPage: true,
    waitUntil: 'networkidle',
    waitForSelector: 'main',
    delayMs: 500,
    blockAds: true,
    blockCookieBanners: true,
    darkMode: false
  })
});

Use the exact property names and accepted values documented for your account and API version; examples of wait-strategy labels can differ among clients. Commonly useful documented controls include:

Need Documented option Practical note
Output format: png, jpeg, webp, or pdf Forward the actual response Content-Type; do not assume every result is PNG.
Viewport and page length Viewport width and height, fullPage, deviceScaleFactor Full-page output may be substantially larger than a viewport capture.
Wait for rendering waitUntil, waitForSelector, delayMs, timeoutMs Wait for a meaningful page state rather than adding a large fixed delay by default.
Specific content selector, hideSelectors A missing target selector can produce the documented 422 selector-not-found response.
Page appearance darkMode, css, js Custom CSS and JavaScript are POST-only in the documented API.
Privacy or regional rendering geolocation, timezoneId, locale These advanced settings are POST-only; use only values your application actually needs.
Page cleanup blockAds, blockCookieBanners Blocking can change page appearance; verify it is suitable for the output’s purpose.
Reuse cache, cacheTTL, staleTTL Choose freshness rules deliberately for pages that change over time.
PDF output pdf controls PDF-specific settings are POST-only; consult the API schema for supported paper and layout options.

Return the correct bytes and response headers

A route returning a screenshot should respond with the provider’s output bytes, not a JSON serialization of a buffer. Set Content-Type from the upstream response, especially when the caller can request JPEG, WebP, or PDF. The Express integration guide also demonstrates setting Cache-Control and an x-credits-remaining header when the client exposes that information.

Use caching only when the requested page and access policy make reuse safe. A short cache lifetime reduces duplicate work for frequently requested, unchanged URLs; private or personalized pages should generally not be shared between users. The provider documents cache, cacheTTL, and staleTTL controls. Your own HTTP cache policy is separate from the provider’s capture cache.

Use the SDK or build a reusable capture service

The provider’s materials list @screenshot-api/js as its Node.js SDK, while its Express integration example uses screenshotapi-to. Those package names are not interchangeable: initialize and call the specific package you installed according to its current documentation. A clean application structure keeps provider calls in a service module and leaves the route responsible for validation and HTTP responses.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A service can accept a typed options object such as width, height, image type, quality, full-page capture, color scheme, wait strategy, delay, retries, and timeout. The Express guide presents these as example service options, including a 30-second timeout; treat them as that guide’s defaults, not guarantees about provider behavior or recommended values for every page.

Keep retries bounded. A retry can help with transient network failures, but repeating invalid requests, quota failures, or selector-not-found errors wastes time and may consume additional resources. Retry only errors known to be transient, use a maximum attempt count and backoff, and respect any provider rate-limit guidance.

Capture several URLs with a batch request

For a group of pages, the documented API provides POST /api/v1/screenshot/batch, which returns a batch ID. Your application can persist that ID and let a caller check progress through GET /api/v1/batch/:batchId or receive stream updates through GET /api/v1/batch/:batchId/stream (SSE). This avoids holding one Express request open while a large set of pages renders.

  1. Validate every URL and apply the same domain, authorization, and quota rules used for one-off captures.

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  2. Submit the batch to the provider and store its batch ID with the requesting user or job.

  3. Expose a status endpoint or SSE stream that checks the caller’s authorization before revealing progress or results.

  4. Handle partial completion: report which captures succeeded and which failed instead of treating the batch as one all-or-nothing screenshot.

Common errors and fixes

Response or symptom Likely cause What to do
400 invalid request Missing URL, malformed options, or a value outside the accepted schema. Validate inputs in Express and compare the outgoing request with the provider’s documented parameter names and types.
401 unauthorized Missing, invalid, or incorrectly transmitted API key. Check the server environment variable and confirm the bearer or API-key header is being sent; rotate an exposed key.
422 selector not found The requested selector does not appear before the capture condition is met. Check the target page and selector, allow the page to finish loading, or remove the selector requirement if it is optional.
429 rate limited or quota exceeded Too many requests or exhausted account allowance. Throttle or queue work, avoid indiscriminate retries, and check the account’s current quota and rate limits.
502 render failure The provider could not complete a browser render for the target. Try the URL directly, reduce unnecessary wait conditions, and retry only if the failure appears transient.
Express returns JSON where an image was expected The endpoint’s default response is JSON, or the request was made without redirect or output handling expected by the client. Read the provider response format, extract or relay the image bytes correctly, and set the corresponding content type.
Timeouts or slow responses The page may be slow, a wait condition may never occur, or the capture timeout may be too short. Set an explicit bounded timeout, choose a more meaningful wait condition, and return a clear timeout response to the caller.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If you want an HTTP screenshot endpoint without managing a browser process in your Express application, call ScreenshotNeo, a screenshot API and MCP server for developers. Its API accepts one GET request with a URL and can return PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation for request options and response details.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

In an Express route, call this endpoint from the server and relay its response bytes and headers, just as in the REST example above. ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000.

Sign up for ScreenshotNeo free to get 1,000 screenshots a month with no card.

Performance, reliability, and cost choices

A hosted API means your application makes an HTTP request instead of provisioning and maintaining a local Chromium binary and browser processes. It also means request time includes provider-side rendering and network transfer; large full-page images and PDFs take longer to return and use more bandwidth than small viewport images. The actual latency depends on the target page, capture configuration, provider service, and network conditions; no universal response-time figure is established here.

For production, set connection and overall timeouts, cap concurrency, and return useful errors rather than leaving callers waiting indefinitely. Monitor provider status codes, timeouts, quota or credit indicators, and your own route latency. Cache only where freshness and privacy allow. Compare a hosted service with self-hosting using the deployment footprint, browser maintenance, memory use, latency, control over rendering, authentication and privacy, retry behavior, quotas, output formats, and total operating cost—not just the per-request price.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Screenshot API pricing and account limits are not stated in the API facts summarized here, so check the provider’s current pricing and quota pages before estimating cost. For either hosted or self-hosted capture, validate demand with realistic pages and settings, and avoid enabling expensive full-page or high-resolution outputs unless the use case needs them.

Frequently Asked Questions

Can an Express screenshot endpoint return a PDF instead of an image?

Yes. The documented API accepts PDF output; use its POST request for PDF-specific settings and relay the resulting bytes with the provider’s returned content type.

Should my frontend call the screenshot provider directly?

Usually not when the API key is secret. Call your authenticated Express route so the key remains server-side and you can validate URLs, enforce access, and control usage.

Can I use the screenshot endpoint for a list of pages?

Yes. Submit a batch request, keep its batch ID, and expose authorized polling or SSE progress rather than making a long-running request for every page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.