How to Screenshot Google SERPs with a Custom Browser User Agent
Override the browser User-Agent in Chrome DevTools or Puppeteer, capture a Google results page, and understand what the screenshot can—and cannot—prove.
To screenshot Google search results with a custom user agent, set the User-Agent (UA) override before loading the search page, then capture the rendered page. For a one-off, use Chrome DevTools’ Network conditions panel. For repeatable captures, use Puppeteer to set the UA and viewport before navigation and save a screenshot.
A screenshot records one browser session at one time. A custom UA does not make the browser identical to a Google crawler, guarantee a particular result page, or prove that every searcher sees the same results.
Choose a capture method
| Method | Best for | Trade-off |
|---|---|---|
| Chrome DevTools | A one-off inspection where you want to see the browser settings and page. | Manual; record settings yourself for later comparisons. |
| Puppeteer | Repeatable or parameterized captures. | Requires a Node.js project and browser automation setup. |
Method 1: Override the User-Agent in Chrome DevTools
- Open Chrome and DevTools. Open the DevTools menu, choose More tools, then Network conditions. You can also open the Command Menu and search for “Show Network conditions.”
- In Network conditions, find User agent, clear Use browser default, and enter the full UA string you want to use. Google documents these controls for testing ad destinations against AdsBot; applying the same override while loading a Google search URL is a general browser technique, not a Google recommendation for collecting SERPs. See Google Ads Help: Override user agent with Chrome DevTools.
- Enter the Google search URL for your query in the address bar and load it. For example,
https://www.google.com/search?q=puppeteer. Reload if the page was already open before you changed the override. - Capture the page with Chrome’s screenshot capability or your operating system’s screenshot tool. If the page is longer than the viewport, use DevTools’ screenshot options to capture the full page where available.
- For a comparison, record the query, capture time, Chrome version, viewport dimensions, locale, device-emulation settings, and whether the browser was headful. Store this information with the screenshot.
Google Ads Help provides desktop and mobile AdsBot UA examples for ad destination quality checks. Those identifiers are for that AdsBot context; do not label them as a Google Search crawler or assume they produce a canonical SERP. The desktop example is AdsBot-Google (+http://www.google.com/adsbot.html). The mobile example is Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; AdsBot-Google-Mobile; +http://www.google.com/mobile/adsbot.html). Use them only when your task actually concerns the documented ad destination check.
Method 2: Capture a SERP with Puppeteer
Puppeteer controls Chrome or Firefox through browser automation protocols and supports page and element screenshots. The following Node.js example sets a desktop-sized viewport and UA before navigating, waits for navigation to settle, and writes a full-page PNG. It is a reusable starting point, not a tested or guaranteed Google-specific recipe. Google may show consent screens, challenges, or different results depending on context.
Install and run
mkdir serp-capture
cd serp-capture
npm init -y
npm install puppeteer
Save this as capture-serp.mjs:
import puppeteer from 'puppeteer';
const query = process.argv.slice(2).join(' ') || 'puppeteer';
const ua = process.env.CUSTOM_UA;
if (!ua) {
throw new Error('Set CUSTOM_UA to the complete User-Agent string you want to use.');
}
const url = `https://www.google.com/search?q=${encodeURIComponent(query)}`;
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewport({ width: 1365, height: 900, deviceScaleFactor: 1 });
await page.setUserAgent(ua);
const response = await page.goto(url, {
waitUntil: 'domcontentloaded',
timeout: 60000,
});
if (!response) {
throw new Error('Navigation returned no HTTP response.');
}
await page.screenshot({ path: 'serp.png', fullPage: true });
console.log(`Saved serp.png for ${url} (HTTP ${response.status()}).`);
} finally {
await browser.close();
}
Run it with a UA string appropriate to your test:
CUSTOM_UA='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36' node capture-serp.mjs 'puppeteer screenshot'
Use a real, internally consistent browser UA for ordinary rendering comparisons. The example version is illustrative; choose a UA that matches the browser version and environment you intend to represent. A UA string alone does not configure all browser characteristics.
Make captures more comparable
- Set viewport before navigation. Results layout depends on available width and height. Use the same dimensions and device scale factor for each run.
- Record the browser mode. Puppeteer is headless by default. Headless and visible-browser rendering can differ, so keep the mode fixed across a comparison and record it.
- Choose a wait condition deliberately.
domcontentloadedwaits for initial HTML parsing without waiting for every resource.loadwaits for page load resources and can take longer. Network-idle conditions can be unsuitable on pages with persistent requests. If a particular element matters, wait for that selector with Puppeteer’s locator or selector wait APIs, using the current Puppeteer documentation. - Control locale and device settings when relevant. UA, viewport, language preferences, client hints, cookies, and prior browser state can all affect what is rendered. Keep the chosen settings fixed and document them.
- Use an explicit output path and check the result. A navigation can return an error page or challenge page while still producing an image. Inspect the status and the screenshot content before treating it as a successful SERP capture.
See the Puppeteer guide from Chrome for Developers and the Puppeteer documentation index for current launch, navigation, emulation, and screenshot APIs.
What a custom UA changes—and what it does not
The User-Agent is a request string identifying information about the requesting browser or crawler. Chrome has reduced information in the default UA string to limit passive identification; additional details may be communicated through User-Agent Client Hints (UA-CH). Chrome’s guidance also describes device emulation that can set UA and client hints together. See Chrome’s User-Agent reduction guidance.
Changing only the UA text changes one part of browser identification. It does not necessarily reproduce the target device’s viewport, touch behavior, client hints, language, cookies, network location, or browser implementation. If your purpose is mobile layout inspection, use device emulation and set the viewport as well as the UA, then record what you configured.
AdsBot is a Google Ads crawler identity for ad destination checks. Google’s documentation does not establish an AdsBot UA as a way to obtain a definitive Google Search results page. A search screenshot is an observation of one rendered session, not a universal ranking record.
Keep the screenshot useful and authentic
- Keep the original image unchanged if it is evidence of what the browser displayed. Add explanatory overlays only when clearly labeled as annotations.
- Do not alter the visible interface, or manufacture, remove, or alter suggestions or search results while presenting the image as Google Search. Review Google’s Search screenshot guidelines.
- Keep query, timestamp, viewport, locale, browser version, UA, and emulation details with the capture when comparing results over time.
- Do not frame one screenshot as proof of what all users see or as a stable ranking measurement. Results can vary by time and context.
Or skip the browser setup
ScreenshotNeo can capture a page with one API request. It returns a PNG, JPEG, WebP, or PDF, with options such as viewport presets, full-page capture, custom UA, and cookies. See the ScreenshotNeo API documentation for parameters and response details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://www.google.com/search?q=puppeteer -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://www.google.com/search?q=puppeteer",
},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://www.google.com/search?q=puppeteer',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(({ writeFile }) => writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
For a custom UA, add the supported UA parameter shown in the API documentation. ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before the capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets Claude, Cursor, and other MCP clients use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000. ScreenshotNeo is a product of ScreenshotNeo. Sign up for 1,000 free screenshots a month, no card required.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| The page looks unchanged after setting the UA. | The page was not reloaded after changing the override, or the browser session retained prior state. | Set the UA first, reload the search URL, and start a clean session if the comparison requires it. |
| The mobile UA still shows a desktop-style page. | Only the UA string changed; viewport, client hints, or device settings may not match a mobile device. | Configure device emulation and viewport as well. Record the configuration rather than describing it as UA-only. |
| Puppeteer saves a challenge, consent page, or error page. | The response was not the expected results page, or access conditions changed. | Inspect the screenshot, final URL, and HTTP status. Do not interpret a challenge page as a SERP or assume a UA override avoids it. |
| Navigation times out. | The page or a resource did not settle within the timeout, or network conditions are slow. | Use a deliberate navigation wait condition, adjust the timeout for your environment, and capture only after the content relevant to your task is ready. |
| Repeated captures differ. | Search results and page rendering can vary by time, query context, browser state, viewport, locale, or other signals. | Keep browser and capture settings constant, record metadata, and treat each image as a time-specific observation. |
| The script fails to launch a browser. | The local Node.js setup or Puppeteer browser installation is incomplete, or the runtime lacks required dependencies. | Review Puppeteer’s installation guidance, reinstall dependencies as appropriate, and check the launch error for missing system libraries or permissions. |
Performance, reliability, and cost
- Performance: Browser startup and page loading usually dominate capture time. Reusing a browser process for batches can reduce startup overhead; close pages and the browser cleanly. Avoid waiting for every network connection when the page has long-lived requests.
- Reliability: Check HTTP status, final URL, and image contents. A successful screenshot operation can still capture an interstitial or error page. For repeat comparisons, save the metadata beside each image.
- Cost: Puppeteer is an open-source browser automation library, but running it still consumes your compute, storage, and maintenance time. Google may change page behavior; neither a UA override nor an automated browser guarantees access or stable results. ScreenshotNeo’s published plans are Free with 1,000 shots/month, Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; annual billing gives two months free, and every feature is on every plan.
Frequently asked questions
Does changing the UA make my browser a Googlebot?
No. A UA string is one identification signal. It does not turn the browser into Google’s crawler or reproduce all crawler behavior.
Can an AdsBot UA show me the Google Search result Google sees?
The AdsBot strings in the cited Google documentation are for ad destination checks. They are not documented as a way to obtain a canonical Search results page.
Can I use the screenshot as proof of my ranking?
It can document what one configured browser rendered at a particular time. Include the context and avoid treating it as a universal result for all searchers.
Should I use headless or headful Puppeteer?
Use the mode that matches the task, then keep it consistent across comparisons. Puppeteer runs headless by default, and mode can affect rendering.


