Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk5 min

How to Take a Puppeteer Screenshot in an Express API Endpoint

Return a Puppeteer screenshot directly from an Express route as a correctly typed PNG response, without writing a temporary file.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To return a Puppeteer screenshot from an Express route, await page.screenshot(), convert its returned bytes to a Node.js Buffer, set the response type to image/png, and send it with res.send(). You do not need to save a temporary file. Close the browser in a finally block so it is cleaned up after both successful and failed requests.

Return a screenshot directly from an Express route

This ES-module example targets the API patterns documented for Puppeteer 25.12.0 and Express 4.x. Confirm compatibility with the versions installed in your project. It sends a full-page PNG as binary data; it does not write a screenshot to disk.

As an Amazon Associate I earn from qualifying purchases.

import express from 'express';
import puppeteer from 'puppeteer';

const app = express();

app.get('/screenshot', async (req, res, next) => {
  let browser;

  try {
    const url = req.query.url;
    if (typeof url !== 'string') {
      return res.status(400).json({ error: 'A URL is required' });
    }

    // In production, validate or allowlist destinations before navigating.
    browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url, { waitUntil: 'networkidle2' });

    const bytes = await page.screenshot({ type: 'png', fullPage: true });
    res.type('png').send(Buffer.from(bytes));
  } catch (error) {
    if (res.headersSent) return next(error);
    next(error);
  } finally {
    if (browser) await browser.close();
  }
});

Add your app’s normal listener, for example app.listen(3000), to run it. With the server running, request /screenshot?url=https%3A%2F%2Fexample.com. The response body is the PNG image, so a browser or HTTP client can consume it as an image rather than receiving JSON containing encoded image data.

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

Why convert the result to a Buffer?

Puppeteer’s page.screenshot() returns a Promise<Uint8Array> by default. Buffer.from(bytes) creates the binary Buffer that Express res.send() accepts. The screenshot API can return a base64 string if you request encoding: 'base64', but that is unnecessary for this binary response.

Why set the response type?

Express 4.x sends a Buffer as application/octet-stream unless you set a type. Calling res.type('png') before send() labels the response as image/png. Express also handles the content length for this ordinary, non-streaming response.

Why use finally and check headersSent?

The finally block closes the browser whether navigation or capture succeeds or throws. If an error occurs after a response has started, attempting to send a second response can itself fail. The res.headersSent check passes that error to Express’s error handling instead of trying to create another response.

Choose the screenshot options you need

The basic route captures the whole page as PNG. Puppeteer’s screenshot API supports other capture and output choices; use only the options that fit the response your endpoint promises.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Need Option Effect
Capture the visible viewport Omit fullPage or set it to false Captures the viewport rather than extending the image to the full page.
Capture the full page fullPage: true Captures beyond the visible viewport.
Capture a bounded region clip Limits the capture to a specified region.
Return a transparent background omitBackground: true Omits the default background for transparency where the page permits it.
Use a compressed image format type: 'jpeg', optionally with quality JPEG supports a quality value from 0 to 100. That quality setting does not apply to PNG.
Save a file instead of only responding with bytes path Writes the screenshot to that path. For a route whose only goal is returning the image, this is not needed.

PNG is the documented default screenshot type. The API documentation does not quantify the file-size difference between PNG and JPEG, so choose based on your image-quality requirements and measure your own pages if response size matters.

Protect the endpoint before navigating to a supplied URL

A route that accepts a URL and opens it in a browser should not treat arbitrary user input as safe. The example’s validation comment is general security guidance, not a Puppeteer-provided SSRF policy. In production, restrict destinations to the hosts and schemes your application actually needs, and reject disallowed input before calling page.goto(). Do not expose an unrestricted browser-navigation endpoint to untrusted callers.

Handle failures and operational trade-offs

Navigation and page readiness

The example uses waitUntil: 'networkidle2' and captures after navigation resolves. That is a choice, not a guarantee that every page has finished rendering all content: applications may load data later or keep network connections open. If a particular page requires a known element or additional delay before capture, define and implement that readiness condition for your application rather than assuming one navigation setting fits every site.

Memory, response size, and latency

The image is held in memory and sent as one response, avoiding temporary-file handling but requiring memory for the screenshot bytes. Full-page captures can be larger than viewport captures. PNG is lossless; JPEG offers a quality option, but no universal size or speed advantage is established here. Measure representative pages and set request timeouts and workload limits appropriate to your deployment.

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.

Browser lifecycle and concurrent requests

This pattern launches and closes a browser for each request, which is straightforward and ensures request-scoped cleanup. Browser startup and concurrent workload behavior depend on deployment and usage; the cited API references do not establish production benchmarks, concurrency limits, or a recommended pooling architecture. If you later reuse browsers or contexts to reduce overhead, define isolation, cleanup, and concurrency behavior deliberately. Puppeteer documents that creating pages or closing a page in the same BrowserContext waits for an ongoing screenshot to finish; bringToFront() does not provide that coordination.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting

  • The response downloads as an unknown binary file. Set the MIME type before sending: res.type('png') for PNG or the corresponding JPEG type for JPEG.
  • The response is not a valid image. Send the screenshot bytes, not a stringified object or JSON representation. With the default screenshot encoding, pass Buffer.from(bytes) to res.send().
  • The page is blank or incomplete. Check that navigation completed and that your readiness condition matches the site’s rendering behavior. Some pages render important content after the navigation event you chose.
  • The request fails after the response has started. Do not attempt a second response once headers are sent. The example forwards the error with next(error) when res.headersSent is true.
  • Browser resources remain open after an error. Keep browser closure in finally; do not place cleanup only after the screenshot succeeds.
  • The endpoint can be used to visit unintended sites. Validate and allowlist destinations before navigation. A string-type check only verifies the query parameter’s type; it is not a destination security policy.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. A single GET request can return an image or PDF. For example, this cURL call saves a WebP screenshot:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before capture, with each cleanup step optional. 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; paid plans start at $5 for 3,000. Sign up for free.

Frequently asked questions

Can an Express screenshot route return an image without saving a file?

Yes. By default, Puppeteer returns screenshot bytes directly. Convert those bytes to a Buffer and send them; a path is only needed when you also want to write a file.

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

Does Puppeteer coordinate screenshot work with page closure?

In the same BrowserContext, Puppeteer documents that page creation and page closure wait for an ongoing screenshot to finish. Bringing a page to the front does not.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.