n8n Screenshot Workflow: HTTP Request to S3

Capture website screenshots in n8n with the HTTP Request node and save them to S3. Importable workflow JSON, binary data settings, retries and error output.

By Simon Chiu · Updated

n8n has no screenshot node, and it does not need one. The built-in HTTP Request node can call the RenderScreenshot API, receive the image as binary data and hand it to the S3 node in the same run. This page gives you a workflow file to import, the settings that matter for binary data, and the error branch that keeps one bad URL from stopping a whole list. For Zapier and Make, start at the automation overview; every integration is listed on the integrations hub.

Last tested: 2026-10-18 with n8n 2.43.7 (Docker image n8nio/n8n:2.43.7). We imported the JSON below with n8n import:workflow and ran it with n8n execute. The HTTP Request node called a local stub that returns the API's documented headers and error JSON, and the S3 node wrote to a local MinIO bucket. No request went to the live API, and the page has no n8n UI screenshots yet.

What you can build

  • A dated archive of a page. A Schedule Trigger fires each morning, and the workflow stores example.com/2026-10-18.webp in your bucket. One object per day gives you a visual history of a pricing or terms page.
  • Thumbnails for new records. A Postgres, Airtable or webhook trigger sends a URL. The workflow captures it, uploads the file, and a later node writes the object key back to the record.
  • A failure list you can act on. URLs that do not render go to a second branch with the HTTP status and the API's error code, ready for a Slack message or a Google Sheet.

Prerequisites

  • n8n Cloud or self-hosted n8n. We tested on 2.43.7; the node versions in the file (HTTP Request 4.2, Edit Fields 3.4, S3 1) are also available in recent 1.x releases.
  • A RenderScreenshot API key that starts with rs_live_. Create a free account to get one.
  • An S3-compatible bucket and an access key that can write to it: AWS S3, Cloudflare R2, MinIO and others work with the generic S3 node.

Import the workflow

Copy the JSON, open an empty workflow in n8n and press Ctrl+V (Cmd+V on macOS), or save it as a file and use Import from File. Then open each node that shows a warning and pick your own credentials.

