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

Build the destination as a URL, encode it as the screenshot service’s url parameter, then treat the response as image bytes. In Playwright, the equivalent is different: navigate with page.goto(url) and capture the already-open page with page.screenshot(). Keeping those two steps separate prevents broken query strings, leaked credentials and screenshots of the wrong page.

First choose the screenshot model

“JavaScript screenshot API” can mean either a hosted HTTP service or a browser you operate with Playwright. The URL is supplied in a different place in each model.

Model Where the URL goes Where rendering runs Typical result
Hosted screenshot API The request’s url parameter The provider’s browser infrastructure Image bytes in the HTTP response
Playwright page.goto(url) Your application’s browser process A file written by page.screenshot()

The rest of this guide shows both approaches. Use a hosted endpoint when you want to send a URL over HTTP without maintaining Chromium. Use Playwright when your application needs direct control over the browser, navigation and capture behavior.

Hosted API: construct and encode the URL

Keep the page address as a URL value rather than concatenating raw text into a query string. URL resolves relative paths correctly, and URLSearchParams percent-encodes ampersands, question marks and other reserved characters inside the destination.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Screen recorder software for PC – record videos and take screenshots from your computer screen – compatible with Windows 11, 10, 8, 7
  • Record videos and take screenshots of your computer screen including sound
  • Highlight the movement of your mouse
  • Record your webcam and insert it into your screen video
  • Edit your recording easily
  • Perfect for video tutorials, gaming videos, online classes and more

JavaScript with fetch

const target = new URL('/article?id=42&ref=home', 'https://example.com');
const endpoint = new URL('https://screenshot-api.net/v1/screenshot');
endpoint.searchParams.set('url', target.href);

const response = await fetch(endpoint, {
  headers: { Authorization: `Bearer ${process.env.SCREENSHOT_API_KEY}` }
});

if (!response.ok) {
  throw new Error(`Screenshot request failed: ${response.status}`);
}

const image = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('screenshot.png', image));

The destination becomes https://example.com/article?id=42&ref=home, while the outer request safely encodes that entire value. The documented hosted response is the rendered image itself, not JSON containing an image URL. Save the response body as binary data and use the returned content type (PNG, JPEG or another format selected by the service) when serving it.

Do not expose production keys

Make authenticated calls from trusted server-side code. A bearer header keeps the key out of the destination URL. Some screenshot services also accept a ?key= query parameter for direct image use, but query-string credentials can appear in page source, browser history, proxy logs and server logs. Reserve that form for cases where its exposure is acceptable, never for a production secret embedded in public client-side JavaScript.

When the input is user supplied

  • Parse with new URL(input) and reject malformed values before making the request.
  • Apply an allowlist of schemes, normally https: and, only when required, http:.
  • Do not let untrusted users choose internal network addresses if your server can reach private infrastructure.
  • Preserve fragments only when the target application uses them client-side; fragments are not sent in ordinary HTTP requests and may not affect server rendering.

Playwright: navigate first, capture second

With Playwright, the screenshot method does not receive the destination URL. The browser must already be on the page.

import { chromium } from 'playwright';

const target = new URL('/article?id=42&ref=home', 'https://example.com');
const browser = await chromium.launch();
const page = await browser.newPage();

try {
  await page.goto(target.href, { waitUntil: 'networkidle' });
  await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
  await browser.close();
}

page.goto() performs navigation; page.screenshot() captures the rendered page. fullPage: true extends the capture to the full scrollable document. For a viewport-only image, omit it. For a selected region, pass a clip rectangle.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
ResumeMaker Professional Deluxe 20 - Software to Create Professional Resumes Includes Sample Resumes Written by Certified Resume Writers, Career Advice, Job Searches & Interview Questions - CD - PC
  • Works on Windows 11, 10, & 8
  • Build a Professional Resume Fast with the step-by-step guide to help you create a professional resume that showcases your unique experience and skills
  • ResumeMaker & Resume Maker are registered trademarks & box images and screenshots are copyrights of Individual Software Inc.
  • Modern Resume Styles - Choose from 60 styles and customize any style with choice of header, colors, graphics and a photograph plus Powerful Ways to Search for Jobs
  • Video Resumes & Expert Advice - View Sample Video Resumes and video resume scripts you can customize plus Email & Share Your Resume on LinkedIn, Facebook & Twitter

Capture a specific area

await page.screenshot({
  path: 'chart.png',
  clip: { x: 80, y: 160, width: 900, height: 500 }
});

Use clipping when the page is long but only one coordinate region matters. If the element’s position changes responsively, locate it first and derive its bounding box rather than hard-coding coordinates.

Make dynamic pages repeatable

Wait for a meaningful readiness condition instead of assuming that navigation means every widget has finished rendering.

await page.goto(target.href, { waitUntil: 'domcontentloaded' });
await page.waitForSelector('[data-chart-ready]');
await page.screenshot({ path: 'stable.png', fullPage: true });

You can also hide animated or volatile elements with stylesheet controls, disable transitions with injected CSS, or wait for a known delay when no reliable selector exists. Screenshot assertions in the Playwright test runner are separate from ordinary capture calls; they wait for consecutive captures to stabilize before comparing an expectation.

