ScreenshotNeo

BlogComparisons

Screenshot API vs Puppeteer for Generating Portfolio Website Thumbnails

Compare Puppeteer and hosted screenshot APIs for portfolio thumbnails, with runnable code, a practical selection guide, and options for producing resized previews.

By the ScreenshotNeo team4 October 202610 min read

Short answer: Use Puppeteer when your JavaScript application needs to control browser navigation, page state, or element capture and you can run and maintain the browser environment. Use a hosted screenshot API when its capture and image-sizing options meet your thumbnail requirements and you prefer to make a service request instead of operating the browser workflow. There is no evidence here that either approach is generally cheaper, faster, or more reliable.

For a portfolio grid, first define the card image dimensions, viewport, page readiness condition, and whether each preview represents a whole page or a particular element. Then choose the approach whose controls and operating model fit those requirements. This guide shows both implementations and the checks that make their results more repeatable.

1. How the two approaches differ

Question Hosted screenshot API Puppeteer
Who runs the browser capture? A screenshot provider receives a request and returns an image. Your application launches and controls a browser through Puppeteer.
How much browser control do you have? You use the options exposed by the service. Your JavaScript workflow controls navigation and can capture a page or a selected element.
How do you size the thumbnail? ScreenshotOne documents image_width and image_height options that resize an image while preserving its aspect ratio. Puppeteer offers screenshot controls including format, quality, clipping, and full-page capture. The reviewed documentation does not establish an equivalent one-option thumbnail resizing comparison.
What do you operate? Your application integrates with and depends on the remote API and its behavior. Your team operates the browser execution environment and maintains the automation integration.

These are differences in control and integration, not measured service comparisons. The available documentation does not establish a general winner for price, speed, throughput, or reliability.

2. Generate thumbnails with Puppeteer

Puppeteer is a JavaScript library for browser automation. The full puppeteer package downloads a compatible Chrome during installation. puppeteer-core is available without that browser download; use it when you supply and manage a compatible browser yourself. Check the current Puppeteer setup documentation for installation details, since package manager install-script settings can affect browser downloads.

Install

npm install puppeteer

Capture a page screenshot

This runnable Node.js example visits a portfolio site, waits for network activity to become quiet according to Puppeteer’s networkidle2 condition, and saves a PNG. Replace the URL and output path with your own values.

// save as capture.mjs
import puppeteer from 'puppeteer';

const url = 'https://example.com/';
const browser = await puppeteer.launch({ headless: true });

try {
  const page = await browser.newPage({
    viewport: { width: 1440, height: 1000 },
    deviceScaleFactor: 1,
  });
  await page.goto(url, { waitUntil: 'networkidle2', timeout: 60_000 });
  await page.screenshot({ path: 'portfolio.png', type: 'png', fullPage: false });
} finally {
  await browser.close();
}

Run it with node capture.mjs. The Puppeteer screenshot guide documents page and element capture. Its Page.screenshot() API supports options such as full-page capture, clipping, output path, format, and quality.

Capture a selected portfolio element

Use an element screenshot when the portfolio page has a card, hero, or project preview whose bounds should define the thumbnail. The selector must exist after navigation; wait for it before locating the element.

// Replace the preceding page.goto() call's URL as needed.
await page.goto('https://example.com/projects/sample', {
  waitUntil: 'networkidle2',
  timeout: 60_000,
});

const selector = '.project-preview';
await page.waitForSelector(selector, { timeout: 15_000 });
const preview = await page.$(selector);
if (!preview) throw new Error(`Element not found: ${selector}`);
await preview.screenshot({ path: 'project-preview.png', type: 'png' });

Place this code inside the try block in the first example, after creating page. Element capture records that element rather than the whole page. If the selector is missing or matches the wrong region, fix the selector or page state before capture.

