ScreenshotNeo

BlogHow-to

How to Capture a Webpage Screenshot from a Webhook in n8n

Build an n8n webhook that accepts a page URL, captures it with a browser screenshot API, and returns the image bytes to the caller.

By the ScreenshotNeo team4 October 202611 min read

To capture a webpage screenshot from an n8n webhook, accept a target URL with the Webhook node, pass it to a browser-rendering screenshot API with an HTTP Request node, then return the response as binary data with Respond to Webhook. The caller sends JSON such as {"url":"https://example.com"} and receives an image response. This guide uses Browserless as the do-it-yourself hosted browser example; the same n8n flow can call other screenshot APIs that accept a URL and return image bytes.

The data path is: caller → n8n Webhook → screenshot API → n8n binary response → caller. A plain HTTP fetch of a page’s HTML is not equivalent: a browser-rendered screenshot can include JavaScript-rendered content and layout.

1. Create the webhook trigger

  1. Add a Webhook node to a workflow.
  2. Choose POST as the HTTP method and set a stable path, for example capture-page. POST is convenient when the caller sends the page URL in a JSON body.
  3. Set the response mode to Using Respond to Webhook node.
  4. During development, select Listen for Test Event and use the displayed test URL. After publishing the workflow, use its production URL. n8n registers the production webhook URL when the workflow is published. n8n Webhook documentation

Send a test request with a URL in the JSON body:

curl -X POST 'YOUR_N8N_WEBHOOK_URL' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com"}' \
  -o capture.png

Inspect the Webhook node’s execution data to see where your n8n version exposes the incoming URL. The payload shape can depend on the request and node configuration. In common JSON-body setups it is available as body.url; use the expression picker to select the actual field shown by your execution.

2. Validate and constrain the target URL

Treat the requested URL as untrusted input. Before calling a browser service, require a URL, allow only the schemes and destinations your use case needs, and reject malformed values. If the service should capture only your own sites, enforce an explicit hostname allowlist. Authentication on the webhook does not by itself make arbitrary URL fetching safe.

Add an If or validation step after the Webhook node if you need to reject missing or disallowed values. Route invalid requests to an error response rather than passing them on to the screenshot service. Keep the Browserless credential out of caller-controlled input; configure it in the HTTP Request node or its credential settings.

n8n supports Basic, Header, and JWT authentication for webhooks, plus IP allowlists and CORS allowed-origin settings. Use authentication when the endpoint is reachable outside a controlled private network, and apply an IP allowlist where the caller has stable egress addresses. CORS governs browser-origin access; it is not a substitute for authenticating other clients. See the Webhook node documentation for the available controls.

3. Call a screenshot API from the HTTP Request node

Add an HTTP Request node after validation. Browserless documents a POST request to its /screenshot endpoint with a URL and capture options. Its screenshot endpoint returns image bytes; its example uses PNG and full-page capture. Follow the endpoint’s current authentication and request requirements when configuring your Browserless account.

Configure the request with:

  • Method: POST
  • URL: your Browserless /screenshot endpoint
  • Body content type: JSON
  • Body: the target URL from the Webhook item and the desired options
  • Response: file or binary response, saved to a named binary property such as data

Use the expression picker for the URL field. For example, if the execution data shows the request body under body, the expression may be {{$json.body.url}}. The exact expression and response option labels vary by n8n version; confirm the field path and binary property in the node’s execution data.

A representative Browserless JSON body is:

{
  "url": "https://example.com/",
  "options": {
    "fullPage": true,
    "type": "png"
  }
}

Browserless documents the screenshot request and options in its Screenshot API reference. The body above illustrates the documented shape; add the service’s required authentication as configured for your endpoint. Do not put a secret in the URL supplied by the webhook caller.

4. Return the screenshot bytes to the caller

  1. Add a Respond to Webhook node after the HTTP Request node.
  2. Choose Binary File as the response type.
  3. Set the input data property to the binary property produced by the HTTP Request node, for example data.
  4. Connect the successful screenshot path to this node, and provide an error path for invalid input or failed captures if your workflow needs a controlled error response.

