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.

To capture an HTTPS website with JavaScript, navigate to its URL in a server-side headless browser, wait for the page’s meaningful content to render, then save a screenshot. Puppeteer and Playwright both support this workflow. For a hosted alternative, ScreenshotNeo takes a screenshot with one GET request.

How a JavaScript screenshot API captures an HTTPS page

A screenshot API usually runs a headless browser on a server. Your JavaScript code supplies the HTTPS URL and capture settings; the browser loads the page, executes its scripts, and renders the result before the API captures the pixels.

The scheme matters: validate that the submitted address uses HTTPS when that is your requirement. But HTTPS alone does not determine when a page is ready. A site may return its initial HTML while a JavaScript application is still fetching data, rendering components, or loading images. A capture made too soon can show placeholders or incomplete content.

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

Choose Puppeteer or Playwright

Both libraries can open an HTTPS URL and save a screenshot. Puppeteer provides a direct Chrome/Chromium automation path and a concise Page.screenshot() API. Playwright offers one API for Chromium, Firefox, and WebKit, and documents additional capture controls including full-page and element screenshots, clipping, masking, and animation handling. See the Puppeteer screenshot API and Playwright screenshot documentation.

Consideration Puppeteer Playwright
Browser approach Direct Chrome/Chromium automation. One API for Chromium, Firefox, and WebKit.
Basic capture page.screenshot() captures the page and can return image bytes or base64. Navigate with page.goto(), then call page.screenshot().
Documented capture controls Page screenshot API. Full-page and element capture, clipping, masking, animation handling, and output formats.
Readiness example The official guide demonstrates a networkidle2 navigation wait. Choose a navigation or application-specific readiness signal suitable for the page.

Choose based on the browser engines and capture controls you need, as well as the runtime you can operate. Neither library can guarantee that every third-party site finishes loading or exposes a universal signal that its content is complete.

Build a basic screenshot endpoint with Playwright

This Node.js example accepts a URL, insists on HTTPS, navigates in an isolated browser context, waits for the document load event, and returns a PNG. It sets a navigation timeout and closes the browser resources even if navigation or capture fails.

  1. Install Playwright: run npm install playwright, then install the Chromium browser with npx playwright install chromium.
  2. Save this as server.mjs:
import { chromium } from 'playwright';
import { createServer } from 'node:http';

const server = createServer(async (req, res) => {
  const requestUrl = new URL(req.url, 'http://localhost');
  const target = requestUrl.searchParams.get('url');

  if (!target) {
    res.writeHead(400, { 'content-type': 'text/plain' });
    res.end('Supply a url query parameter.');
    return;
  }

  let parsed;
  try {
    parsed = new URL(target);
  } catch {
    res.writeHead(400, { 'content-type': 'text/plain' });
    res.end('Invalid URL.');
    return;
  }

  if (parsed.protocol !== 'https:') {
    res.writeHead(400, { 'content-type': 'text/plain' });
    res.end('Only HTTPS URLs are accepted.');
    return;
  }

  let browser;
  try {
    browser = await chromium.launch({ headless: true });
    const context = await browser.newContext({
      viewport: { width: 1440, height: 900 },
      deviceScaleFactor: 1
    });
    const page = await context.newPage();
    page.setDefaultNavigationTimeout(30000);
    await page.goto(parsed.href, { waitUntil: 'load' });
    const png = await page.screenshot({ fullPage: true, type: 'png' });

    res.writeHead(200, {
      'content-type': 'image/png',
      'content-length': png.length,
      'cache-control': 'no-store'
    });
    res.end(png);
    await context.close();
  } catch (error) {
    res.writeHead(502, { 'content-type': 'text/plain' });
    res.end(`Capture failed: ${error.message}`);
  } finally {
    if (browser) await browser.close();
  }
});

server.listen(3000, () => {
  console.log('Screenshot endpoint listening on http://localhost:3000');
});
  1. Run it: node server.mjs
  2. Request a capture: open http://localhost:3000/?url=https%3A%2F%2Fexample.com. The endpoint returns a PNG if navigation and capture succeed.

