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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

ActiveX is not required. For a screenshot of any URL as a browser renders it, run JavaScript in Node.js with Playwright or Puppeteer. If code must run inside the page itself, use html2canvas for a DOM-based image, or use the Screen Capture API when a person should choose a screen, window, or tab. These approaches solve different problems: a web page cannot silently capture an arbitrary URL or the user’s desktop.

Choose the method that matches your screenshot

What you need Best fit Main limitation
Capture an arbitrary URL exactly as a browser renders it Playwright or Puppeteer in Node.js Requires a browser automation process outside the page
Turn selected DOM content into an image from a page feature html2canvas Reconstructs the image from DOM data; cross-origin content and unsupported CSS can differ from real pixels
Let a user select a display, window or tab Screen Capture API Always uses a browser permission and source picker; it is not silent URL capture

The phrase “take a website screenshot with JavaScript” is therefore ambiguous. Decide first whether your JavaScript runs in Node.js (where it can launch a browser and open a URL) or in the document itself (where browser security rules apply).

Capture a rendered URL with Playwright

Playwright is the most direct general-purpose solution when the output should be a browser-rendered screenshot. Its Page API provides navigation and page.screenshot(); the screenshots guide documents full-page and element captures.

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

Install and run

  1. Install a current Node.js release.
  2. Create a project and install Playwright:
    mkdir js-shot
    cd js-shot
    npm init -y
    npm install -D playwright
    npx playwright install chromium
  3. Save this as capture.js:
const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  try {
    const page = await browser.newPage({
      viewport: { width: 1280, height: 800 },
      deviceScaleFactor: 1
    });

    await page.goto('https://example.com', {
      waitUntil: 'domcontentloaded',
      timeout: 45_000
    });

    // Replace this with a page-specific readiness check when needed.
    await page.screenshot({
      path: 'screenshot.png',
      fullPage: true,
      type: 'png'
    });
  } finally {
    await browser.close();
  }
})();

Run node capture.js. A viewport screenshot omits fullPage (or sets it to false). To capture one element, locate it and call await page.locator('.hero').screenshot({ path: 'hero.png' }). Playwright also supports JPEG and WebP output; use the format and quality options documented in its API.

Make readiness deterministic

networkidle can be useful for a page that finishes all requests, but it is not suitable for every site: analytics, advertisements and live data may keep connections open. Prefer a condition that represents the page being ready:

await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('#report', { state: 'visible', timeout: 30_000 });
await page.waitForTimeout(500); // only when a known animation needs to settle
await page.screenshot({ path: 'report.png', fullPage: true });

Lazy-loaded images may not exist until the page is scrolled. Before a full-page shot, scroll through the document and wait for images where the site requires it:

await page.evaluate(async () => {
  await new Promise(resolve => {
    let y = 0;
    const step = 600;
    const timer = setInterval(() => {
      window.scrollBy(0, step);
      y += step;
      if (y >= document.body.scrollHeight) {
        clearInterval(timer);
        window.scrollTo(0, 0);
        resolve();
      }
    }, 100);
  });
});
await page.waitForTimeout(300);
await page.screenshot({ path: 'lazy-page.png', fullPage: true });

For repeatable captures, fix the viewport, device scale factor, locale, timezone and browser version. Fonts, operating-system rendering, animations, video frames and third-party embeds can still vary, so do not promise pixel identity across environments.

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

Puppeteer: an equivalent JavaScript option

Chrome for Developers describes Puppeteer as a high-level API for automating Chrome and Firefox, including screenshots. Install it with npm install puppeteer; the package manages a compatible browser in its standard setup.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1280, height: 800, deviceScaleFactor: 1 });
    await page.goto('https://example.com', {
      waitUntil: 'domcontentloaded',
      timeout: 45_000
    });
    await page.waitForSelector('body');
    await page.screenshot({ path: 'puppeteer.png', fullPage: true });
  } finally {
    await browser.close();
  }
})();

The same operational rules apply: choose a page-specific readiness signal, handle authentication explicitly, and close the browser in a finally block.

Run the same workflow through other interfaces

cURL

Browser automation itself is JavaScript, but a command-line HTTP client can call a screenshot service when you do not want to install a browser. ScreenshotNeo provides a GET endpoint; replace the URL and key:

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 documentation for output and option details.

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

Python

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)

Node.js fetch

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(`HTTP ${res.status}`);
const fs = require('node:fs');
fs.writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));

Use html2canvas inside a web page

html2canvas walks the DOM and paints a canvas representation. It does not take the browser’s actual pixel buffer, and it only implements CSS properties it understands. This is useful for a “download this card” button, not for a guaranteed faithful capture of an arbitrary site.

<script src="https://cdn.jsdelivr.net/npm/html2canvas@latest/dist/html2canvas.min.js"></script>
<button id="save">Save card</button>
<section id="capture">Content to export</section>
<script>
document.querySelector('#save').addEventListener('click', async () => {
  const canvas = await html2canvas(document.querySelector('#capture'));
  const link = document.createElement('a');
  link.download = 'capture.png';
  link.href = canvas.toDataURL('image/png');
  link.click();
});
</script>

Origin and iframe limits

