ScreenshotNeo

BlogHow-to

How to Set a Custom User Agent for Website Screenshots in Puppeteer

Set Puppeteer’s page user agent before navigation, then capture the page. Learn when to use device emulation, how to configure screenshots, and how to fix common issues.

By the ScreenshotNeo team4 October 20267 min read

Set the page’s user agent before navigating, await the setter, then take the screenshot with page.screenshot(). For a simple identity override, use page.setUserAgent(); for a known mobile device layout, emulate a device before navigation so Puppeteer configures both the user agent and viewport.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();

  await page.setUserAgent({
    userAgent: 'ExampleBot/1.0 (+https://example.com/bot)',
  });
  await page.goto('https://example.com', { waitUntil: 'networkidle2' });
  await page.screenshot({ path: 'screenshot.png', fullPage: true });
} finally {
  await browser.close();
}

The example identity is illustrative. Replace it with the exact string appropriate to your test or documented client. A user-agent value changes what the page reports as its agent; it does not by itself reproduce every characteristic of a real browser or device.

1. Install Puppeteer and run the example

In a new Node.js project, install Puppeteer:

npm install puppeteer

Save the first example as screenshot.mjs and run node screenshot.mjs. Puppeteer downloads a compatible browser as part of its standard installation. If your project already uses Puppeteer, keep its installed version and use the matching API reference: the current reference uses an options object for setUserAgent(), while older examples may show a positional argument.

See Puppeteer’s Page.setUserAgent() API, screenshot guide, and ScreenshotOptions reference.

2. Set the user agent before navigation

setUserAgent() applies an override to the page. Await the promise before calling goto(), so the first navigation uses the intended value. Setting it after navigation can leave the initial document served or rendered under the old identity.

const page = await browser.newPage();
await page.setUserAgent({ userAgent: 'ExampleBot/1.0 (+https://example.com/bot)' });
await page.goto('https://example.com', { waitUntil: 'networkidle2' });

The current API reference shows an options object with userAgent, and optional userAgentMetadata and platform. These values are useful when a test needs to set more than the user-agent string. Use the property names and types documented for the Puppeteer version installed in your project; do not combine signatures from different releases.

await page.setUserAgent({
  userAgent: 'ExampleBot/1.0 (+https://example.com/bot)',
  platform: 'Linux x86_64',
  // Supply userAgentMetadata only when your Puppeteer version documents
  // the metadata fields you need.
});

Use a truthful, controlled identifier for your own testing or client. A custom user agent is not authentication and does not grant permission to access a site. It also does not guarantee the site will select a particular page variant: servers and client-side code may use additional signals.

3. Capture the screenshot

After the page reaches the load condition appropriate for the target, call page.screenshot(). A practical full-page example with explicit navigation and cleanup is:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.setUserAgent({ userAgent: 'ExampleBot/1.0 (+https://example.com/bot)' });
  await page.goto('https://example.com', { waitUntil: 'networkidle2', timeout: 45_000 });
  await page.screenshot({ path: 'screenshot.png', fullPage: true, type: 'png' });
} finally {
  await browser.close();
}

networkidle2 is a convenient heuristic, not a guarantee that every page has finished its own work. Pages with long polling, analytics, animations, or delayed content may need a different readiness condition, a selector wait, or a bounded delay. See Puppeteer’s screenshots guide for capture basics.

4. Choose between a custom agent and device emulation

Need Use What it changes
Change only the page’s user-agent value page.setUserAgent() The page-level user-agent override
Capture a known device’s layout page.emulate(device) The device user agent and viewport

Puppeteer’s KnownDevices entries and page.emulate() are the built-in route for known-device screenshots. Emulate before navigation because resizing can affect how a site lays itself out.

import puppeteer from 'puppeteer';
import { KnownDevices } from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  const device = KnownDevices['iPhone 13'];
  await page.emulate(device);
  await page.goto('https://example.com', { waitUntil: 'networkidle2' });
  await page.screenshot({ path: 'mobile.png', fullPage: true });
} finally {
  await browser.close();
}

