ScreenshotNeo

BlogHow-to

How to Capture a Website Screenshot with a Custom Browser User Agent

Set a custom user agent before navigation, choose viewport, full-page, or element capture, and learn when you need more than a user-agent override.

By the ScreenshotNeo team4 October 20268 min read

To capture a website screenshot with a custom browser user agent, create a Playwright browser context with the desired userAgent before opening or navigating the page. Then navigate to the URL and save the screenshot. For content below the visible viewport, set fullPage: true.

A user-agent override changes the browser identity string sent with requests. It does not, by itself, reproduce a phone or tablet: viewport size, screen size, touch capability, and other browser properties may also matter. The examples below use Node.js and Playwright. See the official Playwright emulation documentation and Page API for configuration details.

1. Install Playwright

Use a current Node.js installation. In an empty project directory, install Playwright and its Chromium browser:

npm init -y
npm install playwright
npx playwright install chromium

Playwright can run Chromium, Firefox, and WebKit. Install and launch the browser engine you need for the target test. Browser-specific rendering can differ, so use the same engine when reproducing a browser-specific issue.

2. Capture a page with a custom user agent

Save this as screenshot.js. Replace the example URL and placeholder user agent with the values for your test.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  try {
    const context = await browser.newContext({
      userAgent: 'ExampleBot/1.0',
    });
    const page = await context.newPage();

    await page.goto('https://example.com', {
      waitUntil: 'load',
      timeout: 30_000,
    });
    await page.screenshot({ path: 'screenshot.png' });
    await context.close();
  } finally {
    await browser.close();
  }
})();

Run it with:

node screenshot.js

The context option is set before newPage() and navigation, so the page is created under that context configuration. Choose a user-agent string that matches the test you intend to perform; ExampleBot/1.0 is only a placeholder. This workflow configures the browser request identity, but cannot guarantee that every site will serve a particular page variant.

3. Choose what to capture

Playwright’s screenshot API supports a viewport screenshot by default, a full-page screenshot, and screenshots of a selected element. Choose the scope that matches the question you are investigating.

Capture Use it for Example
Visible viewport A reproducible view of what fits on screen await page.screenshot({ path: 'viewport.png' });
Full page Content extending below the current viewport await page.screenshot({ path: 'full-page.png', fullPage: true });
Element A component or region identified by a locator await page.locator('main').screenshot({ path: 'main.png' });
Higher resolution Output at device-pixel scale for sharper image detail await page.screenshot({ path: 'retina.png', scale: 'css' });

To capture a whole page, change the earlier call to:

await page.screenshot({ path: 'full-page.png', fullPage: true });

To capture a specific element and wait for it to appear:

const target = page.locator('main article');
await target.waitFor({ state: 'visible', timeout: 10_000 });
await target.screenshot({ path: 'article.png' });

For image scale, Playwright supports CSS-pixel output and device-pixel output. Use scale: 'css' for output dimensions based on CSS pixels; use scale: 'device' when you need device-pixel detail. Device scale can increase the image dimensions and file size. Consult the screenshot options documentation for the capture choices available in your Playwright version.

4. Match the rest of the device profile when needed

If the goal is to see a mobile layout, a custom user-agent string alone is not a complete mobile simulation. Sites may also respond to viewport and screen dimensions, touch support, and other environment details. Use a coherent device profile or configure the relevant emulation properties alongside the user agent.

For example, a manually configured context can set the viewport, screen, and touch capability with the user agent:

const context = await browser.newContext({
  userAgent: 'YOUR_TARGET_USER_AGENT',
  viewport: { width: 390, height: 844 },
  screen: { width: 390, height: 844 },
  deviceScaleFactor: 3,
  isMobile: true,
  hasTouch: true,
});

Use values that belong together for the device and browser version being represented. When a Playwright device descriptor matches your target, its bundled settings can be a better starting point than changing only the user agent. Device descriptors and supported options are documented in Playwright emulation. Check the rendered page; an override does not force arbitrary sites to return a specific design or content.

5. Make the capture reproducible

Dynamic pages may change while the screenshot is being taken. Add an explicit readiness condition when the page needs time to render data, fonts, or images. Prefer waiting for a meaningful selector over adding an arbitrary long delay:

await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.locator('main').waitFor({ state: 'visible' });
await page.screenshot({ path: 'ready.png', fullPage: true });

If the page is known to update after navigation, wait for the relevant state in the page before capture. A screenshot taken after the initial document load may still miss content rendered asynchronously. For lazy-loaded content, a full-page capture may trigger layout and loading behavior, but inspect the resulting image to confirm the target content is present.

6. cURL, Python, and Node.js options