Choose dimensions and format deliberately

  • Viewport: Set the viewport to the layout you want represented. A responsive portfolio can produce substantially different compositions at desktop and mobile widths.
  • Full page: Use fullPage: true when the thumbnail should include the entire document. For a portfolio card, a viewport capture or element capture is often a more useful preview shape; decide based on the destination.
  • Format: Puppeteer supports PNG, JPEG, and WebP where supported by the installed browser. JPEG and WebP can be useful when the destination needs smaller image files; choose based on your storage and delivery requirements.
  • Quality: The quality option applies to lossy formats such as JPEG. Set it to a value appropriate for your visual requirements rather than assuming a universal best setting.
  • Clipping: A clip rectangle can capture a defined region of the page when a selector-based element screenshot is not suitable.
  • Device scale: A larger device scale factor can capture more pixels for a given CSS viewport, increasing output dimensions. Confirm the resulting file is appropriate for your card size.

Consult the current screenshot API options for exact option names and behavior in your Puppeteer version.

3. Generate a thumbnail with a hosted screenshot API

A hosted API moves browser capture behind an HTTP request. For example, ScreenshotOne documents an HTTPS GET request to its /take endpoint, requires an access key, returns a screenshot image, and provides image_width and image_height options for resizing while preserving aspect ratio. Keep the access key secret and send it over HTTPS.

cURL

curl -G 'https://api.screenshotone.com/take' \
  --data-urlencode 'access_key=YOUR_ACCESS_KEY' \
  --data-urlencode 'url=https://example.com/' \
  --data-urlencode 'image_width=640' \
  --data-urlencode 'image_height=400' \
  -o portfolio.webp

Check the provider’s current documentation for supported output-format parameters and response behavior. The dimensions above are example target bounds, not a prescribed portfolio-card size.

Python

import requests

response = requests.get(
    'https://api.screenshotone.com/take',
    params={
        'access_key': 'YOUR_ACCESS_KEY',
        'url': 'https://example.com/',
        'image_width': 640,
        'image_height': 400,
    },
    timeout=90,
)
response.raise_for_status()
with open('portfolio.webp', 'wb') as image_file:
    image_file.write(response.content)

Node.js

const query = new URLSearchParams({
  access_key: process.env.SCREENSHOTONE_ACCESS_KEY,
  url: 'https://example.com/',
  image_width: '640',
  image_height: '400',
});

const response = await fetch(`https://api.screenshotone.com/take?${query}`, {
  signal: AbortSignal.timeout(90_000),
});
if (!response.ok) {
  throw new Error(`Screenshot request failed: ${response.status} ${response.statusText}`);
}
const image = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(({ writeFile }) => writeFile('portfolio.webp', image));

Use environment variables or a secrets manager for API credentials. Do not commit keys into source control or expose them in client-side code.

4. Choose the right workflow

  1. Set the destination bounds. Record the portfolio card’s width and height, whether it crops, and the image formats your site accepts.
  2. Choose the representation. Decide between a viewport, a full-page image, or a specific element. Define a viewport width and height for consistent responsive layout.
  3. Define readiness. Decide which state means the page is ready for capture: navigation completion, a particular selector, or an application-specific signal. Network-idle conditions alone may be unsuitable for sites that keep requests open.
  4. Choose by control and operations. Prefer Puppeteer when your workflow needs browser automation or page access. Prefer a hosted API when the provider’s options cover your needs and you want a remote capture request instead of running the browser workflow.
  5. Check representative sites. Review results for the actual portfolio URLs you expect to capture. Decide what the application should do for navigation failures, blocked pages, consent screens, missing selectors, and layout changes. These are checks to perform, not claims that either method handles them automatically.
  6. Compare costs from real terms. Estimate expected capture volume and compare current provider pricing with the cost of operating your own browser environment. The available research does not establish a general cost winner.

5. Or skip the browser setup

