ScreenshotRender
← Back to blog
Tutorials

Puppeteer Screenshot: 3 Ways to Capture a Page in Node.js

Robert Belt·8 min read
Updated On :
Orange minimalist illustration of a Node.js script turning a URL into a full page screenshot

Taking a screenshot in Puppeteer is one line, page.screenshot(), right up until you need the full page, a site behind Cloudflare, or a hundred captures a day without running a Chromium fleet. By the end of this you'll have three working ways to screenshot a page in Node.js, and a rule for which one to reach for.

The three are Puppeteer (the default, Chrome only), Playwright (the same idea with nicer cross browser support), and a single HTTP call (no browser at all). They are ordered by how much infrastructure you want to own, from the most to the least.

What's the fastest way to take a screenshot in Node.js?

The fastest way to capture a page in Node.js is page.screenshot() after launching headless Chrome with Puppeteer, or a single HTTP request if you'd rather not run a browser at all. With ScreenshotRender the entire capture is one fetch call: fetch("https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://en.wikipedia.org/wiki/HTTP&fullPage=true"). The JSON response carries a hosted image URL at data.screenshot.

If you want to own the rendering, drive a real browser with Puppeteer or Playwright instead. Both load the page locally and write a PNG to disk, at the cost of a Chromium binary you install and keep current. The rest of this post shows all three so you can pick by how much you want to maintain.

How do you take a screenshot with Puppeteer?

Puppeteer takes a screenshot in four steps: launch a browser, open a page, navigate to the URL, then call page.screenshot({ path: 'page.png' }). After npm install puppeteer, you launch headless Chrome with puppeteer.launch(), call await page.goto(url), and capture. Modern Puppeteer runs headless by default and downloads its own Chrome for Testing binary on install, so there is no separate driver to manage.

The capture itself is one call, documented in the Puppeteer page.screenshot reference. The catch shows up the moment you want the whole page rather than the slice currently in view, and the moment a page keeps rendering after the initial load. The first is a flag. The second is a wait, and it is the most common reason a Puppeteer screenshot comes back half empty.

How do you take a full page screenshot in Puppeteer?

Set fullPage: true on the screenshot call: page.screenshot({ path: 'page.png', fullPage: true }) captures the entire scrollable document instead of the default 800 by 600 viewport. Puppeteer measures the document height and renders it all into a single image. If you only need the visible area at a specific size, set it first with page.setViewport({ width: 1280, height: 720 }) and leave the flag off.

Full page is where the wrong wait strategy bites. Pages that lazy load images on scroll, or finish rendering after the network goes quiet, come back with a blank lower half if you capture too early. The fix is to wait for a real signal, not a fixed sleep. If you've hit page.waitForTimeout is not a function trying to add a pause, that method was removed in recent Puppeteer; the replacement is a plain promise or waitForSelector. The same scroll-and-stitch headache is why a reliable full page capture is harder than it looks.

How do you take a screenshot with Playwright instead?

Playwright captures a screenshot with the same shape of call, page.screenshot({ path: 'page.png', fullPage: true }), and the API is close enough to Puppeteer that porting takes minutes. The difference is breadth: after npm install playwright and npx playwright install, you get first party Chromium, Firefox, and WebKit builds, so capturing the same page across three engines is one config change rather than three setups. The Playwright screenshots guide covers element and clipped captures too.

Playwright also has smarter built in waiting, which removes a class of flaky captures, and its auto-managed browsers make CI a little less fragile than Puppeteer. For one Chromium PNG the two are interchangeable. For cross browser visual checks, Playwright is the nicer of the do-it-yourself options. Either way you are still running a browser, which means a binary in your environment, memory headroom per capture, and version drift that turns a green CI run red after an unrelated upgrade.

Skip the Chromium build, the Cloudflare fight, and the EC2 fleet.

One GET request to ScreenshotRender returns a hosted PNG with cookie banners and ads already stripped. A real Chromium renders the JavaScript on our infrastructure, so there is nothing to install or keep current. 100 free screenshots per month, no credit card.

Get an API key

How do you screenshot a page in Node.js without running a browser?

You skip the browser entirely by calling a screenshot API: send the URL to an HTTP endpoint and get a hosted image back, which in Node.js is a single fetch call with no dependencies. The full request is one copy-pasteable line: fetch("https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://en.wikipedia.org/wiki/HTTP&fullPage=true"). Read the image URL from (await res.json()).data.screenshot and either store it or download the bytes.

