October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
Buffer

Puppeteer Screenshot to Buffer: Get Image Bytes Without Writing a File

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.

Use await page.screenshot() without a path, then convert the returned Uint8Array with Buffer.from(). Puppeteer’s documented default result is Promise<Uint8Array>, not a Node.js Buffer. Omitting path keeps the image in memory, so you can upload it, attach it to a response, or pass it to an image library without creating a temporary file.

The shortest working example

This example uses the current Puppeteer API documented as version 25.12.0 at the time of reference. It captures https://example.com in memory and creates a Buffer for code that explicitly requires Node’s Buffer class.

import puppeteer from 'puppeteer';
import { Buffer } from 'node:buffer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.goto('https://example.com');

  // No path: nothing is written to disk.
  const screenshotBytes = await page.screenshot();
  const screenshotBuffer = Buffer.from(screenshotBytes);

  // Use screenshotBuffer with your upload, storage, or image-processing code.
  console.log(`Captured ${screenshotBuffer.length} bytes`);
} finally {
  await browser.close();
}

The finally block closes Chromium even when navigation or capture throws. The conversion does not encode or decode the image; it gives you a Buffer containing the same screenshot bytes.

What Puppeteer actually returns

The Page.screenshot() method is documented as capturing a screenshot of the page. With the normal binary overload, its return type is Promise<Uint8Array>. A Node.js Buffer is a Uint8Array-compatible byte container, so most Node APIs that accept a Uint8Array can consume Puppeteer’s result directly.

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

Use the Uint8Array directly when possible

const bytes = await page.screenshot();
await someUploader(bytes);

Prefer this path when the receiving library documents support for Uint8Array. It avoids an unnecessary conversion and makes the API’s actual return type clear.

Convert when a library requires Buffer

const bytes = await page.screenshot();
const buffer = Buffer.from(bytes);
await legacyNodeModuleThatRequiresBuffer(buffer);

Import Buffer from node:buffer in ESM code, as shown above. In CommonJS projects, the global Buffer is normally available, but an explicit import also works and documents the dependency.

Keep the screenshot in memory

The path option is optional. Leave it out to receive bytes instead of saving an image file. Do not set path: '/tmp/shot.png' and then read the file if your goal is an in-memory capture; that adds filesystem work and creates cleanup responsibilities.

Send the Buffer in an HTTP response

import express from 'express';
import puppeteer from 'puppeteer';
import { Buffer } from 'node:buffer';

const app = express();
const browserPromise = puppeteer.launch();

app.get('/screenshot', async (req, res) => {
  const browser = await browserPromise;
  const page = await browser.newPage();
  try {
    await page.goto('https://example.com');
    const bytes = await page.screenshot({ type: 'png' });
    const image = Buffer.from(bytes);
    res.type('png').send(image);
  } catch (error) {
    res.status(502).send('Screenshot failed');
  } finally {
    await page.close();
  }
});

app.listen(3000);

This pattern keeps the browser process alive while creating a new page per request. In production, add authentication, request limits, navigation policy, and an explicit timeout appropriate for your environment.

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

Upload to object storage or an API

const bytes = await page.screenshot({ type: 'webp', quality: 82 });
const buffer = Buffer.from(bytes);

await storageClient.putObject({
  key: 'captures/example.webp',
  body: buffer,
  contentType: 'image/webp'
});

Use a quality value only for formats where Puppeteer supports it. The documented quality range is 0–100 and it does not apply to PNG.

Choose the capture you need

Viewport versus full page

const viewportBytes = await page.screenshot();
const fullPageBytes = await page.screenshot({ fullPage: true });

fullPage defaults to false, so the first call captures the current viewport. Set it to true when you need the page’s full scrollable content.

Capture a rectangle with clip

const bytes = await page.screenshot({
  clip: { x: 40, y: 80, width: 800, height: 500 }
});

clip describes the region in page coordinates. Make sure the rectangle is valid for the page and viewport you created; an incorrect region can produce an error or an unexpectedly cropped image.

Select the image format

const png = await page.screenshot({ type: 'png' });
const jpeg = await page.screenshot({ type: 'jpeg', quality: 85 });
const webp = await page.screenshot({ type: 'webp', quality: 85 });

Puppeteer documents PNG as the default format. A supplied path can also imply a format from its extension, but when you are keeping bytes in memory, set type explicitly so downstream code knows what it will receive.

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

Preserve transparent backgrounds

const transparentBytes = await page.screenshot({ omitBackground: true });

omitBackground: true hides the default white page background. Transparency is useful for isolated UI elements or overlays; it is not a way to remove a website’s own opaque background pixels.

Base64 is a different return mode

If the consumer specifically wants text, use Puppeteer’s base64 encoding overload:

const base64 = await page.screenshot({ encoding: 'base64' });
const dataUri = `data:image/png;base64,${base64}`;

That overload returns a Promise<string>. It is not the default binary result. Base64 increases the representation size and is usually less convenient than a Buffer for file uploads or binary HTTP bodies. Convert base64 back only when an API truly requires bytes:

const base64 = await page.screenshot({ encoding: 'base64' });
const buffer = Buffer.from(base64, 'base64');

A reusable helper for application code

Centralizing capture and conversion keeps browser cleanup consistent:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import puppeteer from 'puppeteer';
import { Buffer } from 'node:buffer';

export async function screenshotBuffer(url, options = {}) {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.goto(url);
    const bytes = await page.screenshot(options);
    return Buffer.from(bytes);
  } finally {
    await browser.close();
  }
}

