Puppeteer User Agent: Set, Rotate, and Test in 2026
A Puppeteer user agent can be set with page.setUserAgent() before navigation and rotated per session, but its browser version, platform, viewport, and client hints must remain consistent to reduce block rates. This guide is for web scraper developers who need copy-ready Node.js patterns for desktop and mobile profiles, controlled rotation, proxy pairing, and automated validation. You will also learn how to diagnose header mismatches and rendering changes while keeping public-web data collection aligned with site terms and applicable laws.
Understanding User Agents in Puppeteer
A Puppeteer user agent is the browser-and-platform identity string a page sends to servers. Optional user-agent metadata provides structured fields, such as platform and mobile status, for client-hint handling.
Puppeteer exposes two relevant identity layers:
Browser.userAgent()returns the browser’s original user-agent string.Page.setUserAgent()overrides the identity for a specific page and can also accept user-agent metadata.
A credible user agent must match the browser’s actual capabilities, platform, viewport, and rendered experience. A mobile identifier paired with a desktop viewport or incompatible client hints creates contradictions that detection systems can flag.
Although customization can help mimic expected browser behavior and reduce basic automation detection, the user agent is only one signal. The selected identity can also change server responses, mobile layouts, JavaScript features, and localized content. It should therefore be managed as part of a coherent browser profile rather than as a random header.
How to Set a Custom User Agent in Puppeteer
The basic implementation requires one page-level Page.setUserAgent() call before navigation.
- Launch Puppeteer and create a page.
const browser = await puppeteer.launch();
const page = await browser.newPage();
- Load a maintained user-agent string and apply it.
const ua = process.env.SCRAPER_USER_AGENT;
if (!ua) throw new Error("SCRAPER_USER_AGENT is required");
await page.setUserAgent({ userAgent: ua });
await page.goto(targetUrl, { waitUntil: "domcontentloaded" });
- Verify both the original and page-level values.
console.log("Original:", await browser.userAgent());
console.log("Page:", await page.evaluate(() => navigator.userAgent));
The override must be applied before the first request; changing it afterward leaves earlier navigation and subresource requests using the previous value. Once this setup works for a single profile, it can be extended to controlled rotation.
Implementing User Agent Rotation
Puppeteer user agent rotation should assign one coherent browser profile per page or session, not a new string for every request. A curated desktop and mobile pool can reduce repetitive fingerprints and handle basic anti-bot screening, but only if every profile contains compatible browser, operating-system, platform, and device values.
- Load vetted profiles from a version-controlled JSON file.
- Select once per page:
import agents from "./agents.json" with { type: "json" };
const pick = agents[Math.floor(Math.random() * agents.length)];
const page = await browser.newPage();
await page.setUserAgent({
userAgent: pick.userAgent,
userAgentMetadata: pick.metadata
});
- Verify before navigation:
console.log(await page.evaluate(() => ({
ua: navigator.userAgent,
platform: navigator.platform
})));
- Rotate at the session boundary, especially when the proxy IP changes.
Keep sticky proxy sessions and browser profiles paired; rotating only one creates an inconsistent identity. Record the value from browser.userAgent() alongside the selected profile so unexpected differences from Puppeteer’s original browser version are easier to debug.
Avoiding Detection with User Agent Manipulation
Rotation addresses repetition, but avoiding detection requires the declared browser identity to match the browser’s observable behavior. The user agent should be treated as one component of the full session fingerprint, not as a standalone disguise.
Keep userAgentMetadata, platform, mobile mode, touch support, locale, and request headers aligned with the selected string. The profile should also use a Chromium generation supported by the installed browser, since an unsupported declared version can conflict with JavaScript-exposed capabilities. Starting from the Browser.userAgent() baseline and modifying only necessary fields can reduce those conflicts.
Network identity matters as well. For multi-page workflows, a 24h+ sticky residential session from EProxies can preserve the same IP while Puppeteer retains its cookies and browser profile. Maintain that continuity through navigation, retries, and pagination rather than changing identities partway through an active workflow.
These measures should support authorized testing and collection rather than attempts to bypass access restrictions. Follow site terms, robots policies where applicable, and relevant data-access laws.
Common Issues and Troubleshooting
When a setup still produces blocks or unexpected pages, failures usually trace to three areas: the user-agent string, client-hint metadata, or the browser configuration presented to the server.
Check the effective value first. Browser.userAgent() reports the original browser identity, not necessarily the page override. Inspect the page value directly:
console.log(await page.evaluate(() => navigator.userAgent));
If the override is missing, confirm that Page.setUserAgent() runs before navigation and before any page code that triggers a request.
For incorrect mobile or desktop rendering, compare the profile with the viewport dimensions, touch support, operating system, interaction model, and metadata passed to Page.setUserAgent(). Incorrect or obsolete strings may also make an otherwise valid session appear inconsistent.
If failures occur only during rotation, log the selected profile beside the URL, response status, and screenshot. This makes malformed or incompatible profiles identifiable so they can be removed instead of retried. Also compare cookies, IP location, and browser characteristics when diagnosing failures that appear later in a session.
Practical Examples of User Agent Setup
With the main failure modes understood, the following examples show how to configure common profiles and inspect their rendering behavior.
Use the browser’s original value as a compatible baseline:
const browserUA = await browser.userAgent();
await page.setUserAgent(browserUA);
await page.goto(targetUrl);
For desktop localization testing, load an approved Chrome string from configuration rather than embedding it in application code:
const profile = JSON.parse(
await fs.promises.readFile('./agents.json', 'utf8')
);
await page.setUserAgent(profile.desktopChrome);
await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });
For mobile scraping, configure the viewport and touch capabilities with the mobile user agent:
await page.setUserAgent(profile.mobileChrome);
await page.setViewport({
width: profile.width,
height: profile.height,
isMobile: true,
hasTouch: true
});
After applying each setup, confirm the reported value with navigator.userAgent, then inspect screenshots and selectors for device-specific rendering changes. This checks both the declared identity and its effect on the returned page.
Advanced Techniques for User Agent Management
For larger deployments, manage the user-agent string, metadata, and viewport as one versioned profile, then bind that profile to a browser context and proxy session.
const profile = {
userAgent: process.env.UA,
platform: "Windows",
mobile: false,
viewport: { width: 1365, height: 768 }
};
const page = await browser.newPage();
await page.setUserAgent({
userAgent: profile.userAgent,
userAgentMetadata: {
platform: profile.platform,
mobile: profile.mobile
}
});
await page.setViewport(profile.viewport);
Store reviewed profiles in version-controlled JSON and reject missing fields during CI. Before deployment, test each profile against a diagnostic endpoint that exposes the received headers and browser properties. Comparing those results with browser.userAgent() also helps identify unexpected version drift after Puppeteer or Chromium upgrades.
Apply the validated profile consistently throughout the associated context. This preserves compatible request headers, rendered layouts, mobile content, and network identity while collecting localized public data under site terms and applicable laws.
Related reading
FAQ
How do I change the user agent in Puppeteer?
Call await page.setUserAgent({ userAgent: 'YOUR_USER_AGENT', userAgentMetadata: { platform: 'Windows' } }) before the first navigation, using the argument shape supported by your installed Puppeteer version. Retrieve the original value with await browser.userAgent(), then verify the override through navigator.userAgent and an HTTP request inspector.
What is the purpose of a user agent in web scraping?
A user agent tells the server which browser, operating system, and device profile the request claims to use. That identity can affect the returned HTML, mobile layout, compatibility code, and localized content. For reliable collection, it must agree with Chromium’s capabilities and related browser signals.
How can I rotate user agents in Puppeteer?
Load a curated array or JSON file of Chromium-compatible profiles and select one before creating or navigating a page. Keep the selected profile for the full browser context or authenticated session, and use its matching viewport and platform metadata to avoid desktop–mobile contradictions.
Why is user agent manipulation important in Puppeteer?
Puppeteer’s original user agent can disclose automation-related or environment-specific details, while a suitable override supports browser compatibility checks, mobile rendering tests, and consistent public-web collection. It does not prevent detection by itself: sites may also evaluate client hints, JavaScript properties, TLS behavior, cookies, IP location, and navigation patterns.
What are common issues with Puppeteer user agents?
Frequent failures include setting the override after navigation, declaring an outdated browser version, pairing a mobile string with a desktop viewport, or supplying metadata that conflicts with navigator.platform. If the server still receives the old value, inspect both the outgoing User-Agent header and navigator.userAgent, and check the official API signature for your installed Puppeteer release.
How do I test whether Puppeteer changed the user agent correctly?
Compare the browser default from browser.userAgent() with await page.evaluate(() => navigator.userAgent) after applying the override and navigating. Inspect the actual HTTP request as well, because JavaScript-visible values and request headers are separate detection surfaces. Where the target browser exposes user-agent client hints, also validate navigator.userAgentData.
Is changing a Puppeteer user agent legal?
Changing a browser identifier is not, by itself, permission to collect protected or restricted data. Use it for authorized testing, localization checks, and compliant public-web research while respecting the target site’s terms, robots directives where applicable, access controls, privacy obligations, and relevant laws.
This article was written by the EProxies team and reviewed against our editorial quality standards before publishing.