A custom browser user agent must be applied by a browser or a screenshot service that supports user-agent configuration. cURL can send an HTTP User-Agent header, but it does not render a webpage or capture a browser screenshot. To create an image with cURL, call a screenshot API that accepts the user-agent parameter. ScreenshotNeo accepts the parameter names used by other screenshot APIs; see the ScreenshotNeo API documentation for the supported options.

Python with Playwright

import asyncio
from pathlib import Path
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        try:
            context = await browser.new_context(
                user_agent='YOUR_TARGET_USER_AGENT',
                viewport={'width': 1365, 'height': 900},
            )
            page = await context.new_page()
            await page.goto('https://example.com', wait_until='load', timeout=30_000)
            await page.screenshot(path='screenshot.png', full_page=True)
            await context.close()
        finally:
            await browser.close()

asyncio.run(main())

Install the Python package and browser with pip install playwright and playwright install chromium.

Node.js with Playwright

The complete Node.js setup is in sections 1 and 2. Set userAgent on browser.newContext() before creating the page. Use fullPage: true for the entire document or a locator’s screenshot() method for one element.

cURL with ScreenshotNeo

For a rendered screenshot through an API, send the target URL and custom user agent as parameters. This example saves a WebP image:

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

Python with ScreenshotNeo

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={
        "access_key": "YOUR_API_KEY",
        "url": "https://example.com",
        "userAgent": "YOUR_TARGET_USER_AGENT",
    },
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js with ScreenshotNeo

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://example.com',
  userAgent: 'YOUR_TARGET_USER_AGENT',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

Use the exact parameter spelling accepted by the API for the option in your integration; consult the docs when configuring output format, full-page capture, or other capture settings. Keep API keys out of public client-side code.

7. Troubleshooting

Symptom Likely cause What to do
The page still looks like desktop Only the user-agent string changed; viewport, touch, or other device properties do not match. Set a coherent device profile or the viewport and relevant emulation properties. Inspect the page after capture.
The screenshot shows only the top of the page The default capture is the visible viewport. Set fullPage: true for a full-document image.
An element screenshot fails or is incomplete The locator did not resolve to a visible element, or the element has not rendered yet. Wait for the target locator to be visible and verify the selector against the loaded page.
Content is missing from a full-page capture It may be lazy-loaded or rendered after the navigation event used. Wait for the relevant content or selector, then capture and inspect the output.
The page differs from the expected user-agent variant The site may use other request or browser signals, cached responses, or its own routing rules. Check the actual rendered page and match additional emulation settings as appropriate. A user-agent override cannot guarantee a particular response.
Navigation times out The page is slow, unreachable, or waiting for a load condition that does not occur promptly. Check the URL and network access; choose a suitable readiness condition, raise the timeout when justified, and wait for the specific content needed.
The output file cannot be opened as an image The request may have returned an error response or a different format. For API captures, check the HTTP status and response headers before saving bytes as an image; confirm the requested format and API parameters.
The browser executable is missing The Playwright package is installed but its browser binary is not. Run npx playwright install chromium, or the corresponding install command for the engine you use.

8. Performance, reliability, and cost

Browser screenshots involve launching a browser, loading the target page, waiting for required content, and encoding the image. Reusing a browser process for multiple captures can avoid repeated launches; keep each capture in its own context when it needs isolated cookies, storage, or emulation settings. Set practical navigation and selector timeouts, and close contexts and browsers even when a capture fails.

For repeatable comparisons, keep the browser engine and version, user agent, viewport, device scale, target URL, and readiness condition consistent. Websites can change their content independently, so a matching user agent alone does not make captures deterministic. Higher-resolution and full-page images can use more memory and produce larger files.

With a local Playwright workflow, cost depends on the machine and infrastructure running the browser. With a hosted screenshot API, check its billing rules, limits, and response metadata. ScreenshotNeo says only clean shots are billed; bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and responses identify the page verdict and billed status in headers.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. This one-call example passes a custom user agent and saves a WebP result:

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

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets Claude, Cursor, and other MCP clients take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan. See the API docs for configuration and sign up for 1,000 free screenshots a month, with no card.

FAQ

Does changing the user agent make a screenshot identical to another browser or device?

No. It changes the user-agent string. Match the relevant viewport, screen, touch, and other emulation settings for a more coherent device-like setup, then inspect the result.

Can I use cURL by itself to take a website screenshot?

No. cURL can make HTTP requests and set headers, but it does not render the page. Use a browser automation library such as Playwright or call a screenshot API.

How do I capture just one part of a page?

In Playwright, locate the element and call screenshot() on that locator. Wait until it is visible if it loads dynamically.

Will a custom user agent make every website show the intended version?

No. A site can make decisions using other signals or its own rules. The configured user agent is an input to the browser context, not a guarantee about the site’s response.