ScreenshotNeo

BlogHow-to

How to Generate Website Screenshots from URLs in Node.js in India

Capture a URL as a viewport, full-page, or element screenshot with Node.js. Includes runnable Playwright and Puppeteer examples, setup, troubleshooting, and an API option.

By the ScreenshotNeo team4 October 20269 min read

To generate a website screenshot from a URL in Node.js, open the URL in a browser controlled by a library such as Playwright or Puppeteer, wait for the page state you need, and call the page’s screenshot method. The examples below save a PNG locally. Playwright can also capture the full scrollable page, an individual element, or return image bytes in memory. These steps are the same for developers in India: the sources document general browser setup and APIs, not an India-specific screenshot API or hosting requirement.

1. Choose the capture you need

Decide what the output should show before writing the script:

  • Viewport: the visible browser area. This is the default screenshot mode.
  • Full page: the full scrollable page, including content below the fold.
  • Element: one component selected by a CSS selector or locator.
  • Image buffer: image bytes held in memory for further processing instead of a file.

Playwright documents viewport, full-page, element, and buffer capture in its Page API. The file extension in path determines the screenshot format. Playwright’s screenshot options also include image quality for formats that support it and scale settings for CSS-pixel or device-pixel output. Device scaling can produce larger images.

2. Install Playwright and its browser

Playwright is a practical default when you want its documented Chromium, WebKit, and Firefox options. A basic script can use the playwright package directly:

mkdir url-screenshot
cd url-screenshot
npm init -y
npm install playwright
npx playwright install chromium

The browser binary is a separate install from the npm package. Playwright’s browser installation guide explains browser downloads, system dependencies, and supported engines. To install all default browsers instead, run npx playwright install. On a Linux environment that needs system packages, use npx playwright install --with-deps chromium where supported by your environment.

3. Capture a URL with Playwright

Save this as screenshot.mjs. It takes the target URL from the command line, writes screenshot.png, and always closes the browser even when navigation or capture fails.

import { chromium } from 'playwright';

const url = process.argv[2] ?? 'https://example.com';
const browser = await chromium.launch({ headless: true });

try {
  const page = await browser.newPage({
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 1,
  });

  const response = await page.goto(url, {
    waitUntil: 'load',
    timeout: 30_000,
  });

  if (!response) {
    console.warn('Navigation did not return a main-document response.');
  } else if (!response.ok()) {
    console.warn(`Main document returned HTTP ${response.status()}`);
  }

  await page.screenshot({ path: 'screenshot.png' });
  console.log('Saved screenshot.png');
} finally {
  await browser.close();
}

Run it with node screenshot.mjs https://example.com. A returned HTTP error status does not necessarily prevent the page from rendering, so the example reports it and still captures what loaded. Treat this as a useful debugging signal rather than a guarantee that the page is complete.

Full-page and element screenshots

For a full-page capture, change the screenshot call to:

await page.screenshot({ path: 'full-page.png', fullPage: true });

For one element, wait for it and use its locator:

const card = page.locator('.product-card').first();
await card.waitFor({ state: 'visible', timeout: 10_000 });
await card.screenshot({ path: 'product-card.png' });

Replace .product-card with a selector from the target page. If the selector matches multiple elements, choose the intended one with first(), nth(), or a more specific selector. Element screenshots are useful when the output should isolate a component rather than include the surrounding page.

Wait for page content that loads late

A navigation event does not prove that every image, animation, or application request has settled. If a known component appears after navigation, wait for it explicitly:

await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
await page.locator('main article').waitFor({ state: 'visible', timeout: 15_000 });
await page.screenshot({ path: 'article.png', fullPage: true });

Choose a readiness signal that matches the page. A fixed delay can help with a known short animation, but it is less reliable than waiting for a meaningful selector. Network-idle waits may also be unsuitable for pages that keep analytics, streaming, or polling requests open.

Capture into memory

Omit path to get image bytes back instead of saving directly to a file:

const imageBytes = await page.screenshot({ type: 'png' });
// Pass imageBytes to your storage, processing, or comparison code.

The returned buffer can be written with Node’s filesystem API or passed to an image-processing pipeline.

4. Puppeteer alternative

Puppeteer offers the same basic workflow: launch a browser, navigate, save a screenshot, and close the browser. Its screenshots guide demonstrates Page.screenshot() with waitUntil: 'networkidle2'; use that as an example, not as a universal signal that every site is visually settled. See the Puppeteer screenshots guide.

npm install puppeteer
import puppeteer from 'puppeteer';

const url = process.argv[2] ?? 'https://example.com';
const browser = await puppeteer.launch({ headless: true });

try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 900 });
  const response = await page.goto(url, {
    waitUntil: 'networkidle2',
    timeout: 30_000,
  });

  if (response && !response.ok()) {
    console.warn(`Main document returned HTTP ${response.status()}`);
  }

  await page.screenshot({ path: 'screenshot.png' });
  console.log('Saved screenshot.png');
} finally {
  await browser.close();
}

Run it with node screenshot.mjs https://example.com. For an element capture, get an element handle and call its screenshot method:

const element = await page.waitForSelector('.product-card', { visible: true });
if (!element) throw new Error('Product card was not found');
await element.screenshot({ path: 'product-card.png' });