Complete JavaScript request patterns

Building URLs from route data

function articleUrl(origin, id, ref) {
  const url = new URL('/article', origin);
  url.searchParams.set('id', String(id));
  if (ref) url.searchParams.set('ref', ref);
  return url;
}

const target = articleUrl('https://example.com', 42, 'home');
const endpoint = new URL('https://screenshot-api.net/v1/screenshot');
endpoint.searchParams.set('url', target.href);
const response = await fetch(endpoint, {
  headers: { Authorization: `Bearer ${process.env.SCREENSHOT_API_KEY}` }
});

Using searchParams.set() avoids hand-written escaping and correctly handles values containing spaces, ampersands or Unicode characters.

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.
Rank #3
Typing Instructor Bundle - Includes Two Software Programs for Kids & Adults to Learn to Touch Type - CD/PC
  • Works on Windows 11, 10 & 8
  • Kids ages 6 to 12 and older kids to adults learn to type on exciting adventures outside the classroom
  • Both typing programs provide rewards every step of the way and learn in English or spanish
  • Teaches keyboard basics following an age appropriate typing plan
  • Typing Instructor is a registered trademark & box images and screenshots are copyrights of Individual Software Inc.

Check content before writing a file

const contentType = response.headers.get('content-type') || '';
if (!contentType.startsWith('image/')) {
  const message = await response.text();
  throw new Error(`Expected an image, received ${contentType}: ${message}`);
}
const bytes = new Uint8Array(await response.arrayBuffer());

This check catches authentication pages, validation errors and JSON error responses that would otherwise be saved with an image filename.

Equivalent cURL, Python and Node.js calls

The following hosted-service examples use ScreenshotNeo’s endpoint. See the ScreenshotNeo documentation for the current parameter reference.

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)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

Or skip the browser setup

ScreenshotNeo is a hosted screenshot API and MCP server. Its URL is passed as a parameter, so your JavaScript only needs to build the target and make one request:

const target = new URL('/article?id=42', 'https://example.com');
const q = new URLSearchParams({
  access_key: process.env.SCREENSHOTNEO_KEY,
  url: target.href
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const bytes = Buffer.from(await res.arrayBuffer());

ScreenshotNeo accepts the cookie or consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides 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 shots.

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

Create a free ScreenshotNeo account to get the 1,000 monthly screenshots without entering a card.

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

Troubleshooting dynamic URL captures

The target has its own query string

Symptom: parameters after the first ampersand disappear or are interpreted as parameters of the screenshot endpoint. Fix: construct the destination with URL and set it through URLSearchParams (or use cURL’s --data-urlencode). Never paste an unescaped destination into the outer query string.

The saved file is JSON or HTML

Symptom: an image filename opens as an error document. Cause: an HTTP error, authentication failure or redirect response was saved without checking it. Fix: test response.ok, inspect content-type, and log the status and response text before writing bytes.

Playwright captures a loading shell

Cause: the application renders content after navigation. Fix: wait for a stable selector, a known application event or a carefully chosen delay. Use networkidle only when the page’s background requests eventually settle.

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.

Images or fonts are missing

Cause: blocked resources, cross-origin restrictions, lazy loading or a capture taken too early. Fix: wait for the relevant elements, verify resource responses in the browser, and scroll or otherwise trigger lazy content before capturing. A hosted service with full-page lazy-image loading can remove some of this browser setup.

The API key appears in client code

Cause: the request is made directly from browser JavaScript with a query-string key. Fix: proxy the call through your server and send credentials in a protected environment. Treat any key already shipped to users as exposed and rotate it.

Reliability, performance and cost decisions

  • URL generation: deterministic URL construction makes retries safe and prevents accidental captures of a default route.
  • Timeouts: set a client timeout long enough for slow pages, then record the target and HTTP status when it expires.
  • Binary handling: stream or buffer image bytes; do not parse a successful image response with response.json().
  • Repeatability: freeze animations, wait for readiness selectors and use consistent viewport settings when comparing captures.
  • Browser ownership: Playwright gives maximum control but requires browser processes, updates and resource management. A hosted API moves that operational work to the provider.
  • Billing awareness: ScreenshotNeo reports page verdict and billing status in response headers, and cache hits and failed captures are not billed under its stated rules.

FAQ

Should the URL be placed in the screenshot method?

No. In a hosted API it is the request’s url parameter. In Playwright, call page.goto(url) first; the screenshot method captures the current page.

Can I pass a relative URL?

Resolve it against a known origin with new URL(relative, origin) before sending it. A screenshot service needs an absolute destination that its renderer can request.

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

What does a hosted screenshot response contain?

The documented response is the rendered image bytes with a matching image content type, not a JSON object containing a separate image link.

Frequently Asked Questions

Is URL encoding still needed when using JavaScript’s URL object?

Yes. Set the complete destination through URLSearchParams on the outer endpoint; this encodes the destination’s own query characters safely.

When is Playwright preferable to a hosted API?

Choose Playwright when you need application-controlled browser state, custom navigation logic or local test assertions. Choose a hosted API when you prefer an HTTP call without operating the browser.

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.