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.

There are three practical ways to create an image from a Next.js application: call a hosted screenshot API from a server route, run Playwright or Puppeteer yourself, or use Next.js ImageResponse when you really need a data-driven social card rather than a capture of a live page. This guide shows runnable server-side examples, deployment decisions, output options, failure fixes, and a hosted shortcut with ScreenshotNeo.

Choose the right kind of screenshot

“Screenshot API” is ambiguous. A hosted API accepts a URL and returns an image or PDF. A browser automation library gives your code a page.screenshot() method and leaves browser installation, navigation, and operations to you. Next.js also has a native Open Graph image route that renders a designed card from application data without loading a page.

Need Best starting point Why
Capture an existing URL, including its real CSS and JavaScript Hosted API or Playwright/Puppeteer Both drive a browser against the rendered page.
Control the browser, cookies, headers, selectors, and code path Playwright or Puppeteer You operate the automation directly.
Generate a consistent social card from title, author, and image data Next.js ImageResponse No browser capture is required.
Run captures in a serverless production route Hosted API, or a host-compatible browser package Browser binaries and function limits are common deployment constraints.

Keep credentials and browser work on the server. Never expose a screenshot-provider key in a client component or ship it in browser JavaScript.

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

Option 1: capture a URL with Playwright

Install Playwright in the project and make sure the browser required by your installed version is available in the deployment environment. The examples below use an App Router route handler at app/api/screenshot/route.js.

#1 Best Overall
Sale
Philips 24 Inch Computer Monitor FHD 100Hz VA VESA Flicker-Free, 241V8LB
  • CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
  • INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
  • THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
  • WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
  • A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
npm install playwright
npx playwright install chromium

Viewport screenshot returned by a route

import { chromium } from 'playwright';

export async function GET(request) {
  const target = new URL(request.url).searchParams.get('url');
  if (!target) {
    return new Response('Missing url', { status: 400 });
  }

  let parsed;
  try {
    parsed = new URL(target);
    if (!['http:', 'https:'].includes(parsed.protocol)) throw new Error('scheme');
  } catch {
    return new Response('url must be an absolute HTTP(S) URL', { status: 400 });
  }

  const browser = await chromium.launch({ headless: true });
  try {
    const page = await browser.newPage({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1 });
    await page.goto(parsed.href, { waitUntil: 'networkidle', timeout: 30_000 });
    const image = await page.screenshot({ type: 'png' });
    return new Response(image, {
      headers: { 'Content-Type': 'image/png', 'Cache-Control': 'public, max-age=300' }
    });
  } finally {
    await browser.close();
  }
}

Call it with /api/screenshot?url=https%3A%2F%2Fexample.com. The screenshot buffer is returned directly, so the route does not write a temporary file. In a real service, restrict which hosts may be captured; an unrestricted URL parameter can become a server-side request forgery risk.

Full page, buffer, and element captures

// Entire document written to disk
await page.screenshot({ path: 'page.png', fullPage: true });

// Keep the image in memory
const buffer = await page.screenshot();

// Capture one element
const header = await page.locator('.header').screenshot({ path: 'header.png' });

fullPage: true expands beyond the viewport. A locator capture is useful for a card, chart, or component and avoids including the rest of the page. Add an explicit wait for data that appears after navigation:

await page.goto(parsed.href, { waitUntil: 'domcontentloaded' });
await page.locator('[data-ready="true"]').waitFor({ state: 'visible', timeout: 15_000 });
await page.screenshot({ path: 'ready.png', fullPage: true });

For deterministic output, set the viewport and device scale factor, wait for a known application state, and use a fixed locale, timezone, or test data. “Network idle” is not a guarantee that every animation or client-side request has finished.

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

Option 2: capture with Puppeteer

Puppeteer exposes the same basic workflow: launch Chromium, create a page, navigate, capture, and close. A minimal script is:

