Skip to content

Guide

Take a website screenshot in Node.js

Playwright launches Chromium and writes a PNG. A hosted screenshot API skips that install and returns image bytes from one HTTP call. This guide shows a complete local script first. The DataTuber example is only the route this website implements.

Published by
DataTuber
Published
Updated
Reading time
8 min read

Key takeaways

  • Playwright is the direct approach: install the package, install Chromium, open a page, and call page.screenshot.
  • A viewport capture is the window size you set. fullPage: true uses that width and the document’s scroll height.
  • A hosted API does not require a browser on your machine. Each service defines its own fields. This page does not compare vendors.
  • On this site, POST /api/screenshots accepts a public https URL, a viewport name, and png or jpg. It does not accept a pixel size or a full-page flag.
  • Check the HTTP status before you save the body. A DataTuber error is JSON with a message. A success body is the image.

Ways to capture a page

Two approaches cover most Node.js screenshot work. Run a browser yourself, or send the URL to a service that runs one for you.

Playwright and Puppeteer are the usual libraries. Playwright keeps the browser download separate from npm install. The puppeteer package downloads Chromium as part of its install. The script on this page uses Playwright. Both can open localhost, set a viewport, and capture the full document height.

A hosted screenshot API accepts a page URL and returns an image. Your process does not launch a browser. Authentication, allowed hosts, viewport fields, and full-page support are defined by that API. Later sections describe only the route this DataTuber website implements. They are not a catalog of other services.

Prerequisites

Use Node.js 18 or newer. You need a network connection the first time you install Playwright’s Chromium build, and enough disk for that browser. Confirm the runtime with node --version before you install anything.

The script uses import and top-level await. Save it as screenshot.mjs, or use a package.json with "type": "module" and a .js file. Either way, run it with node.

Install Playwright and Chromium

npm install playwright adds the library. It does not add the browser. npx playwright install chromium downloads the Chromium build Playwright launches. Skip that second command and launch fails because the executable is missing.

npm install playwright
npx playwright install chromium
node screenshot.mjs

Run these in the project directory, then run the script saved as screenshot.mjs.

A complete Playwright example

This opens https://example.com at 1280×720, writes viewport.png for that window, then writes full-page.png for the full document. browser.close() runs even when navigation throws. Replace the URL with the page you want to capture.

import { chromium } from "playwright";

const browser = await chromium.launch();
const page = await browser.newPage({
  viewport: { width: 1280, height: 720 },
});

try {
  const response = await page.goto("https://example.com", {
    waitUntil: "load",
    timeout: 30_000,
  });
  if (!response?.ok()) {
    const status = response ? response.status() : "no response";
    throw new Error(`Navigation failed (${status}).`);
  }

  await page.screenshot({ path: "viewport.png", type: "png" });
  await page.screenshot({
    path: "full-page.png",
    type: "png",
    fullPage: true,
  });
} finally {
  await browser.close();
}

Save as screenshot.mjs. Node.js 18 or newer. The script talks to example.com, not to DataTuber.

waitUntil: "load" waits for the load event. Pages that draw after that event can still look unfinished. Wait for a selector you care about before calling screenshot if the first image is blank. networkidle waits until network connections settle, and pages that keep a connection open can sit there until timeout.

Viewport and full page

The viewport is the browser window: a width and a height in CSS pixels. page.screenshot() without fullPage captures that rectangle only. Content below the fold is not in the file.

fullPage: true keeps the viewport width and extends the image to the document’s scroll height. Playwright scrolls and stitches that capture. A short page looks almost the same either way. A long article does not.

Full-page capture is a poor fit for a page that grows forever, such as an infinite scroll. Fixed headers can also repeat or cover content in the stitched image. Capture the viewport, or a single element with locator.screenshot(), when the full document is not a stable height.

The script does not set deviceScaleFactor, so the PNG is one pixel per CSS pixel. Raise it only when you need a denser image. That produces more pixels. It is not a quality score.

Browser automation and a hosted API

Choose Playwright when the page is on your machine, behind a login you can script, or when you need an exact width, height, and full-page flag. Choose an HTTP API when you do not want to install or operate a browser. The table states what this website’s route accepts. It does not rank products, and it does not report timings.

Playwright in your Node process compared with POST /api/screenshots on this website. Not a speed or quality ranking.

What you install

Playwright
playwright, then Chromium
POST /api/screenshots
Nothing beyond Node.js 18

Who runs the browser

Playwright
Your Node process
POST /api/screenshots
This website’s capture route

Size

Playwright
Any width and height you set
POST /api/screenshots
A viewport name, not pixels

Full page

Playwright
fullPage: true
POST /api/screenshots
Not a field on this route

Which URLs

Playwright
Any URL the machine can open, including localhost
POST /api/screenshots
Public https URLs only

Failure you handle

Playwright
A thrown navigation or launch error
POST /api/screenshots
An HTTP status and a JSON message