The parameters are the whole API surface. url is the page to capture, fullPage=true grabs the entire scrollable document instead of the default 1280 by 720 viewport, and wait takes a millisecond delay for pages that finish rendering after the initial load, like a React single page app. There is no SDK to install; the landing page shows the same call in Python, Node.js, and cURL because any language that speaks HTTP works identically.

The other thing you stop doing yourself is cleanup. Cookie consent banners, ad overlays, and chat widgets are removed automatically before every capture, on every plan including the free one, so the PNG is the page rather than the page plus three popups. With Puppeteer or Playwright you would write that dismissal logic by hand for each site. The free plan covers 100 screenshots a month with no credit card, which is enough to wire this into a Node script before you decide on volume. The same three-way split exists in Python, if that's your other stack.

When does each Node.js screenshot method fail?

Every method here fails on the same short list of pages: bot-protected sites, login walls, lazy-loaded content, and fragile CI environments. Knowing which case you are in saves you a day of debugging the wrong layer.

  • Cloudflare and bot protection. A vanilla headless Puppeteer or Playwright gets served a challenge page, so your screenshot is the challenge, not the site. You need a stealth setup and usually a residential proxy, or an API that bakes it in. ScreenshotRender ships Stealth Mode on the Hobby plan and above; see our guide to screenshotting Cloudflare-protected sites for what changes.
  • Login walls. A URL-only API takes a URL, not a session cookie, so it cannot reach a page behind a login. This is the one case where driving Puppeteer yourself wins: you can script the sign-in and capture the authenticated page. For public pages, the URL-only call is the simpler trade.
  • Lazy-loaded images and SPAs. Content that loads on scroll or after the network goes idle is missing if you capture too early. In Puppeteer or Playwright you scroll and wait for a selector; with the API you pass the wait parameter in milliseconds.
  • CI fragility. A different Chromium version or a missing font on the runner shifts pixels and breaks brittle tests. Driving a browser in CI means owning that drift; an HTTP call renders on fixed infrastructure, so the output for the same URL stays stable across runs.

None of this means browsers are bad. It means a local browser carries costs, install, memory, and version drift, that you only want to pay when you genuinely need to drive the page, not when you just need an image of it.

Common questions about taking a screenshot in Puppeteer and Node.js

How do I take a full page screenshot in Puppeteer?

Pass fullPage: true to the screenshot call: page.screenshot({ path: 'page.png', fullPage: true }). Puppeteer measures the document height and stitches the entire scrollable page into one image instead of just the default viewport. If the page lazy loads content on scroll, scroll to the bottom or wait for the images first, otherwise the lower part of the capture comes back blank.

What is the difference between Puppeteer and Playwright screenshots?

The API is nearly identical: both expose page.screenshot with a fullPage option and both drive a real Chromium. Playwright ships first party builds for Chromium, Firefox, and WebKit and installs them with one command, so cross browser captures are easier. Puppeteer is Chrome focused and slightly lighter if Chromium is all you need. For a single full page PNG the two are interchangeable.

Can I take a screenshot in Node.js without installing Chrome?

Yes, by calling a screenshot API instead of driving a local browser. The rendering happens on the provider's infrastructure, so your project only needs a fetch call and no Chromium binary. Puppeteer and Playwright both download a browser locally, which is the part that drifts and breaks in CI; an HTTP request has nothing to install.

How do I screenshot a Cloudflare-protected site in Node.js?

A vanilla headless Puppeteer or Playwright gets served a Cloudflare challenge page instead of the real content, so your capture is the challenge, not the site. You need a stealth setup plus a residential proxy, or an API that handles bot detection for you. ScreenshotRender's Stealth Mode, bundled on the Hobby plan and above, returns the real page from the same one line call.

Is there a free screenshot API for Node.js?

Yes. ScreenshotRender's free plan includes 100 screenshots per month with no credit card required, full page capture, and cookie banner and ad removal enabled by default. Any language that speaks HTTP works, and Node.js is one of the three snippets shown on the landing page, so wiring it in is a single fetch call.

The honest takeaway: pick by how much you want to own. If you only need an image of a public URL, the one line fetch call is the least to maintain. If you need to drive the page, sign in, or run cross browser visual checks, run Puppeteer or Playwright and accept the browser that comes with it. The screenshot is one line in all three; the difference is everything around it.

Keep reading