Rank #2
Philips 22 Inch Computer Monitor FHD 100Hz VA VESA Flicker-Free, 221V8LB
  • CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
  • 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
  • SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
  • INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
  • THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
  await page.goto('https://news.ycombinator.com', { waitUntil: 'networkidle2' });
  await page.screenshot({ path: 'hn.png' });
} finally {
  await browser.close();
}

Puppeteer also supports element capture and options for the capture extent, clipping rectangle, file path, image type, quality, and transparent backgrounds:

await page.screenshot({
  path: 'hero.webp',
  type: 'webp',
  quality: 82,
  fullPage: true,
  omitBackground: true
});

await page.locator('.hero').screenshot({ path: 'hero-element.png' });

Quality applies to JPEG and WebP, not PNG. Use clip when you need a precise rectangle rather than a whole page or element. Return the resulting buffer from a Next.js route when another service, not the filesystem, should receive the image.

Deploying browser automation in Next.js

Local success does not prove that a serverless deployment can launch Chromium. Verify the target runtime, architecture, browser binary availability, cold-start budget, writable temporary storage, and function bundle limit. Vercel’s guide for Puppeteer uses puppeteer-core with @sparticuz/chromium-min because the standard puppeteer package is too large for the 250 MB limit cited in that guide. That limit and package recipe are platform-specific and should be checked against current Vercel documentation before deployment.

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

A typical serverless adaptation looks like this (the exact executable path and Chromium package settings depend on the versions you install):

Rank #3
Sale
Dell 24 Monitor - SE2426H - 23.8-inch FHD (1920x1080) 144Hz 1ms Display, in-Plane Switching (IPS) Technology, AMD FreeSync™, TÜV 3-Star 2X HDMI, Tilt
  • Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
  • Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
  • Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
  • In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
  • Ultra-thin bezels: Maximize your viewing experience with thin bezels.
import puppeteer from 'puppeteer-core';
import chromium from '@sparticuz/chromium-min';

const browser = await puppeteer.launch({
  args: chromium.args,
  executablePath: await chromium.executablePath(),
  headless: true
});

Do not assume this configuration works unchanged on every host. Pin compatible versions, test a production build in the same runtime, and close the browser in a finally block. For high volume, a long-lived worker or hosted service can avoid repeatedly downloading or starting a browser, but that introduces its own scaling and security responsibilities.

Option 3: use Next.js ImageResponse for Open Graph cards

If the requirement is a social preview assembled from known data, a browser screenshot may be unnecessary. Next.js supports an opengraph-image.tsx convention, for example app/blog/[slug]/opengraph-image.tsx, that returns an ImageResponse:

import { ImageResponse } from 'next/og';

export const size = { width: 1200, height: 630 };
export const contentType = 'image/png';

export default async function Image({ params }) {
  const post = await getPost(params.slug);
  return new ImageResponse(
    <div
      style={{
        background: 'white',
        color: 'black',
        display: 'flex',
        flexDirection: 'column',
        width: '100%',
        height: '100%',
        padding: 64
      }}
    >
      <div style={{ fontSize: 56, fontWeight: 700 }}>{post.title}</div>
      <div style={{ fontSize: 30, marginTop: 24 }}>{post.author}</div>
    </div>
  );
}

The documented renderer supports common CSS such as flexbox but only a subset of CSS; advanced layouts such as CSS grid are not supported in the documented example. Choose this route for a designed, data-driven card. Choose a browser capture when the image must reflect an arbitrary URL, its existing stylesheet, client-side state, or a full document.

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

Or skip the browser setup

ScreenshotNeo is a hosted screenshot API and MCP server. One GET request can return PNG, JPEG, WebP, or PDF. It accepts cookie or consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. 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.

Use the API from a server route or job. Keep the key in an environment variable. The complete option set includes full-page and CSS-selector captures, dark mode, 12 device presets plus custom viewports, retina scale, PDF paper size/margins/orientation/page ranges, HTML/CSS-to-image, custom JavaScript and CSS, pre-capture clicks, selector hiding, selector/delay/network-idle waits, ad/tracker/request/resource blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, TTL-based caching, signed public-image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, an OpenAPI specification, and compatibility with parameter names used by other screenshot APIs.