ScreenshotNeo is a hosted website screenshot API and MCP server. One GET request returns a screenshot in PNG, JPEG, or WebP, or a PDF. Use the [ScreenshotNeo API documentation](https://screenshotneo.com/docs/) for the endpoint and options.

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

Equivalent Python and Node.js calls:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
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}`);
  • Cookie banners are accepted and removed before the screenshot; more than 60 known consent platforms, newsletter popups, and chat widgets can be removed, and each step can be turned off.
  • Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and whether the request was billed.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents and MCP clients.
  • The Free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots.

ScreenshotNeo also supports full-page capture with lazy images loaded, element capture by CSS selector, dark mode, device presets and custom viewports, retina scale, PDF settings, HTML/CSS input, custom CSS and JavaScript, clicks, selector hiding and waiting, delays and network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, image resizing, configurable cache TTL, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work to make switching easier. Every feature is on every plan.

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

6. Reliability, performance, and cost considerations

Reliability

Both approaches depend on the target site being reachable and rendering the intended page state. With Puppeteer, your application also needs a working browser installation and execution environment. With a hosted API, your integration depends on the provider’s endpoint and service behavior. The reviewed sources provide no uptime or failure-rate comparison. Treat navigation failures, timeouts, blocked pages, consent prompts, and changing layouts as explicit outcomes in your thumbnail workflow.

Performance

No controlled speed or throughput comparison is available here. Measure end-to-end completion time with representative sites and your deployment setup if those figures matter to your application. For either approach, avoid capturing more page area or image resolution than the destination needs; define a stable capture boundary and resize appropriately.

Cost

Do not infer a cost winner from the implementation style alone. A hosted service has provider terms to check; Puppeteer requires operating the browser environment and maintaining the integration. Estimate the expected number of portfolio URLs and refresh frequency, then compare current provider pricing with the resources and maintenance involved in your own deployment.

7. Troubleshooting

Symptom Likely cause What to do
Puppeteer cannot launch Chrome The compatible browser was not downloaded, is unavailable, or the runtime cannot launch it. Review Puppeteer installation guidance and package-manager install-script behavior. If using puppeteer-core, provide a compatible browser as part of your environment.
Navigation times out The target page did not reach the selected navigation condition within the timeout, or it keeps network connections active. Choose a readiness condition appropriate to the site, wait for a known selector or application signal, and handle timeout as a failed capture rather than saving a misleading preview.
Element screenshot fails or is empty The selector does not exist yet, matches the wrong node, or the element is not visible. Wait for the selector, verify it against the actual page, and confirm the element is rendered before taking its screenshot.
Thumbnail looks different across sites Sites use different responsive breakpoints, fonts, loading behavior, or layouts. Use a defined viewport and readiness condition; decide whether each site needs an element capture or a full-page capture. Inspect representative results.
Hosted API responds with an error The request may have an invalid key, unsupported option, unreachable target, or provider-side failure. Check the provider’s current API documentation, validate the URL and parameter names, keep credentials secret, and handle unsuccessful HTTP responses explicitly.
Output dimensions do not match the card exactly Aspect-ratio-preserving resizing or the chosen capture bounds do not match the destination geometry. Choose capture bounds with the intended aspect ratio, then apply a deliberate crop or fit strategy in your image pipeline. Do not assume resizing alone will crop to arbitrary dimensions.

8. Frequently asked questions

Can Puppeteer capture just one project card?

Yes. Locate the card with a CSS selector after it appears and use the element’s screenshot method. The selector must identify the intended rendered element.

Does a hosted API always produce the same thumbnail?

No such guarantee follows from the documented options. Target websites can change their content and layout, so define a capture state and review results for the sites you use.

Should I use Playwright instead?

Playwright is another browser automation option with documented viewport, element, and full-page screenshots. It is browser automation, not a hosted screenshot API. The title comparison here is specifically about Puppeteer and a hosted API.

Which option should I use for a small portfolio?

Choose based on whether browser-level control or managed capture better fits your implementation and operations. For either choice, first verify the output against your actual card layout and target pages.

Sources