const image = await screenshotBuffer('https://example.com', {
  fullPage: true,
  type: 'jpeg',
  quality: 85
});

For a service handling many requests, do not launch a new browser for every request unless the low volume justifies it. Keep a controlled browser pool, create and close pages per job, and ensure failed jobs still release their pages.

Concurrency and reliability details

Puppeteer notes that while a screenshot is being taken in a BrowserContext, some page-creation and close methods wait for the screenshot operation to finish. Page.bringToFront() does not wait for existing screenshot operations. Treat a page as busy until its screenshot promise resolves, especially when coordinating multiple pages or captures.

Serialize operations on one page

await page.goto(target);
const first = await page.screenshot();
// Change page state only after the first capture has completed.
const second = await page.screenshot({ fullPage: true });

For parallel work, prefer separate pages or BrowserContexts and cap concurrency according to the memory available to your deployment. There is no universal screenshot-size or memory guarantee: page complexity, viewport, full-page height, image assets, browser version, and runtime all affect resource use.

Keep output metadata with the bytes

When you pass a Buffer to storage or an HTTP response, also record the selected format and dimensions in your own metadata. A Buffer does not by itself tell your application whether the bytes are PNG, JPEG, or WebP.

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

Troubleshooting Puppeteer screenshot buffers

“I got a file path or undefined, not bytes”

Check that you did not pass path. The in-memory form is const bytes = await page.screenshot();. If you do provide a path, Puppeteer writes the capture there instead of using the pathless workflow.

“Buffer.from is not defined”

Import it explicitly with import { Buffer } from 'node:buffer'; in an ESM module. In a browser bundle, Node’s Buffer API is not automatically available; perform the conversion on the server.

“The image is blank or incomplete”

  • Confirm that page.goto() completed before the screenshot call.
  • Check that the URL is reachable from the machine running Chromium.
  • Use fullPage: true when the missing content is below the viewport.
  • Verify that a clip rectangle is inside the intended page area.
  • For pages that render asynchronously, wait in your application for the page state your capture requires before calling screenshot().

“Quality has no effect”

The documented quality setting does not apply to PNG. Select JPEG or WebP when you need lossy quality control, then set a value from 0 to 100.

“Transparency is still white”

Use omitBackground: true and choose a format that preserves transparency. Also check whether the page itself paints a white element or background; Puppeteer cannot make those page pixels transparent.

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

“The process becomes slow or runs out of memory”

Large full-page captures and pages containing many high-resolution images require more memory. Reduce concurrency, capture a region with clip, avoid unnecessary full-page images, and close pages after each job. Do not rely on a universal byte limit because Puppeteer’s result size depends on the content and runtime.

“Closing the page hangs during capture”

Wait for the screenshot promise before closing or recycling the page. Puppeteer documents that some page-close and page-creation operations in the same BrowserContext wait for an active screenshot to finish.

Alternative: return bytes without a Buffer conversion

If your downstream API accepts a typed array, this is sufficient:

const bytes = await page.screenshot({ fullPage: true });
await fetch(uploadUrl, {
  method: 'PUT',
  headers: { 'content-type': 'image/png' },
  body: bytes
});

Use Buffer.from(bytes) when the API checks for a Node Buffer specifically, exposes Buffer-only methods, or your existing code standardizes binary payloads on Buffer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo provides a hosted screenshot API when you do not want to install or operate Chromium. One GET request returns PNG, JPEG, WebP, or PDF data. Its cleanup steps accept cookie and consent banners before capture and remove more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing state in X-Page-Verdict and X-Billed headers.

cURL

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

Python

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)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API documentation for parameters and response handling. The service also supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper and page-range controls, custom CSS and JavaScript, pre-capture clicks, selector hiding, selector or network-idle waits, ad/tracker/request blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable TTL caching, signed public-image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, and an OpenAPI specification. Existing parameter names used by other screenshot APIs are accepted to ease migration.

ScreenshotNeo includes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account to try it.

Which approach should you use?

Requirement Best fit Reason
Your Node process already runs Puppeteer page.screenshot() plus optional Buffer.from() No extra network service; complete control over the browser page.
A consumer accepts typed arrays Return the original Uint8Array Matches Puppeteer’s documented binary return type.
A consumer requires Node Buffer Buffer.from(bytes) Provides the Buffer interface without writing a temporary file.
You need text embedded in JSON or HTML encoding: 'base64' Uses Puppeteer’s string-returning overload, at the cost of base64 overhead.
You want hosted capture and AI-agent tools ScreenshotNeo Browser setup is replaced by an API and MCP server, with clean-shot processing and billing status headers.

Frequently Asked Questions

Does Puppeteer return a Buffer by default?

No. The documented default screenshot overload returns a Uint8Array. Convert it with Buffer.from() only when your Node consumer specifically requires Buffer.

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.

Can I take a screenshot without saving a file?

Yes. Omit the path option; the screenshot is returned as in-memory bytes.

When should I use base64 instead of a Buffer?

Use the encoding: ‘base64’ overload when the receiving interface requires a string, such as a JSON field or data URI. Use binary bytes for uploads and other file-like operations.

Why is my full-page Buffer much larger than a viewport capture?

fullPage: true includes the page’s complete scrollable content. Long pages and high-resolution assets naturally produce more image data; capture a clip or reduce concurrency when resource use matters.

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.

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

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.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

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.