This is a starter example, not a public service ready to accept arbitrary URLs. It has no authentication, destination allowlist, rate limit, or resource-size cap. Add those protections before exposing it beyond a trusted environment.

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

Wait for the application, not just the first document load

waitUntil: 'load' waits for the page’s load event, but it does not prove that a client-rendered app has finished fetching or displaying the content you want. If the site exposes a stable element, wait for it explicitly:

await page.goto(parsed.href, { waitUntil: 'domcontentloaded' });
await page.locator('[data-capture-ready="true"]').waitFor({
  state: 'visible',
  timeout: 15000
});

Replace the selector with one that the target application actually renders when its relevant content is ready. If you control the application, an explicit completion signal is more reliable than guessing from elapsed time. When no selector or application signal is available, use an appropriate load-state wait and a bounded timeout. The Puppeteer guide demonstrates networkidle2, but that is one policy, not a universal guarantee: analytics, streaming, ads, or long polling can keep network activity going. See the Puppeteer network guide.

Set the capture area, format, and rendering behavior

Decide what the image is for before choosing the capture settings. A responsive-layout check needs a deliberate viewport; an archive or review may need the whole page; a thumbnail may need only one component.

  • Viewport and device scale: set the viewport to control responsive layout, and use device scale when you need higher pixel density. A desktop viewport can produce a different page composition than a phone-sized one.
  • Viewport or full page: a viewport screenshot captures the visible area. A full-page screenshot includes the scrollable document; Playwright documents this with fullPage: true. Very long pages can create large output files or exceed browser and service limits.
  • Element or clipped region: capture a chart, card, or component when a full-page image is unnecessary. Playwright documents locator-based element screenshots and clipped screenshots; confirm that the target has rendered and is visible before capture.
  • Format: PNG is lossless and suits text and interface details; JPEG can reduce file size for photographic content; WebP is an option where the recipient supports it. Playwright documents PNG, JPEG, and WebP screenshot formats.
  • Animation and variable regions: disable or stabilize animations when repeatability matters. Playwright supports animation handling and masking, which can help with transient or sensitive regions.

For example, in Playwright, a viewport PNG is await page.screenshot({ type: 'png' }); a full-page JPEG is await page.screenshot({ path: 'page.jpg', type: 'jpeg', fullPage: true }). Check the receiving system’s supported formats before selecting WebP or a higher device scale.

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.

Use Puppeteer for the same HTTPS workflow

Puppeteer’s Page.screenshot() captures the page and can return bytes or base64. The following minimal script saves the image bytes to a PNG file:

import puppeteer from 'puppeteer';

const target = new URL(process.argv[2] ?? 'https://example.com');
if (target.protocol !== 'https:') {
  throw new Error('Only HTTPS URLs are accepted.');
}

const browser = await puppeteer.launch({ headless: true });
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 900 });
  page.setDefaultNavigationTimeout(30000);
  await page.goto(target.href, { waitUntil: 'networkidle2' });
  const image = await page.screenshot({ path: 'screenshot.png', fullPage: true });
  console.log(`Saved ${image.length} bytes to screenshot.png`);
} finally {
  await browser.close();
}

Install Puppeteer with npm install puppeteer, save the script as capture.mjs, and run node capture.mjs https://example.com. The use of networkidle2 follows a documented example; for pages that keep network requests open, prefer a stable selector or a signal defined by the application.

Or skip the browser setup

ScreenshotNeo is a hosted screenshot API and MCP server for developers. It accepts a URL and returns a PNG, JPEG, WebP, or PDF. A single GET request is enough for a basic capture. The request below saves a WebP screenshot of https://stripe.com; replace that URL with your target. Get setup details in the ScreenshotNeo documentation.

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

ScreenshotNeo accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status with X-Page-Verdict and X-Billed headers. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

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

The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots; yearly billing gives two months free, and every feature is on every plan. See ScreenshotNeo for the service and sign up free.

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