{
  "name": "RenderScreenshot to S3",
  "nodes": [
    { "parameters": {}, "id": "8d0c2a51-1f0e-4a8e-9c61-0b7e3f2a1001", "name": "Run manually",
      "type": "n8n-nodes-base.manualTrigger", "typeVersion": 1, "position": [0, 0] },
    { "parameters": { "assignments": { "assignments": [
        { "id": "a1", "name": "url", "value": "https://example.com", "type": "string" } ] }, "options": {} },
      "id": "8d0c2a51-1f0e-4a8e-9c61-0b7e3f2a1002", "name": "Page to capture",
      "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [220, 0] },
    { "parameters": {
        "url": "https://api.renderscreenshot.com/v1/screenshot",
        "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": { "parameters": [
          { "name": "url", "value": "={{ $json.url }}" },
          { "name": "preset", "value": "desktop_hd" },
          { "name": "format", "value": "webp" },
          { "name": "block_cookies", "value": "true" },
          { "name": "cache_available", "value": "true" } ] },
        "options": {
          "response": { "response": { "fullResponse": true, "responseFormat": "file", "outputPropertyName": "screenshot" } },
          "timeout": 70000 } },
      "id": "8d0c2a51-1f0e-4a8e-9c61-0b7e3f2a1003", "name": "Screenshot",
      "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [440, 0],
      "retryOnFail": true, "maxTries": 3, "waitBetweenTries": 5000, "onError": "continueErrorOutput",
      "credentials": { "httpHeaderAuth": { "id": "rsHeaderAuth01", "name": "RenderScreenshot API key" } } },
    { "parameters": {
        "operation": "upload", "bucketName": "screenshots",
        "fileName": "={{ $('Page to capture').item.json.url.replace(/^https?:\\/\\//, '').replace(/[^a-z0-9.-]+/gi, '-') }}/{{ $now.toFormat('yyyy-MM-dd') }}.webp",
        "binaryPropertyName": "screenshot", "additionalFields": {} },
      "id": "8d0c2a51-1f0e-4a8e-9c61-0b7e3f2a1004", "name": "Upload to S3",
      "type": "n8n-nodes-base.s3", "typeVersion": 1, "position": [680, -100],
      "credentials": { "s3": { "id": "rsS3Bucket0001", "name": "S3 bucket" } } },
    { "parameters": { "assignments": { "assignments": [
        { "id": "b1", "name": "failed_url", "value": "={{ $('Page to capture').item.json.url }}", "type": "string" },
        { "id": "b3", "name": "status", "value": "={{ $json.error.status }}", "type": "number" },
        { "id": "b2", "name": "reason", "value": "={{ $json.error.message }}", "type": "string" } ] }, "options": {} },
      "id": "8d0c2a51-1f0e-4a8e-9c61-0b7e3f2a1005", "name": "Record failure",
      "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [680, 100] }
  ],
  "connections": {
    "Run manually": { "main": [[{ "node": "Page to capture", "type": "main", "index": 0 }]] },
    "Page to capture": { "main": [[{ "node": "Screenshot", "type": "main", "index": 0 }]] },
    "Screenshot": { "main": [
      [{ "node": "Upload to S3", "type": "main", "index": 0 }],
      [{ "node": "Record failure", "type": "main", "index": 0 }] ] }
  },
  "settings": { "executionOrder": "v1" },
  "pinData": {}
}

Set up the two credentials

  1. In the Screenshot node, open Header Auth and create a credential. Set Name to Authorization and Value to Bearer rs_live_.... Do not put the key in a query parameter: n8n saves the full request URL in each execution, and anyone who can open the execution log would see it.
  2. In the Upload to S3 node, create an S3 credential. For AWS, the endpoint is your region's S3 endpoint. For MinIO, turn on Force Path Style. For Cloudflare R2, use the account's R2 endpoint and the region auto.
  3. Change Bucket Name from screenshots to your bucket, then run the workflow once with Execute workflow.

How the HTTP Request node is set up

Three options decide whether the S3 node gets a file it can use:

  • Response Format: File. Without it, n8n tries to read the image as text or JSON. The API returns raw image bytes when you do not send Accept: application/json, so the node must treat the body as a file.
  • Put Output in Field: screenshot. This is the binary field name. The S3 node's Input Binary Field must use the same name.
  • Include Response Headers and Status (fullResponse). The headers then appear in the item's JSON next to the binary data. In our run they included x-screenshot-title, x-credits-used, x-credits-remaining and x-request-id, so a later node can name the file after the page title or log the credits left. Titles with non-ASCII characters arrive percent-encoded; decode them with decodeURIComponent() in an expression.

In our test, n8n 2.43.7 stored the binary data on disk by default (filesystem-v2 in the execution data), not in memory. That matters for long full-page captures: memory mode keeps every file of the run in the n8n process.

Parameter mapping

Each query parameter in the node maps to a flat name of the GET endpoint:

n8n field Name Value in the file Effect
Query Parameters url {{ $json.url }} Page to capture. Must start with http:// or https://.
Query Parameters preset desktop_hd 1920×1080 PNG settings. See presets.
Query Parameters format webp Overrides the preset's format. Keep the S3 file extension in step.
Query Parameters block_cookies true Removes cookie banners. Only the word true turns it on.
Query Parameters cache_available true Reuses an identical render from the cache TTL for 0 credits.
Header Auth Authorization Bearer rs_live_... Your API key.
Options Timeout 70000 Longer than the API's longest page wait (60 s).

Options that have no GET name, such as waiting for a selector or injecting CSS, need a POST with a JSON body. Change the method to POST, turn on Send Body with JSON, and use the nested names from the parameter reference.

Errors and retries in n8n

The Screenshot node has Retry On Fail on (3 tries, 5 seconds apart) and On Error set to Continue (using error output). A failed URL leaves the node through its second output instead of stopping the run. In our test with a page that timed out, the node tried three times and then sent this item to Record failure:

{ "failed_url": "https://timeout.example.com", "status": 422,
  "reason": "422 - \"{\"error\":{\"type\":\"target_error\",\"code\":\"timeout\",...}}\"" }

Two things we saw that are worth knowing:

  • n8n retries every error. It sent a request with url=example.com (no scheme) three times, although the API answers that with a 400 that will never succeed. Failed renders use no credit, but every try counts toward your account's per-minute limit.
  • Retries are short. A 429 means the account's one-minute window is full, and a 5-second wait rarely clears it. Read the rate limit rules, and see the error code list for which codes are worth a second try.

Limits and costs

  • Credits. One credit per fresh render. Cache hits from cache_available=true and failed renders cost 0. The pricing page lists the credits on each plan.
  • Rate limit. Per account, shared by all keys, from 10 requests a minute on the free plan. For a list of URLs, put a Loop Over Items node with a small batch size and a Wait node before the Screenshot node.
  • n8n executions. On n8n Cloud, one run of the workflow is one execution, however many nodes it has.
  • Large files. Full-page captures of long pages are big. WebP or JPEG keeps them smaller than PNG.

If you are on a paid plan, the API can copy each render into your bucket itself, with no S3 node at all. Configure custom storage once; a per-request storage.path must contain {hash} and {ext}.

Troubleshooting

Symptom Cause Fix
S3 node: no binary data Field names differ Use screenshot in both nodes
The file in S3 is JSON An Accept: application/json header was added Remove it, or switch to the JSON flow and save image.url
401 with missing_credentials Header value without Bearer Set the value to Bearer rs_live_...
400 with invalid_url The trigger sent a bare domain Prefix https:// in the Edit Fields node
Same page, a new credit each run cache_available missing Add it, or set cache_ttl for a longer reuse window
The image shows a cookie wall Banner not in the block list See blocking cookie banners

Frequently asked questions

Do I need a community node to take screenshots in n8n?
No. The built-in HTTP Request node calls the screenshot API and stores the image as binary data. Because nothing is installed, the same workflow runs on n8n Cloud and on self-hosted n8n.
Why does the S3 node say there is no binary data?
The S3 node reads the field named in Input Binary Field, and it must match the HTTP Request node's Put Output in Field option. In the workflow on this page both are set to screenshot.
Does n8n's Retry On Fail spend extra credits?
No. A failed render uses no credit. But n8n retries every error, including a 400 for a bad URL, and each try counts against your per-minute rate limit, so keep Max Tries low.

Related in this topic

Try RenderScreenshot free

150 free credits every month, no credit card required.