Use a device name present in the Page API documentation for your installed version. Device emulation sets a viewport as well as a user agent, but it should not be described as a complete real-device fingerprint simulation. If you need a custom viewport or device scale factor in addition to a custom agent, configure those dimensions explicitly and keep them consistent with the test you intend to run.

5. Configure output and capture scope

Screenshot options control the image independently of the user-agent override. Common choices include:

Option Purpose Notes
path Save the output to a file The extension determines the image type when type is omitted.
fullPage Capture the full document Defaults to false.
clip Capture a rectangular page region Use coordinates and dimensions for the region you want.
type Choose output format Supported screenshot output includes PNG and JPEG; check the installed version for available types.
quality Set lossy image quality Applies to JPEG, not PNG.
await page.screenshot({
  path: 'region.jpg',
  type: 'jpeg',
  quality: 82,
  clip: { x: 0, y: 0, width: 1200, height: 800 },
});

For a full-page PNG, omit quality because PNG does not use that setting. For a focused region, make sure the requested clip fits the rendered page and viewport behavior supported by your Puppeteer version. Refer to the official options reference for the exact version-specific shape.

6. Keep captures repeatable

  • Set the agent and any device or viewport settings before navigation.
  • Use the same URL, viewport, agent, readiness condition, and screenshot options when comparing runs.
  • Wait for a meaningful selector when the page has a known content-ready marker; use a timeout so a broken page cannot hang indefinitely.
  • Prefer a fixed viewport and avoid changing layout dimensions midway through the capture.
  • Use try/finally to close the browser even if navigation or screenshot capture fails.

Screenshot cost and runtime are driven by browser startup, page load, assets, and capture size. Reusing a browser process for a batch of pages can avoid repeated startup overhead, but isolate pages and always close the browser when the job ends. Large full-page images consume more memory and take longer to write than small clipped images; choose the smallest capture area and format that meets the task.

7. Common errors and fixes

Symptom Likely cause Fix
The page still appears to use the default agent The setter was not awaited, was called after navigation, or used a signature unsupported by the installed release. Await page.setUserAgent() before goto(); check the versioned API reference and inspect the browser request behavior.
The site returns the same layout The site does not select layout from user agent alone, or its decision depends on viewport or other signals. For a device layout, emulate a known device before navigation or set the viewport alongside the desired agent. Do not assume the string alone reproduces a physical device.
Navigation times out The page keeps network connections open or does not reach the selected lifecycle condition. Choose an appropriate waitUntil condition, wait for a specific selector, and set a finite timeout. A timeout means readiness was not observed in time; it does not necessarily mean no content rendered.
Screenshot is blank or incomplete Capture began before the relevant content rendered, or the page failed to load assets. Wait for a content selector or a known readiness signal, then capture. Inspect page errors and failed requests when diagnosing the target.
Unknown device or undefined device entry The device label differs from the installed version’s KnownDevices entries. Use a documented device name for that version, or set viewport and user agent explicitly.
Screenshot option or format rejected The option is misspelled, incompatible with the format, or not supported in that release. Check ScreenshotOptions; remove quality for PNG and use a supported type.

8. Or skip the browser setup

If your goal is a screenshot rather than controlling a local browser, ScreenshotNeo provides a website screenshot API and MCP server. Its one-call request accepts a URL and returns an image or PDF. See the ScreenshotNeo API documentation.

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

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

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 response headers identify the page verdict and billing status. Its MCP server includes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account and get 1,000 screenshots a month with no card.

FAQ

Does changing the user agent change the browser’s original user agent?

No. Browser.userAgent() reports the browser’s original value; Puppeteer documents that a page can override it with Page.setUserAgent(). See the Browser.userAgent() reference.

Should I use a custom user agent to take a mobile screenshot?

Usually use device emulation when you want a known device layout, because it sets both the user agent and viewport. A string override alone is only one input.

Does the user agent affect PNG versus JPEG?

No. The user agent affects the page request context; screenshot output options such as type and quality determine the image encoding.

Can I use this to bypass bot protection?

A user-agent override is not an authorization mechanism and does not guarantee access. Use it for legitimate testing of systems you control or are permitted to access.