The exact labels for saving an HTTP response as a file or binary property can differ across n8n versions. Run a test execution and confirm that the HTTP Request output contains binary data, then set Respond to Webhook to that property. n8n’s node returns a binary file to the webhook caller when configured this way. Respond to Webhook documentation

Respond to Webhook uses the first incoming item for a request. If a workflow creates multiple screenshot items, split them into separate requests or return a deliberate archive or metadata response using a design suited to multiple results. Make sure every expected branch reaches a response node: n8n documents a standard 200 response if the workflow ends without executing Respond to Webhook, and a 500 response if an error occurs before its first execution.

5. Test the complete request

  1. With the workflow listening for a test event, send a known public page URL to the test webhook.
  2. Inspect each node’s input and output. Confirm the target URL was parsed correctly and the screenshot API returned binary data.
  3. Check the response’s content type and open the downloaded file as an image. Browserless documents an image response with Content-Type: image/png for PNG captures.
  4. Publish the workflow and repeat the request against the production URL.
  5. Test a slow or dynamic page separately, with a readiness condition appropriate to that page.

This workflow is an assembly of documented n8n and Browserless components. The exact node UI and binary output property depend on the installed version, so verify those settings in your own execution data.

Capture options that matter

Need What to configure When to use it
Visible viewport Leave full-page capture off When the caller needs only what fits in the browser viewport.
Whole document Set fullPage: true For a long page capture. Confirm the selected API supports the page dimensions you need.
One element Use Browserless’ top-level selector option For a chart, report, or other specific element. The selector must match after the page renders.
Wait for dynamic content Wait for a selector, event, function, or timeout supported by the API Choose a readiness signal tied to the content instead of adding an unnecessarily long fixed delay.
Lazy-loaded content Enable Browserless’ scrollPage: true, optionally with full-page capture When images or sections appear only as the page scrolls.
Image format Set the supported output type, such as PNG Match the caller’s needs and the endpoint’s documented options.

Browserless documents selector, event, function, and timeout waiting options, along with scrolling the page to trigger lazy content. See its Screenshot API reference for the current parameter details. A CAPTCHA, access-denied page, or blank result may reflect the site’s access policy or automation defenses; no screenshot service can guarantee access to every site.

cURL, Python, and Node.js callers

These examples call the n8n webhook and save its binary response. Replace the webhook URL with the test or production URL shown by your workflow.

cURL

curl -X POST 'YOUR_N8N_WEBHOOK_URL' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com"}' \
  -o capture.png

Python

import requests

webhook_url = "YOUR_N8N_WEBHOOK_URL"
response = requests.post(
    webhook_url,
    json={"url": "https://example.com"},
    timeout=120,
)
response.raise_for_status()

content_type = response.headers.get("Content-Type", "")
if not content_type.startswith("image/"):
    raise ValueError(f"Expected an image response, got {content_type!r}: {response.text[:500]}")

with open("capture.png", "wb") as image_file:
    image_file.write(response.content)

Node.js

const response = await fetch('YOUR_N8N_WEBHOOK_URL', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'https://example.com' }),
  signal: AbortSignal.timeout(120_000),
});

if (!response.ok) {
  throw new Error(`Webhook returned ${response.status}: ${await response.text()}`);
}

const contentType = response.headers.get('content-type') || '';
if (!contentType.startsWith('image/')) {
  throw new Error(`Expected an image response, got ${contentType}`);
}

const image = Buffer.from(await response.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('capture.png', image));

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. Your n8n HTTP Request node can call it directly with one GET request; put the access key in protected node configuration, and map the incoming webhook URL to the url parameter. See the ScreenshotNeo API documentation for request and response details.

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 returned ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
  • Cookie and consent banners are accepted and removed before capture; the service also removes known newsletter popups and chat widgets.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Responses include page-verdict and billing headers.
  • An MCP server lets AI agents use screenshot, page-info, and PDF-capture tools.
  • The free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.

Sign up for ScreenshotNeo free: 1,000 screenshots a month, no card required.

Security, reliability, and operating cost

Protect the webhook and the destination