The route this site implements

POST https://datatuber.com/api/screenshots is the screenshot route served by this website. Do not send the call to api.datatuber.com. That host is not this API. The body is JSON with url, viewport, and format.

viewport is desktop, tablet, or mobile. In the current presets, desktop is 1280×720, tablet is 768×1024, mobile is 390×844. format is png or jpg. jpeg is accepted and stored as jpeg. Custom pixel sizes and a full-page flag are not part of this request.

The URL has to be https, with no username, password, port, or IP address. The server resolves the hostname and rejects localhost, link-local, and private addresses. http URLs are rejected.

Replace YOUR_API_KEY with a key from a verified account if you want the image stored for that workspace. The dashboard shows the secret once. Leave the placeholder in any example you commit. The homepage demo calls the same path without a key and does not store the image.

import { writeFile } from "node:fs/promises";

const origin = "https://datatuber.com";

const response = await fetch(new URL("/api/screenshots", origin), {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://www.python.org",
    viewport: "desktop",
    format: "png",
  }),
});

if (!response.ok) {
  const payload = await response.json().catch(() => null);
  const message =
    payload && typeof payload.message === "string"
      ? payload.message
      : response.statusText;
  throw new Error(message);
}

const image = Buffer.from(await response.arrayBuffer());
await writeFile("screenshot.png", image);

Node.js 18 or newer. YOUR_API_KEY is a placeholder. The origin is https://datatuber.com, which is the host serving this site.

A successful response body is the image, with Content-Type image/png or image/jpeg, and cache-control no-store. Any other status is JSON. When the route recognized the failure, that JSON has a string message. Writing the body to disk before you check response.ok saves an error as if it were a PNG.

Homepage demo compared with a keyed call on the current DataTuber route. Limits come from the beta plan and rate buckets in the account migration.

Authorization

Homepage demo
No Authorization header
API key
Bearer token

Path

Homepage demo
POST /api/screenshots
API key
POST /api/screenshots

Image kept

Homepage demo
Not stored
API key
Stored for that workspace

Allowance

Homepage demo
5 captures an hour for a hashed IP
API key
100 screenshots in a UTC month, and 6 requests a minute

Shared gap

Homepage demo
11 seconds between captures
API key
11 seconds between captures

Nothing is charged before January 1, 2027. Pricing has no checkout. Field details are on Screenshots.

Common errors

Playwright: if launch says the executable does not exist, run npx playwright install chromium in that project. If goto throws a timeout, the load event did not happen within timeout. Increase it, or wait for a specific selector instead of the whole page. A connection error means the URL did not open from that machine. A blank PNG usually means the pixels you wanted were not painted yet.

A full-page file that is enormous, or that never finishes, usually means the page keeps growing. Capture the viewport instead.

This site’s route returns JSON, not an image, when the call is refused. "Send a URL, viewport, and format." means a required field was missing or not one of the accepted names. "Only https URLs are accepted." and "IP addresses are not accepted." are URL rules. "This hostname is blocked." and "The hostname resolved to a blocked address." reject local and private targets. "That API key is not valid." means the bearer token did not match a key. "Verify your email before using DataTuber." means the account cannot create or use a key yet.

"Screenshot capture is not configured on this server." means this deployment has no capture credentials. A 429 message asks you to wait. Those strings are the messages implemented in this repository.

What this page is based on

Playwright
The script uses playwright’s launch, newPage, goto, and screenshot methods. No timed run of that script is reported here.
This website
POST /api/screenshots, the URL checks, the viewport presets, and the account migration in this repository. Checked October 30, 2026.
Not included
No timed live capture, no performance numbers, and no ranking of other screenshot products.

Questions

Do I have to install a browser?

For the Playwright script, yes. npm install playwright is not enough. Run npx playwright install chromium as well. A hosted HTTP API does not install a browser on your machine.

What is the difference between a viewport and a full-page screenshot?

The viewport is the window size. fullPage: true keeps that width and captures the scroll height of the document. This site’s API only accepts the names desktop, tablet, and mobile. It has no full-page field.

Can Playwright screenshot localhost?

Yes, if the page is reachable from the machine running Node. POST /api/screenshots on this site rejects localhost, IP addresses, and private hosts.

Which Node.js version do I need?

Node.js 18 or newer. The HTTP example uses global fetch. If Playwright refuses to launch, its install notes will name the Node version it expects.

Which host do I call for DataTuber?

https://datatuber.com/api/screenshots. api.datatuber.com is not serving this API. Getting started shows the same body in cURL, JavaScript, Python, and PHP.

Will the DataTuber call charge a card?

No payment is collected before January 1, 2027. Pricing has no checkout.

  • Guides

    The short index of notes published on this site.

  • Getting started

    The same POST in cURL, JavaScript, Python, and PHP.

  • Screenshots

    The body fields, and what a keyed call stores.

  • Pricing

    The beta allowance, and the earliest date billing can start.