Rank #4
Samsung 27" Essential S3 (S36GD) Series FHD 1800R Curved Computer Monitor
  • CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
  • SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
  • MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
  • KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
  • INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient

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}`);
const data = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', data));

See the ScreenshotNeo documentation for request parameters and response details. It also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

Plan Included shots Price
Free 1,000/month $0, no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Yearly billing gives two months free, and every feature is available on every plan. You can sign up free for 1,000 screenshots a month 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

Make captures repeatable and safe

  • Validate targets: allow only HTTP(S), and use an allow-list when users supply URLs.
  • Control state: provide authentication through server-side cookies or headers, never client-exposed secrets.
  • Wait for meaning, not hope: wait for a selector or application-ready signal instead of an arbitrary short delay.
  • Stabilize visuals: set viewport, scale, timezone, locale, fonts, and reduced-motion behavior where possible.
  • Limit work: cap navigation time, page size, full-page height, and concurrent browsers.
  • Cache deliberately: cache only when the URL and underlying data can safely be reused; invalidate when content changes.
  • Observe outcomes: record status, target, duration, output type, and provider verdict or billed status without logging secrets.

Troubleshooting

The route works locally but fails after deployment

The browser executable may be missing, incompatible with the runtime architecture, or excluded by a function-size limit. Use a host-compatible Chromium package, verify the runtime setting, and test the production bundle rather than only development mode.

The image is blank or only partly rendered

Navigation may have finished before client data or fonts arrived. Wait for a specific selector, use a suitable navigation condition, and increase the timeout only after identifying the slow dependency. Check that the target is reachable from the deployment region.

Best Value
Sale
Sceptre New 22-Inch Gaming Monitor, FHD 1080p, Up to 144Hz, HDMI, DisplayPort, Built-in Speakers, Machine Black (E225W-FW144 Series, 2026)
  • 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
  • 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
  • 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.

Full-page capture omits lazy images

Lazy content may load only after scrolling or an application event. Scroll in the page, wait for image completion or a ready marker, then capture; a hosted service with lazy-image loading can be simpler for public pages.

Fonts, animations, or layout differ between runs

Install and load the intended fonts, fix viewport and device scale, disable animations for capture, and avoid time-dependent content. A network-idle event alone does not make a page deterministic.

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

The endpoint is slow or times out

Reduce page scope, block unnecessary resources, use a selector instead of full-page capture, and enforce a queue or concurrency limit. Do not retry indefinitely: classify navigation, browser, and target errors separately.

A user-controlled URL creates a security problem

An unrestricted capture endpoint can reach internal addresses or cloud metadata services. Validate schemes, resolve and filter hostnames, block private address ranges, restrict redirects, and isolate browser processes. Treat page content as untrusted input.

Decision checklist

  • Use ImageResponse when your input is structured data and the output is a designed OG card.
  • Use Playwright when you want modern browser automation, locator captures, and an in-process buffer.
  • Use Puppeteer when its Chrome-focused API and your deployment environment fit the project.
  • Use ScreenshotNeo when you want a URL-to-image or PDF service without packaging and operating Chromium, with consent cleanup and billing visibility built in.

Frequently Asked Questions

Can a Next.js client component take the screenshot?

Put browser automation or API credentials in a server route, server action, or background job. A client component should request the resulting image rather than launch a privileged capture.

Should I use a screenshot or ImageResponse for Open Graph metadata?

Use ImageResponse for a card generated from application data and supported CSS. Use a screenshot when the preview must reproduce an already rendered page or arbitrary URL.

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

Does network idle guarantee that a screenshot is complete?

No. Client rendering, fonts, animations, and lazy content can finish later. Wait for an application-specific selector or ready state.

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.