Require webhook authentication for endpoints exposed beyond a private network. Limit allowed caller IPs when practical, and use a destination allowlist if callers should not be able to request arbitrary sites. Decide how to handle redirects and private or internal network destinations in the architecture you deploy; the reviewed n8n webhook documentation does not establish a complete SSRF-safe design. Keep screenshot-service credentials in n8n’s protected configuration rather than in the request body supplied by a caller.

Plan for binary size and timeouts

n8n documents a default maximum webhook payload size of 16 MB and says self-hosted instances can change it with N8N_PAYLOAD_SIZE_MAX. Large screenshots and slow captures can also encounter limits imposed by the screenshot service, n8n hosting plan, execution timeout, or binary-data storage configuration. Check the limits for your installed n8n version and hosting plan before relying on large images or high throughput.

Handle failures explicitly

Use an error branch or workflow error handling for invalid URLs, upstream timeouts, service errors, and sites that block automation. Return a clear non-image error response for failed captures so callers do not save an error body with a .png extension. For long-running work or many pages, consider an asynchronous design that returns a job identifier and stores or delivers the result separately; a synchronous webhook must remain open while the screenshot is rendered.

Estimate cost from actual captures

The Browserless path has a service cost determined by that provider’s current plan and usage terms, plus any n8n hosting or execution charges. Check current provider pricing before production use. ScreenshotNeo’s listed plans range from 1,000 free captures per month to paid tiers from $5 for 3,000; only clean shots are billed, and the response reports verdict and billing information. Yearly billing gives two months free.

Troubleshooting

Symptom Likely cause What to check
Webhook returns 404 or does not trigger Using the production URL before publishing, a wrong path or method, or using the test URL when the workflow is not listening. Use the displayed test URL while listening; publish the workflow for production and verify the method and path.
Screenshot request has no target URL The expression points to the wrong incoming-data field. Inspect Webhook execution data and select the actual URL field with the expression picker.
HTTP Request returns an error Incorrect endpoint, missing or invalid service authentication, malformed JSON, or an upstream service failure. Check the provider’s current endpoint and authentication instructions, then inspect the node’s status and response body without exposing credentials.
Caller receives JSON or text instead of an image The HTTP Request node did not save its response as binary, the wrong binary property was selected, or an error body was returned. Inspect the HTTP Request output for its binary property and set Respond to Webhook to that exact property. Check response content type and status.
Caller receives an empty file or unexpected 200 The workflow may have ended without reaching Respond to Webhook. Trace each execution branch and ensure every intended outcome reaches a response node; n8n documents a standard 200 when the workflow finishes without executing it.
Response is 500 An error occurred before Respond to Webhook executed, or the response node configuration failed. Inspect the failed node and execution details; handle the failure path and verify the selected binary property.
Page is blank or incomplete Rendering was not ready, the page needs scrolling for lazy content, or the site blocks automated access. Wait for a relevant selector or supported readiness condition, enable scrolling where appropriate, and check whether the site permits automated access.
Capture is clipped or too large Viewport capture was used instead of full-page, or full-page dimensions exceed service or workflow limits. Choose the appropriate capture scope and verify endpoint and deployment limits. Consider capturing a specific element.
Only one result is returned for multiple items Respond to Webhook uses the first incoming item for a request. Use one request per screenshot or design an explicit multi-result response.

Frequently asked questions

Can the webhook accept a URL as a query parameter?

Yes, if you choose a GET request and map the query parameter shown in Webhook execution data. POST with JSON is often easier to extend and avoids putting the target URL in the request line and logs.

Can I return a PDF instead?

That depends on the screenshot service endpoint and the output it supports. Configure the HTTP Request node to retain the returned file as binary and set the response content type and filename appropriately for the chosen endpoint.

Why use a screenshot API instead of downloading the webpage?

A screenshot represents a rendered browser page. A basic download returns the server’s response content and does not, by itself, execute the page’s JavaScript or produce a visual image.

Can this capture every website?

No. A site can require authentication, block automation, present a CAPTCHA, or depend on content unavailable to the browser service. Follow the site’s access rules and test the particular pages your workflow needs.