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 withn8n import:workflowand ran it withn8n 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.webpin 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
- In the Screenshot node, open Header Auth and create a credential. Set Name to
Authorizationand Value toBearer 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. - 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. - Change Bucket Name from
screenshotsto 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 includedx-screenshot-title,x-credits-used,x-credits-remainingandx-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 withdecodeURIComponent()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=trueand 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 |