How to Capture a Website Screenshot with a Mobile Viewport in n8n
Capture a website at a mobile viewport in n8n with a hosted browser API or Puppeteer. Configure the viewport, save the image, and troubleshoot common failures.
To capture a website screenshot at a mobile viewport in n8n, use a browser-rendering service through the HTTP Request node, or run Puppeteer in an environment with a compatible browser. Set the viewport width and height before navigating to the page, wait for the content you need, capture the viewport or full page, then pass the returned image as binary data to a storage or delivery node.
A plain HTTP request that fetches a webpage’s HTML does not render it like a browser and cannot produce a website screenshot by itself. n8n’s Browserless integration listing describes screenshot capture and custom API calls through HTTP Request. Puppeteer provides browser viewport and screenshot APIs. [c001] [c002] [c003]
Choose a capture route
| Route | Use it when | Trade-off |
|---|---|---|
| Hosted browser or screenshot API | You want n8n to call a managed browser service and receive an image. | Request fields, authentication, output format, and binary mapping depend on the provider. Check its current documentation; this research does not establish current Browserless endpoint parameters. [c001] |
| Puppeteer in your runtime | You control the execution environment and want direct browser automation. | You must provide a working Chrome environment or connect to a remote browser. The puppeteer package downloads Chrome for Testing; puppeteer-core does not and suits remote or operator-managed browsers. [c004] |
| Third-party Puppeteer community node | You want a node interface and the installed node version exposes the options you need. | It is community software; check its install, runtime, and browser requirements. The repository describes screenshot formats, device emulation, and remote browser support. [c005] |
In all three routes, “mobile viewport” can mean only a narrow CSS viewport or a broader device-emulation setup. Width and height alone do not reproduce every property of a physical phone. Configure mobile, touch, and device scale settings only when the chosen tool supports them and you actually need them.
Build the workflow with a hosted browser service
- Choose a trigger. Use Manual Trigger while building, then a Schedule, webhook, or another trigger as appropriate.
- Provide the URL and dimensions. Store the target URL and intended viewport width and height in workflow data. Validate that the URL is allowed for your workflow and that the dimensions are positive numbers within your provider’s documented limits.
- Add an HTTP Request node. Configure it for the screenshot provider’s documented method, endpoint, authentication, and parameters. n8n’s Browserless listing describes using HTTP Request for custom API calls, but the exact current Browserless request fields should be taken from Browserless documentation rather than guessed. [c001]
- Request an image response. Select the provider’s documented output format, such as PNG, JPEG, or WebP where supported. Configure the node response as a file/binary response and choose a binary property name, for example
data. Node labels and response controls can vary by n8n version. - Store or deliver the binary output. Connect the HTTP Request node to the destination you need, such as a file-storage, object-storage, or messaging node. Select the binary property configured in the request node.
- Run with a test URL. Confirm the output item contains binary data and that the resulting file opens. If the result is JSON or HTML, review the provider response mode and API parameters.
Provider request template: treat the following as a checklist, not a copy-paste request. Replace every placeholder with fields from the provider’s current API documentation; this research does not validate a live endpoint, exact parameter names, or binary-response mapping.
HTTP Request node
Method: [provider-documented method]
URL: [provider-documented screenshot endpoint]
Authentication: [n8n credential or provider-supported auth]
Parameters/body: target URL, viewport width, viewport height, output format
Response: file/binary, property name: data
Put API secrets in n8n credentials or the provider’s supported authentication mechanism. Avoid putting credentials in a URL or in workflow prompts. For private target pages, verify how the browser service receives the necessary cookies or headers and whether the provider supports your authentication pattern.
Capture with Puppeteer
This runnable Node.js example uses Puppeteer directly. It sets a mobile-sized viewport before navigation, waits for a page-specific selector, and saves a viewport screenshot. Use a selector that appears when the content you need is ready; adjust the timeout and navigation wait to suit the site.
npm install puppeteer
// save as capture.mjs
import puppeteer from 'puppeteer';
const url = process.argv[2] ?? 'https://example.com';
const width = Number(process.env.VIEWPORT_WIDTH ?? 390);
const height = Number(process.env.VIEWPORT_HEIGHT ?? 844);
const readySelector = process.env.READY_SELECTOR;
if (!Number.isInteger(width) || !Number.isInteger(height) || width < 1 || height < 1) {
throw new Error('VIEWPORT_WIDTH and VIEWPORT_HEIGHT must be positive integers');
}
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewport({ width, height, deviceScaleFactor: 1 });
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
if (readySelector) {
await page.waitForSelector(readySelector, { timeout: 30000 });
}
await page.screenshot({ path: 'screenshot.png', type: 'png' });
} finally {
await browser.close();
}
Run it with node capture.mjs https://example.com. To wait for a known application element, set READY_SELECTOR, for example READY_SELECTOR='.product-grid'. The example uses a viewport screenshot. Puppeteer also supports page screenshots and element screenshots; consult its API for the installed version. [c003]
Optional Puppeteer settings
- Device scale factor: set
deviceScaleFactorwhen you need a higher-resolution image. Larger output can increase file size and capture work. - Mobile and touch emulation: configure
isMobileandhasTouchinsetViewportif your browser version and use case support them. Apply them before navigation; changing them later can reload a page in some cases. [c002] - Full-page capture: pass
fullPage: truetopage.screenshotwhen you need the scrollable page, not just the visible viewport. Very long pages can create large images. - Element capture: find a target with
page.locator('selector')or another supported locator API and use its screenshot method, or use the equivalent API in your installed Puppeteer version. Check the current API because locator support can change. [c003] - Format: use
type: 'jpeg'ortype: 'webp'where supported by your Puppeteer and browser versions. PNG is a practical default for sharp text and transparency; JPEG is often smaller for photographic content. - Remote browser:
puppeteer-corecan connect to an operator-managed or remote browser, but you must supply a compatible browser endpoint and connection details. It does not install Chrome. [c004]
Make the screenshot reflect the intended mobile state
- Set dimensions before loading. Choose the CSS viewport size for the layout breakpoint you want to inspect, then call
setViewportbeforegoto. Puppeteer recommends setting the viewport before navigation because many sites do not expect a viewport change after load. [c002] - Decide whether you need device emulation. A width and height test responsive layout. Mobile and touch flags can affect browser behavior, but still do not make desktop browser automation equivalent to a real phone.
- Wait for the visual state, not just a timer. Prefer a known selector or application state. If a page has delayed images or client-rendered content, a navigation event alone may be too early. A fixed delay is a fallback when no useful readiness signal exists.
- Pick the capture region. Viewport captures show the initial screen. Full-page captures include the scrollable page. Element captures isolate a component. Choose deliberately because full-page output may be very tall and element output can fail if the selector is missing or hidden.
- Inspect the output in n8n. Confirm that the image is in the expected binary property and that downstream nodes use that same property.
Pass the image through n8n
The exact binary field configuration depends on the n8n node and provider. For an HTTP Request response configured as a file, use the binary property produced by that node in the next step. For a Puppeteer community node, follow that node’s documented output field. The community repository lists screenshot options, but its behavior and requirements depend on the installed version. [c005]
- Use a descriptive filename with a safe extension matching the actual format.
- When processing multiple URLs, keep each URL and its screenshot associated in the same item or attach a stable identifier before branching.
- For downstream APIs, check their accepted MIME type, file-size limit, and binary field requirements.
- Do not log screenshots or authentication data if the captured page contains sensitive information.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. It returns an image or PDF from a single GET request. Its API accepts a URL and viewport options; see the ScreenshotNeo documentation for parameter names and response behavior. In n8n, configure HTTP Request to make a GET request to the API with your access key, target URL, and desired mobile viewport dimensions, and return the response as binary data.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-d width=390 \
-d height=844 \
-o shot.webp
The API key and viewport parameter names should be set according to the current docs. In n8n, keep the key in credentials rather than hard-coding it into a shared workflow.
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://example.com",
"width": 390,
"height": 844,
},
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',
width: '390',
height: '844',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', bytes));
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture, and bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card required.
Performance, reliability, and cost
- Rendering time: Browser startup, navigation, and site scripts affect total time. No measured capture timings are established by the research, so benchmark your own target pages and workflow. [c003] [c004]
- Waiting strategy: Waiting for all network activity to stop can be unsuitable for pages with persistent connections or polling. A known selector or application-ready signal is usually a more targeted condition. Keep waits bounded so a stuck page does not hold a workflow run indefinitely.
- Image size: Full-page captures and high device scale factors produce larger files. Use the smallest dimensions and format that meet the downstream need.
- Retries: Retry transient network or provider errors with a finite attempt count and backoff. Avoid unlimited retries: they can tie up n8n executions and repeat work.
- Service cost: Hosted provider prices, quotas, and rate limits vary and were not established in this research. Check the current provider plan before scheduling high-volume runs. For ScreenshotNeo, consult its published pricing and usage headers to track billed results.
- Operational ownership: A hosted browser removes the need for you to install and maintain its browser runtime. Self-managed Puppeteer gives browser-level control but makes you responsible for compatible Chrome, libraries, memory, and process cleanup. [c004] [c005]
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Screenshot has desktop layout | Viewport was changed after navigation, or the request did not apply dimensions. | Set width and height before navigating. Confirm the hosted API’s documented parameter names or the Puppeteer viewport configuration. [c002] |
| Page content is missing | Capture happened before client-side rendering or lazy content appeared. | Wait for a page-specific selector or app-ready state, then capture. Use a bounded timeout. |
| HTTP node returns JSON or HTML | Response mode is not set to file, or the API request is invalid and returned an error document. | Inspect status and response body, verify endpoint and parameters against the provider docs, then configure binary/file response mode. |
| Browser fails to launch | Chrome is absent, incompatible, or missing system libraries; puppeteer-core does not install Chrome. |
Install the compatible browser and dependencies, use the documented runtime, or connect to a supported remote browser. [c004] [c005] |
| Community node is unavailable | The package may not be installed, allowed, or compatible with the current n8n environment. | Check the community node’s installation and runtime instructions; alternatively call a hosted browser API from HTTP Request. [c001] [c005] |
| Selector wait times out | The selector differs at mobile width, appears only after interaction, or the page failed. | Inspect the page at the same viewport, use a stable selector, or wait for a more suitable state. Check navigation status and authentication. |
| Downstream node says no binary data | The previous node returned text/JSON or wrote the file under another property name. | Set the response to file/binary and use the exact binary property name downstream. |
| Image is unexpectedly huge | Full-page mode or a high device scale factor captured more pixels than needed. | Use viewport capture, lower the scale factor, or resize after capture if the destination permits. |
| Private page is unauthenticated | Browser service did not receive the session or credentials. | Use the provider’s supported secure cookie/header mechanism, or authenticate in the Puppeteer flow. Keep secrets in n8n credentials. |
FAQ
What mobile width should I use?
Use the viewport width relevant to the breakpoint or layout you need to inspect. A single width cannot represent every phone or browser configuration.
Does a mobile viewport prove the page works on a real phone?
No. It checks a browser viewport and any emulation options you configured. Validate touch behavior, device-specific APIs, and real hardware separately when those matter.
Can I capture only one component?
Yes, if the selected browser tool supports element screenshots. Ensure the element exists and is visible after the page reaches the desired state.
Can I use an HTTP Request node without a browser service?
Not to render a normal webpage screenshot. Use a browser or a screenshot API that runs one for you.
Sources
- [c001] n8n Browserless integration listing.
- [c002] Puppeteer Page.setViewport API.
- [c003] Puppeteer screenshot guide.
- [c004] Puppeteer installation guide.
- [c005] Community Puppeteer node repository described in the research dossier.