Images generally must be same-origin or served with suitable cross-origin headers (or a permitted proxy). Once a canvas is tainted by an unreadable cross-origin image, toDataURL() cannot read it. A script in one origin also cannot inspect a cross-origin iframe. No client-side option bypasses these browser security boundaries. Check the library’s supported CSS list before relying on filters, complex blending, pseudo-elements or unusual fonts.

When the Screen Capture API is the right answer

The Screen Capture API is designed for user-selected sharing. A user gesture should call getDisplayMedia(), after which the browser presents a picker:

async function recordSelection() {
  const stream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: false
  });
  const video = document.createElement('video');
  video.srcObject = stream;
  await video.play();
  const canvas = document.createElement('canvas');
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  canvas.getContext('2d').drawImage(video, 0, 0);
  canvas.toBlob(blob => {
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = 'selection.png';
    a.click();
    stream.getTracks().forEach(track => track.stop());
  }, 'image/png');
}

This cannot be converted into a silent “open this URL and capture it” function. The user chooses the source and can stop sharing at any time.

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

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One request returns PNG, JPEG, WebP or PDF. Before capture it accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.

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

Its 63 options cover full-page capture with lazy images, CSS-selector elements, dark mode, 12 device presets or a custom viewport, retina scale, PDF paper and page settings, HTML/CSS to image, custom JavaScript and CSS, pre-capture clicks, hidden selectors, selector/delay/network-idle waits, ad and tracker blocking, custom headers/cookies/user agent/Authorization, timezone and geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, asynchronous jobs with signed webhooks, 100-URL bulk calls, a usage API and an OpenAPI specification. Common parameter names used by other screenshot APIs also work, which eases migration.

An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients. Every feature is available on every plan: 1,000 shots per month free without a card; Starter $5 for 3,000; Growth $15 for 15,000; Pro $39 for 60,000; Scale $99 for 250,000; and Business $249 for 1,000,000. Yearly billing gives two months free.

Create a free ScreenshotNeo account to use the 1,000 monthly shots without a card.

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.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting checklist

The screenshot is blank or only partly loaded

  • Wait for a meaningful selector instead of assuming navigation completion means rendering is finished.
  • Scroll to trigger lazy loading, then capture.
  • Increase the navigation timeout only after checking for a genuinely slow dependency.
  • Disable animations with page CSS or wait for a known transition to finish.

Images or fonts are missing

  • Confirm the URL is reachable from the capture environment and does not require an unprovided login.
  • For html2canvas, fix same-origin or CORS headers; it cannot read a tainted canvas.
  • Use a consistent browser image and font environment for repeatable output.

Playwright or Puppeteer will not launch

  • Run the framework’s browser installation command and check that the process has permission to execute it.
  • In containers, provide the required sandbox configuration according to your deployment’s security policy rather than disabling protections blindly.
  • Close every browser in error paths so orphaned processes do not exhaust memory.

The page blocks automation or requires a challenge

Automation does not defeat authentication, access controls or a site’s restrictions. Capture only pages you are authorized to access. Use a permitted authenticated context, or stop and handle the challenge manually. A service may classify a bot check or failed load as unsuccessful rather than returning a usable image.

Full-page output is too large

Capture a specific element or viewport, reduce the device scale factor, choose JPEG/WebP where appropriate, or split a long document into deliberate sections. For PDFs, set paper size, margins, orientation and page ranges instead of producing one enormous image.

Performance, reliability and cost decisions

  • Reuse browser processes: launching Chromium for every URL is expensive; keep one browser and create isolated pages or contexts for a batch.
  • Limit concurrency: too many pages consume CPU, RAM and network bandwidth and can trigger target-site rate limits.
  • Cache intentionally: cache only when a previous render is acceptable; dynamic pages need a freshness policy.
  • Record diagnostics: save the URL, viewport, browser version, readiness condition and error text with each job.
  • Protect credentials: keep cookies, Authorization headers and API keys out of source control and logs.
  • Prefer asynchronous jobs for volume: a queue with retries and a bounded timeout is safer than one long-running request per user action.

Which approach should you use?

  1. Choose Playwright or Puppeteer when a server-side process must open arbitrary URLs and save browser-rendered pixels.
  2. Choose html2canvas when your own page needs a convenient export of selected, same-origin DOM content and visual approximation is acceptable.
  3. Choose Screen Capture API when the user must explicitly select a screen, window or tab.
  4. Choose ScreenshotNeo when you want a hosted capture endpoint, cleanup of consent banners and popups, explicit billing verdicts, PDF and advanced controls, or MCP access for AI agents.

Frequently Asked Questions

Can JavaScript in a normal web page capture another website without permission?

No. Browser origin rules prevent arbitrary cross-origin inspection, and the Screen Capture API requires the user to choose a source.

Does Playwright require ActiveX or Internet Explorer?

No. It launches supported Chromium, Firefox or WebKit browsers through a Node.js package.

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

Is html2canvas pixel-perfect?

No. It reconstructs an image from DOM information and supports only the CSS it implements.

What should I do with a page that never reaches network idle?

Use a page-specific selector, event or bounded delay that indicates the content you need is ready.

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.