Puppeteer documents that an element screenshot attempts to scroll a hidden element into view by default.

5. Screenshot formats and useful options

Need Playwright option or approach Notes
PNG output path: 'shot.png' or type: 'png' Good general-purpose lossless output.
JPEG or WebP Use the corresponding supported type and extension Use quality settings where the selected format supports them; check the API docs for the installed version.
Full scrollable page fullPage: true Can create very tall output; large pages use more memory and storage.
Element only Locator or element screenshot Wait for the target to be visible and use a selector that identifies the intended element.
CSS-pixel versus device-pixel size scale: 'css' or scale: 'device' Device scale can produce higher-resolution, larger files.
Viewport dimensions Set viewport when creating the page Keep dimensions consistent if comparing screenshots.
Output for processing Omit path and retain returned bytes Useful for uploads or image comparison without an intermediate file.

Consult the Playwright Page API for the exact accepted screenshot options in the version installed in your project.

6. Running this in an application or deployment

  1. Install the matching browser binary. Browser versions are tied to Playwright releases. When upgrading Playwright, refresh the browser installation as needed using the documented install command.
  2. Make browser setup part of deployment. A local development machine may have libraries and browser binaries that a clean server does not. Follow the browser installation instructions for the target operating system.
  3. Bound work. Set navigation and selector timeouts, limit concurrent browser work to what the host can sustain, and close pages and browsers after capture.
  4. Validate target access. Confirm that the deployment can reach the target URL and that the target permits the requested access. India does not imply a distinct library configuration in the cited documentation; validate your own host and target-site access.
  5. Protect the endpoint if you expose one. Validate and restrict submitted URLs and avoid allowing untrusted callers to direct a browser to internal network addresses. Keep credentials out of screenshot output and logs.

These are operational precautions for a service that opens user-supplied URLs; they are not India-specific requirements.

7. Troubleshooting

Symptom Likely cause Fix
Executable or browser not found The package is installed but its browser binary is missing or does not match the installed version. Run npx playwright install chromium after installing or updating Playwright. In deployment, include this in the build setup.
Linux launch fails because a shared library is missing The host image lacks browser system dependencies. Use Playwright’s documented dependency installation for the target environment, such as npx playwright install --with-deps chromium where supported.
Navigation timeout The host is slow, the site is hanging, or the chosen lifecycle event never occurs. Check the URL and network reachability, choose a lifecycle event that fits the site, set an appropriate timeout, and wait for a meaningful selector when possible.
Screenshot is blank or missing expected content The page did not render successfully, content is delayed, or the screenshot ran before the relevant component appeared. Inspect the navigation response and page state, then wait for a visible content selector before capture.
Images or fonts are absent External resources have not loaded, are blocked, or failed at the target. Wait for the relevant image or component, check the target’s resource access, and distinguish failed page resources from a screenshot API problem.
Full-page file is unexpectedly large The page is long or device-pixel scaling creates more pixels. Capture only the needed element or viewport, use CSS scale where suitable, or select a more compact image format and quality.
Selector wait fails The selector is incorrect, the element is inside a frame, or the page state differs from expectation. Inspect the page markup and use a selector that exists in the loaded document; account for frames when relevant.
Works locally but not in production Different browser binaries, missing OS libraries, restricted outbound access, or resource limits. Reproduce with the deployment’s browser install and operating system, verify network access, and monitor memory and concurrency.

8. Performance, reliability, and cost

Browser capture requires launching or reusing a browser process, loading the target page, and rasterizing the selected area. The page itself often dominates work because it may load scripts, images, fonts, and third-party resources. There is no universal capture-time benchmark in the cited documentation, so measure against your own pages and deployment.

  • Control image size: capture the needed area and viewport dimensions. Full-page and device-scale output can increase image size and memory use.
  • Reuse carefully: for repeated captures, browser reuse can avoid repeated launches, but isolate page state and close pages when finished. Set a concurrency limit appropriate to available memory.
  • Make readiness explicit: waiting for a page-specific selector is usually clearer than assuming that a generic navigation event means every visual element is ready.
  • Handle failures: record the URL, navigation status, timeout, and capture outcome; retry only transient failures and place a cap on retries.
  • Budget for operations: self-hosting means maintaining browser binaries, system dependencies, compute, storage, and failure handling. The cited sources do not establish a fixed cost or performance figure.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. Send one GET request with the URL and receive an image or PDF. Its API supports PNG, JPEG, WebP, full-page and element captures, and many other options. 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,
)
r.raise_for_status()
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(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

Cookie banners, popups, and chat widgets are removed before the shot, and each step can be turned off. Bot checks, blank pages, and failed loads are never billed; response headers identify the page verdict and billing outcome. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

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

FAQ

How do I take a screenshot of a URL in Node.js?

Navigate to the URL with Playwright or Puppeteer, then call the page screenshot method with a file path.

How do I capture the whole page with Playwright?

Pass fullPage: true to page.screenshot().

Does this require different setup in India?

The cited library documentation describes general Node.js and browser installation workflows, not a distinct India-only setup. Check the access and operating requirements of your own deployment.

Should I use Playwright or Puppeteer?

Both document URL navigation and screenshot capture. Choose based on the browser engines, project setup, and readiness behavior your workflow needs; the sources do not establish a universal winner.