Secure and operate a screenshot service safely

A public screenshot endpoint turns URLs into browser navigation requests. Treat each submitted address as untrusted input: a URL can target internal services as well as public websites. Checking only for an https: prefix is not sufficient to make arbitrary destinations safe.

  • Allow only the destinations your product needs, or reject private, loopback, and link-local network destinations after resolving hostnames. Re-check redirects so an allowed public URL cannot redirect the browser to an internal address.
  • Run browser processes with restricted permissions and network access. Use an isolated browser context per request so cookies and page state do not leak between captures.
  • Set navigation and overall request timeouts, limit concurrent jobs, and cap response and image sizes. Close pages, contexts, and browsers on both success and failure.
  • Avoid logging credentials, authorization headers, cookies, or full URLs if they may contain secrets. Restrict access to captures; screenshots can expose private content visible to the browser.
  • Use a maintained browser and automation-library version, and plan how browser processes will be reused or recycled. Reuse can reduce repeated launch overhead, but isolate page state and apply concurrency limits.

These are engineering safeguards for a service that accepts remote destinations; browser screenshot documentation describes capture capabilities, not a complete security policy. Do not send a browser credentials for a private page unless the service’s access controls, logging, storage, and output handling are designed for that data.

Troubleshoot incomplete or failed captures

Symptom Likely cause What to try
Screenshot shows a loader, skeleton, or empty app shell Capture occurred before client-side rendering or data loading finished. Wait for a stable, visible application selector or an app-defined ready signal; set a bounded timeout.
Navigation times out on a page that appears usable Background requests, analytics, streaming, or long polling prevent the chosen network-idle condition. Use a selector or app-specific signal instead of requiring all network activity to stop.
Screenshot is cut off The capture used the current viewport rather than the full document, or the intended component was outside the selected area. Use a full-page screenshot or target the required element or clip explicitly.
Layout differs from the browser a user sees Viewport dimensions, device scale, browser engine, fonts, or responsive breakpoints differ. Set the viewport and device scale deliberately, and use the browser engine relevant to the output environment.
Page fails to navigate despite valid HTTPS The host may be unreachable from the server, may reject automated browsers, or may have a TLS or redirect problem. Check the destination from the capture host, inspect navigation errors and redirects, and do not disable certificate checks as a default workaround.
Service becomes slow or memory use grows Too many concurrent pages, unbounded full-page captures, or browser resources not closed. Limit concurrency and page dimensions, enforce size and time budgets, and close contexts after each job.
Endpoint can reach internal infrastructure Arbitrary user-supplied destinations are not restricted. Apply destination allowlists and private-address protections, including redirect checks, before accepting public traffic.

Performance, reliability, and cost expectations

There is no single meaningful latency or success-rate figure for JavaScript screenshots: results vary with page complexity, browser version, geography, concurrency, and hosting. A page with large images or a slow client-side app needs more time and resources than a simple static page. Benchmark against the sites and conditions your service actually serves rather than promising a universal capture time.

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

For a self-hosted service, browser startup, memory, concurrency, retries, storage, and maintenance are part of the operating cost. Reusing a browser process may avoid repeated startup work, but requires careful context isolation and resource cleanup. Full-page output can be significantly larger than a viewport capture. For hosted APIs, compare the billing rules, supported formats, capture controls, and treatment of failed or cached results; verify the terms for the plan you intend to use.

Frequently Asked Questions

Can a browser screenshot API capture an HTTPS site that requires login?

Yes, if the browser session is given the required authentication, but protect credentials and resulting screenshots as sensitive data. Do not expose private pages through an unauthenticated capture endpoint.

Does HTTPS mean the page is safe to capture?

No. HTTPS protects the connection but does not establish that an arbitrary destination is safe for a server-side browser to visit. Restrict destinations and redirects to prevent access to internal services.

Which image format should I return from an API?

Use PNG for lossless interface details, JPEG for photographic content where smaller files matter, and WebP when the consumer supports it.

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

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.