How to Solve Cloudflare Challenge in n8n with CapSolver

Ethan Collins
Pattern Recognition Specialist
12-Mar-2026

Cloudflare's bot protection goes far beyond CAPTCHA widgets. The Cloudflare Challenge — the full-page "Verifying your browser…" screen that blocks access to a site entirely — is one of the most aggressive bot defenses on the web. It runs a full JavaScript challenge in a real browser environment, checks behavioral signals, and fingerprints your TLS connection before it ever lets you through.
Standard automation tools fail here. Not because they can't solve the challenge, but because Cloudflare fingerprints the TLS handshake itself — and any non-browser HTTP client gets blocked before the challenge is even served, or re-challenged immediately after, even with a valid cf_clearance cookie.
In this guide, you'll learn how to build a Cloudflare Challenge scraper in n8n that actually works — combining CapSolver to solve the challenge, a local Go TLS server to spoof Chrome's TLS fingerprint, and an n8n workflow to tie it all together.
What you'll build:
- A dual-trigger workflow (schedule + webhook) that bypasses Cloudflare Bot Management
- A lightweight Go server that makes HTTP requests with a real Chrome TLS fingerprint
- A reusable scraper template you can point at any CF-protected site
- Use-case workflows for scraping, account login, and a standalone challenge solver API — all behind Cloudflare Challenge
What Is the Cloudflare Challenge?
The Cloudflare Challenge (also called the JS challenge or Bot Management challenge) is a full-page interstitial that Cloudflare injects before a visitor can access a protected site. You've seen it: a black or white screen with "Verifying your browser…" or "Just a moment…" and a loading bar or Cloudflare logo.
Unlike Turnstile — which is a small widget embedded inside a page — the Cloudflare Challenge takes over the entire page. You cannot access any content until it completes.
| Cloudflare Challenge | Cloudflare Turnstile | |
|---|---|---|
| Where it appears | Full-page interstitial — blocks site access entirely | Embedded widget inside a page (e.g., login form) |
| What it looks like | "Verifying your browser…" loading screen | A small checkbox or invisible widget in a form |
| Who adds it | Cloudflare adds it automatically based on security rules | The website owner embeds it in their HTML |
| Solving approach | AntiCloudflareTask — requires a proxy |
AntiTurnstileTaskProxyLess — no proxy needed |
| Cookie returned | cf_clearance (domain-specific, IP-bound) |
Turnstile token (short-lived, used once) |
| Proxy required? | Yes — same IP must be used for solve and fetch | No |
If you see an embedded checkbox or widget inside a form, that's Turnstile — not this challenge. Check the CapSolver guide on identifying challenge types if you're unsure.
Why Standard HTTP Clients Fail
Here's the problem that most guides skip over: Cloudflare checks your TLS fingerprint, not just your cookies.
When a browser connects to a website over HTTPS, it sends a TLS ClientHello that includes details about its supported cipher suites, extensions, and settings. Cloudflare records this fingerprint (called a JA3 or JA4 fingerprint) and compares it to known browser profiles.
Go's net/http, Python's requests, curl, and most HTTP libraries all have distinct TLS fingerprints. Even if CapSolver successfully solves the challenge and returns a valid cf_clearance cookie, Cloudflare will re-challenge or block the request if it detects a non-browser TLS fingerprint on the subsequent fetch.
The fix: a Go server using httpcloak — a library that spoofs a real Chrome TLS stack including:
- JA3 / JA4 fingerprint
- HTTP/2 SETTINGS frames
- ALPN negotiation
- Header ordering and values
This makes the fetch look exactly like a Chrome browser request at the network level.
Prerequisites
| Requirement | Notes |
|---|---|
| n8n self-hosted | Required — the TLS server must run on the same machine as n8n. n8n Cloud is not suitable for this use case. |
| CapSolver account | Sign up here and get your API key |
| Go 1.21+ | Must be installed on the n8n server. Check with go version. |
| Residential or mobile proxy | Datacenter proxies will fail on most Cloudflare-protected sites. See Proxy Requirements below. |
Setting Up CapSolver in n8n
CapSolver is available as an official integration in n8n — no community node installation required.
Step 1: Open the Credentials Page
Go to your n8n instance and navigate to Settings → Credentials.

Step 2: Create the CapSolver Credential
- Click Create credential (top right)
- Search for "CapSolver" and select CapSolver API
- Enter your API Key from the CapSolver Dashboard
- Leave Allowed HTTP Request Domains set to
All - Click Save
You should see a green "Connection tested successfully" banner.

Important: Every CapSolver node in your workflows will reference this credential. You only need to create it once — all your solver workflows will share the same credential.
Step 1 — Build the TLS Server
This Go server receives fetch requests from n8n and executes them using httpcloak's Chrome TLS profile. It's a small, self-contained binary that you run alongside n8n.
Create the source file
Create a directory and save the following as main.go:
bash
mkdir -p ~/tls-server && cd ~/tls-server
go
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
"github.com/sardanioss/httpcloak/client"
)
type FetchRequest struct {
URL string `json:"url"`
Method string `json:"method"`
Headers map[string]string `json:"headers"`
Proxy string `json:"proxy"`
Body string `json:"body"`
}
type FetchResponse struct {
Status int `json:"status"`
Body string `json:"body"`
Headers map[string][]string `json:"headers"`
}
type ErrorResponse struct {
Error string `json:"error"`
}
func writeError(w http.ResponseWriter, status int, msg string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(ErrorResponse{Error: msg})
}
func fetchHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeError(w, http.StatusMethodNotAllowed, "only POST allowed")
return
}
var req FetchRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid JSON: "+err.Error())
return
}
if req.URL == "" {
writeError(w, http.StatusBadRequest, "url is required")
return
}
if req.Method == "" {
req.Method = "GET"
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
c := client.NewClient("chrome-145", client.WithTimeout(60*time.Second))
defer c.Close()
if req.Proxy != "" {
c.SetProxy(req.Proxy)
}
// Extract user-agent separately so httpcloak uses it instead of its preset value.
headers := make(map[string][]string, len(req.Headers))
var userAgent string
for k, v := range req.Headers {
lower := strings.ToLower(k)
if lower == "user-agent" {
userAgent = v
} else {
headers[k] = []string{v}
}
}
var bodyReader io.Reader
if req.Body != "" {
bodyReader = strings.NewReader(req.Body)
}
hcReq := &client.Request{
Method: strings.ToUpper(req.Method),
URL: req.URL,
Headers: headers,
Body: bodyReader,
UserAgent: userAgent,
FetchMode: client.FetchModeNavigate,
}
resp, err := c.Do(ctx, hcReq)
if err != nil {
writeError(w, http.StatusBadGateway, "fetch failed: "+err.Error())
return
}
body, err := resp.Text()
if err != nil {
writeError(w, http.StatusInternalServerError, "read body failed: "+err.Error())
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(FetchResponse{
Status: resp.StatusCode,
Body: body,
Headers: resp.Headers,
})
}
func main() {
const port = "7878"
mux := http.NewServeMux()
mux.HandleFunc("/fetch", fetchHandler)
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{"status":"ok"}`)
})
log.Printf("TLS server (httpcloak chrome-145) listening on :%s", port)
log.Fatal(http.ListenAndServe(":"+port, mux))
}
Initialize and build
bash
go mod init tls-server
go get github.com/sardanioss/httpcloak/client
go build -o main main.go
Run the server
bash
./main
Verify it's running (in a new terminal)
bash
curl http://localhost:7878/health
Expected: {"status":"ok"}
Note: The TLS server must run on the same machine as your n8n instance. The n8n workflow calls it at
http://localhost:7878/fetch. If you're using n8n Cloud, you would need a self-hosted setup — this is one reason self-hosted n8n is strongly recommended for Cloudflare Challenge scraping.
Step 2 — Allow n8n to Call Localhost
By default, n8n blocks HTTP Request nodes from calling localhost addresses (SSRF protection). You need to disable this restriction.
Add the N8N_BLOCK_ACCESS_TO_LOCALHOST=false environment variable and restart your n8n instance. How you do this depends on how you run n8n:
If you run n8n directly:
bash
export N8N_BLOCK_ACCESS_TO_LOCALHOST=false
n8n start
If you use Docker:
Add -e N8N_BLOCK_ACCESS_TO_LOCALHOST=false to your docker run command, or add it to the environment section in your docker-compose.yml.
Workflow: Cloudflare Challenge Solver API
This workflow creates a POST endpoint that accepts a Cloudflare-protected URL and proxy, solves the challenge via CapSolver, and returns the raw cf_clearance cookie and userAgent. No TLS server needed — your application handles the fetch.
How It Works
Webhook (POST /solver-cloudflare-challenge) → Cloudflare Challenge (CapSolver)
→ Format Solution → Respond to Webhook
4 nodes, webhook-only, no schedule path, no TLS server dependency.
- Webhook — Receives POST requests with
websiteURLandproxy - Cloudflare Challenge — CapSolver solves the challenge using
AntiCloudflareTask - Format Solution — Serializes
cookiesobject to a cookie string, handles errors viacontinueOnFail - Respond to Webhook — Returns
cf_clearance, serialized cookie string, anduserAgent
Node Configuration
1. Webhook Node
| Setting | Value |
|---|---|
| HTTP Method | POST |
| Path | solver-cloudflare-challenge |
| Respond | Response Node |
This creates an endpoint at: https://your-n8n-instance.com/webhook/solver-cloudflare-challenge
2. CapSolver Node (Cloudflare Challenge)
| Parameter | Value | Description |
|---|---|---|
| Operation | Cloudflare Challenge |
Selects AntiCloudflareTask |
| Type | AntiCloudflareTask |
Full-page Cloudflare Challenge |
| Website URL | ={{ $json.body.websiteURL }} |
The Cloudflare-protected URL |
| Proxy | ={{ $json.body.proxy }} |
Residential proxy in host:port:user:pass format |
| Continue On Fail | true |
Returns structured errors instead of crashing |
CapSolver launches a real browser through your proxy, loads the target URL, and solves the Cloudflare challenge. When successful, it returns a solution object containing:
cookies— an object{ cf_clearance: "..." }with the clearance cookieuserAgent— the exact User-Agent string the browser used during the solve
Note: The field is
websiteURL(nottargetURL) — matching the field name used by all other Solver APIs and the CapSolver node itself.
3. Format Solution (Code Node)
This node is needed because AntiCloudflareTask returns cookies as an object ({ cf_clearance: "..." }), not a simple token string like reCAPTCHA or Turnstile. It serializes the cookie, extracts cf_clearance, and returns a structured error if CapSolver failed.
javascript
const input = $input.first().json;
if (input.error || !input.data || !input.data.solution) {
const errorMsg = input.error
? (input.error.message || JSON.stringify(input.error))
: 'No solution returned — site may not be showing a challenge';
return [{ json: { success: false, error: errorMsg } }];
}
const solution = input.data.solution;
const cookies = solution.cookies;
const cfClearance = (cookies && typeof cookies === 'object')
? (cookies.cf_clearance || '') : '';
const cookieString = (cookies && typeof cookies === 'object')
? Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ')
: (cookies || '');
return [{ json: {
success: true,
cf_clearance: cfClearance,
cookies: cookieString,
userAgent: solution.userAgent || '',
solvedAt: new Date().toISOString()
}}];
4. Respond to Webhook
| Setting | Value |
|---|---|
| Respond With | JSON |
| Response Body | ={{ JSON.stringify($json) }} |
Test It
bash
curl -X POST https://your-n8n-instance.com/webhook/solver-cloudflare-challenge \
-H "Content-Type: application/json" \
-d '{
"websiteURL": "https://protected-site.com",
"proxy": "host:port:user:pass"
}'
Successful response:
json
{
"success": true,
"cf_clearance": "abc123...",
"cookies": "cf_clearance=abc123...",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/145.0.0.0 ...",
"solvedAt": "2026-03-11T12:00:00.000Z"
}
Failed response (no challenge found, bad proxy, etc.):
json
{
"success": false,
"error": "No solution returned — site may not be showing a challenge"
}
Import This Workflow
Copy the JSON below and import it into n8n via Menu → Import from JSON. After importing, select your CapSolver credential in the Cloudflare Challenge node.
Click to expand workflow JSON
json
{
"name": "Cloudflare Challenge — Solver API",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "solver-cloudflare-challenge",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [-208, 0],
"id": "cf770001-7777-7777-7777-777777777701",
"name": "Webhook",
"webhookId": "cf770001-aaaa-bbbb-cccc-777777777701"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"type": "AntiCloudflareTask",
"websiteURL": "={{ $json.body.websiteURL }}",
"proxy": "={{ $json.body.proxy }}",
"userAgent": "={{ $json.body.userAgent }}",
"html": "={{ $json.body.html }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [112, 0],
"id": "cf770001-7777-7777-7777-777777777702",
"name": "Cloudflare Challenge",
"credentials": {
"capSolverApi": {
"id": "YOUR_CREDENTIAL_ID",
"name": "CapSolver account"
}
},
"continueOnFail": true
},
{
"parameters": {
"jsCode": "const input = $input.first().json;\n\nif (input.error || !input.data || !input.data.solution) {\n const errorMsg = input.error\n ? (input.error.message || JSON.stringify(input.error))\n : 'No solution returned — site may not be showing a challenge';\n return [{ json: { success: false, error: errorMsg } }];\n}\n\nconst solution = input.data.solution;\nconst cookies = solution.cookies;\nconst cfClearance = (cookies && typeof cookies === 'object') ? (cookies.cf_clearance || '') : '';\nconst cookieString = (cookies && typeof cookies === 'object')\n ? Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ')\n : (cookies || '');\n\nreturn [{ json: {\n success: true,\n cf_clearance: cfClearance,\n cookies: cookieString,\n userAgent: solution.userAgent || '',\n solvedAt: new Date().toISOString()\n}}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [400, 0],
"id": "cf770001-7777-7777-7777-777777777703",
"name": "Format Solution"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [700, 0],
"id": "cf770001-7777-7777-7777-777777777704",
"name": "Respond to Webhook"
}
],
"connections": {
"Webhook": {
"main": [[{ "node": "Cloudflare Challenge", "type": "main", "index": 0 }]]
},
"Cloudflare Challenge": {
"main": [[{ "node": "Format Solution", "type": "main", "index": 0 }]]
},
"Format Solution": {
"main": [[{ "node": "Respond to Webhook", "type": "main", "index": 0 }]]
}
},
"active": false,
"settings": { "executionOrder": "v1" }
}
Workflow: Using Cloudflare Challenge Solutions
So far, the Solver API above shows how to get a solved cf_clearance cookie and userAgent. But what do you actually do with them?
Unlike reCAPTCHA or Turnstile where you submit a token in a form field, the Cloudflare Challenge returns a cookie (cf_clearance) that must be sent as a header on every subsequent request. The cookie is bound to the proxy IP and User-Agent used during the solve — both must match exactly on the fetch.
Here's the general pattern:
- Solve the Cloudflare Challenge → Get the
cf_clearancecookie anduserAgentfrom CapSolver - Prepare the request → Build headers with the cookie, matching User-Agent, and Chrome-like
sec-ch-uaheaders - Fetch through the TLS server → Send the request via
http://localhost:7878/fetchto match Chrome's TLS fingerprint - Verify the response → Check if the site returned real content (status 200 with HTML) vs. a re-challenge page
- Process the result → Extract the data you need using the HTML node, Edit Fields, or Code node
Key concept: Standard HTTP clients fail here even with a valid
cf_clearancecookie — Cloudflare fingerprints the TLS handshake itself. The Go TLS server (httpcloak) makes the fetch look exactly like Chrome at the network level. Every workflow that fetches a Cloudflare-protected page must go through the TLS server.
Example: Cloudflare Challenge Scraper

Workflow Flow
Schedule path:
Every 6 Hours → Set Target Config [Schedule] → Solve Cloudflare Challenge
→ Prepare TLS Request → Fetch via TLS Server → Extract Result
Webhook path:
Webhook Trigger → Set Target Config [Webhook] → Solve Cloudflare Challenge
→ Prepare TLS Request → Fetch via TLS Server → Extract Result → Respond to Webhook
How It Works
- Set Target Config — Stores
targetURLandproxy(inhost:port:user:passformat). The Schedule path uses hardcoded values; the Webhook path reads them from the POST body. - Solve Cloudflare Challenge — CapSolver node with
onError: "continueRegularOutput"— continues even if the page isn't currently showing a challenge. - Prepare TLS Request — Code node that converts
host:port:user:passproxy tohttp://user:pass@host:portURL format, serializessolution.cookiesto a cookie header string, and builds Chrome-like request headers with the exactuserAgentfrom the solve. - Fetch via TLS Server — HTTP Request to
http://localhost:7878/fetchusingcontentType: "raw"(not"json"— n8n's JSON mode corrupts the body). - Extract Result — Pulls
status,body, andfetchedAtfrom the TLS server response. - Respond to Webhook — Returns the result as JSON (webhook path only).
Why
contentType: "raw"and not"json"? n8n'sjsoncontent type mode expects body parameters as key-value pairs. If you passJSON.stringify($json)as a string, n8n treats the whole string as a single malformed param and sends{"": ""}to the server. Usingrawmode sends the body exactly as the expression evaluates.
Click to expand workflow JSON
json
{
"name": "Cloudflare Challenge — CapSolver + Schedule + Webhook",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 6
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.3,
"position": [-400, 0],
"id": "cf111111-1111-1111-1111-111111111101",
"name": "Every 6 Hours"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "cfg-s-001",
"name": "targetURL",
"value": "https://YOUR_CF_PROTECTED_SITE.com",
"type": "string"
},
{
"id": "cfg-s-002",
"name": "proxy",
"value": "YOUR_PROXY_HOST:PORT:USER:PASS",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [-96, 0],
"id": "cf111111-1111-1111-1111-111111111102",
"name": "Set Target Config [Schedule]"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"type": "AntiCloudflareTask",
"websiteURL": "={{ $json.targetURL }}",
"proxy": "={{ $json.proxy }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [208, 0],
"id": "cf111111-1111-1111-1111-111111111103",
"name": "Solve Cloudflare Challenge [Schedule]",
"credentials": {
"capSolverApi": {
"id": "YOUR_CREDENTIAL_ID",
"name": "CapSolver account"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "const config = $('Set Target Config [Schedule]').first().json;\nconst capResult = $input.first().json;\n\nfunction toProxyURL(proxy) {\n if (!proxy) return '';\n if (proxy.startsWith('http')) return proxy;\n const parts = proxy.split(':');\n if (parts.length === 4) return `http://${parts[2]}:${parts[3]}@${parts[0]}:${parts[1]}`;\n return proxy;\n}\n\nlet cookieStr = '';\nlet ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36';\n\nif (capResult.data && capResult.data.solution) {\n const solution = capResult.data.solution;\n const cookies = solution.cookies;\n cookieStr = cookies && typeof cookies === 'object'\n ? Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ')\n : (cookies || '');\n if (solution.userAgent) ua = solution.userAgent;\n}\n\nconst chromeMatch = ua.match(/Chrome\\/(\\d+)/);\nconst chromeVer = chromeMatch ? chromeMatch[1] : '145';\nconst secChUa = `\"Chromium\";v=\"${chromeVer}\", \"Not A(Brand\";v=\"8\", \"Google Chrome\";v=\"${chromeVer}\"`;\n\nconst headers = {\n 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',\n 'accept-language': 'en-US,en;q=0.9',\n 'sec-ch-ua': secChUa,\n 'sec-ch-ua-mobile': '?0',\n 'sec-ch-ua-platform': '\"Windows\"',\n 'sec-fetch-dest': 'document',\n 'sec-fetch-mode': 'navigate',\n 'sec-fetch-site': 'none',\n 'sec-fetch-user': '?1',\n 'upgrade-insecure-requests': '1',\n 'user-agent': ua\n};\n\nif (cookieStr) headers['cookie'] = cookieStr;\n\nreturn [{ json: {\n url: config.targetURL,\n method: 'GET',\n proxy: toProxyURL(config.proxy),\n headers\n}}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [512, 0],
"id": "cf111111-1111-1111-1111-111111111104",
"name": "Prepare TLS Request [Schedule]"
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:7878/fetch",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify($json) }}",
"options": {
"timeout": 60000
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [800, 0],
"id": "cf111111-1111-1111-1111-111111111105",
"name": "Fetch via TLS Server [Schedule]"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "out-s-001",
"name": "status",
"value": "={{ $json.status }}",
"type": "number"
},
{
"id": "out-s-002",
"name": "body",
"value": "={{ $json.body }}",
"type": "string"
},
{
"id": "out-s-003",
"name": "fetchedAt",
"value": "={{ new Date().toISOString() }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1104, 0],
"id": "cf111111-1111-1111-1111-111111111106",
"name": "Extract Result [Schedule]"
},
{
"parameters": {
"httpMethod": "POST",
"path": "cloudflare-scraper",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [-400, 420],
"id": "cf111111-1111-1111-1111-111111111107",
"name": "Webhook Trigger",
"webhookId": "cf111111-aaaa-bbbb-cccc-111111111107",
"onError": "continueRegularOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "cfg-w-001",
"name": "targetURL",
"value": "={{ $json.body.targetURL }}",
"type": "string"
},
{
"id": "cfg-w-002",
"name": "proxy",
"value": "={{ $json.body.proxy }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [-96, 420],
"id": "cf111111-1111-1111-1111-111111111108",
"name": "Set Target Config [Webhook]"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"type": "AntiCloudflareTask",
"websiteURL": "={{ $json.targetURL }}",
"proxy": "={{ $json.proxy }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [208, 420],
"id": "cf111111-1111-1111-1111-111111111109",
"name": "Solve Cloudflare Challenge [Webhook]",
"credentials": {
"capSolverApi": {
"id": "YOUR_CREDENTIAL_ID",
"name": "CapSolver account"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "const config = $('Set Target Config [Webhook]').first().json;\nconst capResult = $input.first().json;\n\nfunction toProxyURL(proxy) {\n if (!proxy) return '';\n if (proxy.startsWith('http')) return proxy;\n const parts = proxy.split(':');\n if (parts.length === 4) return `http://${parts[2]}:${parts[3]}@${parts[0]}:${parts[1]}`;\n return proxy;\n}\n\nlet cookieStr = '';\nlet ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36';\n\nif (capResult.data && capResult.data.solution) {\n const solution = capResult.data.solution;\n const cookies = solution.cookies;\n cookieStr = cookies && typeof cookies === 'object'\n ? Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ')\n : (cookies || '');\n if (solution.userAgent) ua = solution.userAgent;\n}\n\nconst chromeMatch = ua.match(/Chrome\\/(\\d+)/);\nconst chromeVer = chromeMatch ? chromeMatch[1] : '145';\nconst secChUa = `\"Chromium\";v=\"${chromeVer}\", \"Not A(Brand\";v=\"8\", \"Google Chrome\";v=\"${chromeVer}\"`;\n\nconst headers = {\n 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',\n 'accept-language': 'en-US,en;q=0.9',\n 'sec-ch-ua': secChUa,\n 'sec-ch-ua-mobile': '?0',\n 'sec-ch-ua-platform': '\"Windows\"',\n 'sec-fetch-dest': 'document',\n 'sec-fetch-mode': 'navigate',\n 'sec-fetch-site': 'none',\n 'sec-fetch-user': '?1',\n 'upgrade-insecure-requests': '1',\n 'user-agent': ua\n};\n\nif (cookieStr) headers['cookie'] = cookieStr;\n\nreturn [{ json: {\n url: config.targetURL,\n method: 'GET',\n proxy: toProxyURL(config.proxy),\n headers\n}}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [512, 420],
"id": "cf111111-1111-1111-1111-111111111110",
"name": "Prepare TLS Request [Webhook]"
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:7878/fetch",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify($json) }}",
"options": {
"timeout": 60000
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [800, 420],
"id": "cf111111-1111-1111-1111-111111111111",
"name": "Fetch via TLS Server [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "out-w-001",
"name": "status",
"value": "={{ $json.status }}",
"type": "number"
},
{
"id": "out-w-002",
"name": "body",
"value": "={{ $json.body }}",
"type": "string"
},
{
"id": "out-w-003",
"name": "fetchedAt",
"value": "={{ new Date().toISOString() }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1104, 420],
"id": "cf111111-1111-1111-1111-111111111112",
"name": "Extract Result [Webhook]"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [1408, 420],
"id": "cf111111-1111-1111-1111-111111111113",
"name": "Respond to Webhook"
}
],
"connections": {
"Every 6 Hours": {
"main": [[{"node": "Set Target Config [Schedule]", "type": "main", "index": 0}]]
},
"Set Target Config [Schedule]": {
"main": [[{"node": "Solve Cloudflare Challenge [Schedule]", "type": "main", "index": 0}]]
},
"Solve Cloudflare Challenge [Schedule]": {
"main": [[{"node": "Prepare TLS Request [Schedule]", "type": "main", "index": 0}]]
},
"Prepare TLS Request [Schedule]": {
"main": [[{"node": "Fetch via TLS Server [Schedule]", "type": "main", "index": 0}]]
},
"Fetch via TLS Server [Schedule]": {
"main": [[{"node": "Extract Result [Schedule]", "type": "main", "index": 0}]]
},
"Webhook Trigger": {
"main": [[{"node": "Set Target Config [Webhook]", "type": "main", "index": 0}]]
},
"Set Target Config [Webhook]": {
"main": [[{"node": "Solve Cloudflare Challenge [Webhook]", "type": "main", "index": 0}]]
},
"Solve Cloudflare Challenge [Webhook]": {
"main": [[{"node": "Prepare TLS Request [Webhook]", "type": "main", "index": 0}]]
},
"Prepare TLS Request [Webhook]": {
"main": [[{"node": "Fetch via TLS Server [Webhook]", "type": "main", "index": 0}]]
},
"Fetch via TLS Server [Webhook]": {
"main": [[{"node": "Extract Result [Webhook]", "type": "main", "index": 0}]]
},
"Extract Result [Webhook]": {
"main": [[{"node": "Respond to Webhook", "type": "main", "index": 0}]]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
}
}
Workflow: Use-Case Examples
The Solver API and scraper example above show the core pattern: solve the challenge, use the solution to fetch through TLS. The following workflows extend this pattern to production-ready use cases — each with dual triggers (schedule + webhook), persistent state tracking, and structured output. Each requires the same prerequisites: a self-hosted n8n instance, the TLS server running on port 7878, a residential proxy, and a CapSolver credential.
| Workflow | Purpose |
|---|---|
Cloudflare Challenge Scraping — Price & Product Details — CapSolver + Schedule + Webhook |
Scrapes price and product name from a CF-protected page every 6 hours, compares against previous values, alerts on changes |
Cloudflare Challenge Account Login — CapSolver + Schedule + Webhook |
Logs into your own account on a CF-protected site by solving the challenge first, then POSTing credentials through the TLS server |
Example 1: Scraping — Price & Product Details
This workflow scrapes a product page every 6 hours (schedule) or on demand (webhook), extracts the price using the HTML node, and compares it against the previously stored value.
Schedule path:
Every 6 Hours → Set Target Config → Solve CF Challenge → Prepare TLS Request
→ Fetch via TLS Server → Extract Data → Compare Data
→ Data Changed? → Build Alert / No Change
Error handling: If CapSolver fails, the workflow continues without cookies (via
continueOnFail). The TLS server fetch may still succeed if the page isn't currently showing a challenge.
Key behaviors:
- Uses
dataPropertyName: "body"(not"data") because the TLS server returns{ status, body, headers } - HTML node extracts price and product name via CSS selectors (
.product-price,h1) $workflow.staticData.lastPricepersists the previous price across executions- Price comparison detects both drops (severity:
deal) and increases (severity:info) - Proxy format auto-conversion:
host:port:user:pass→http://user:pass@host:portviatoProxyURL()helper
Click to expand full workflow JSON
json
{
"name": "Cloudflare Challenge Scraping — Price & Product Details — CapSolver + Schedule + Webhook",
"nodes": [
{
"parameters": {
"rule": { "interval": [{ "field": "hours", "hoursInterval": 6 }] }
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.3,
"position": [-500, 0],
"id": "cf333333-3333-3333-3333-333333333301",
"name": "Every 6 Hours"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "cfg-s-001", "name": "targetURL", "value": "https://YOUR_CF_PROTECTED_SITE.com/product-page", "type": "string" },
{ "id": "cfg-s-002", "name": "proxy", "value": "YOUR_PROXY_HOST:PORT:USER:PASS", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [-200, 0],
"id": "cf333333-3333-3333-3333-333333333302",
"name": "Set Target Config [Schedule]"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"type": "AntiCloudflareTask",
"websiteURL": "={{ $json.targetURL }}",
"proxy": "={{ $json.proxy }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [100, 0],
"id": "cf333333-3333-3333-3333-333333333303",
"name": "Solve Cloudflare Challenge [Schedule]",
"onError": "continueRegularOutput",
"credentials": { "capSolverApi": { "id": "YOUR_CREDENTIAL_ID", "name": "CapSolver account" } }
},
{
"parameters": {
"jsCode": "const config = $('Set Target Config [Schedule]').first().json;\nconst capResult = $input.first().json;\n\nfunction toProxyURL(proxy) {\n if (!proxy) return '';\n if (proxy.startsWith('http')) return proxy;\n const parts = proxy.split(':');\n if (parts.length === 4) {\n return `http://${parts[2]}:${parts[3]}@${parts[0]}:${parts[1]}`;\n }\n return proxy;\n}\n\nlet cookieStr = '';\nlet ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36';\n\nif (capResult.data && capResult.data.solution) {\n const solution = capResult.data.solution;\n const cookies = solution.cookies;\n cookieStr = cookies && typeof cookies === 'object'\n ? Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ')\n : (cookies || '');\n if (solution.userAgent) ua = solution.userAgent;\n}\n\nconst chromeMatch = ua.match(/Chrome\\/(\\d+)/);\nconst chromeVer = chromeMatch ? chromeMatch[1] : '145';\nconst secChUa = `\"Chromium\";v=\"${chromeVer}\", \"Not A(Brand\";v=\"8\", \"Google Chrome\";v=\"${chromeVer}\"`;\n\nconst headers = {\n 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',\n 'accept-language': 'en-US,en;q=0.9',\n 'sec-ch-ua': secChUa,\n 'sec-ch-ua-mobile': '?0',\n 'sec-ch-ua-platform': '\"Windows\"',\n 'sec-fetch-dest': 'document',\n 'sec-fetch-mode': 'navigate',\n 'sec-fetch-site': 'none',\n 'sec-fetch-user': '?1',\n 'upgrade-insecure-requests': '1',\n 'user-agent': ua\n};\n\nif (cookieStr) headers['cookie'] = cookieStr;\n\nreturn [{ json: {\n url: config.targetURL,\n method: 'GET',\n proxy: toProxyURL(config.proxy),\n headers\n}}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [400, 0],
"id": "cf333333-3333-3333-3333-333333333304",
"name": "Prepare TLS Request [Schedule]"
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:7878/fetch",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify($json) }}",
"options": { "timeout": 60000 }
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [700, 0],
"id": "cf333333-3333-3333-3333-333333333305",
"name": "Fetch via TLS Server [Schedule]"
},
{
"parameters": {
"operation": "extractHtmlContent",
"sourceData": "json",
"dataPropertyName": "body",
"extractionValues": {
"values": [
{ "key": "price", "cssSelector": ".product-price, [data-price], .price", "returnValue": "text", "returnArray": false },
{ "key": "productName", "cssSelector": "h1, .product-title", "returnValue": "text", "returnArray": false }
]
},
"options": {}
},
"type": "n8n-nodes-base.html",
"typeVersion": 1.2,
"position": [1000, 0],
"id": "cf333333-3333-3333-3333-333333333306",
"name": "Extract Data"
},
{
"parameters": {
"jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Product';\n\nconst parsePrice = (str) => {\n if (!str) return null;\n const match = str.match(/[\\d,]+\\.?\\d*/);\n return match ? parseFloat(match[0].replace(',', '')) : null;\n};\n\nconst currentNum = parsePrice(currentPrice);\nconst previousNum = parsePrice(previousPrice);\n\nstaticData.lastPrice = currentPrice;\nstaticData.lastChecked = new Date().toISOString();\n\nconst changed = previousNum !== null && currentNum !== null && currentNum !== previousNum;\nconst direction = changed ? (currentNum < previousNum ? 'dropped' : 'increased') : 'unchanged';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\n\nreturn [{\n json: {\n productName,\n currentPrice,\n previousPrice: previousPrice || 'first check',\n changed,\n direction,\n diff: changed ? `$${diff}` : null,\n checkedAt: new Date().toISOString()\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1300, 0],
"id": "cf333333-3333-3333-3333-333333333307",
"name": "Compare Data"
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 },
"conditions": [
{ "id": "price-if-001", "leftValue": "={{ $json.changed }}", "operator": { "type": "boolean", "operation": "true", "singleValue": true } }
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [1600, 0],
"id": "cf333333-3333-3333-3333-333333333308",
"name": "Data Changed?"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "alert-001", "name": "alert", "value": "=Price {{ $json.direction }} for {{ $json.productName }}: {{ $json.previousPrice }} → {{ $json.currentPrice }} ({{ $json.direction === 'dropped' ? '-' : '+' }}{{ $json.diff }})", "type": "string" },
{ "id": "alert-002", "name": "severity", "value": "={{ $json.direction === 'dropped' ? 'deal' : 'info' }}", "type": "string" },
{ "id": "alert-003", "name": "checkedAt", "value": "={{ $json.checkedAt }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1900, -80],
"id": "cf333333-3333-3333-3333-333333333309",
"name": "Build Alert"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "nc-001", "name": "status", "value": "no_change", "type": "string" },
{ "id": "nc-002", "name": "currentPrice", "value": "={{ $json.currentPrice }}", "type": "string" },
{ "id": "nc-003", "name": "checkedAt", "value": "={{ $json.checkedAt }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1900, 128],
"id": "cf333333-3333-3333-3333-333333333310",
"name": "No Change"
},
{
"parameters": {
"httpMethod": "POST",
"path": "cloudflare-price-monitor",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [-500, 500],
"id": "cf333333-3333-3333-3333-333333333311",
"name": "Webhook Trigger",
"webhookId": "cf333333-aaaa-bbbb-cccc-333333333311",
"onError": "continueRegularOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "cfg-w-001", "name": "targetURL", "value": "={{ $json.body.targetURL }}", "type": "string" },
{ "id": "cfg-w-002", "name": "proxy", "value": "={{ $json.body.proxy }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [-200, 500],
"id": "cf333333-3333-3333-3333-333333333312",
"name": "Set Target Config [Webhook]"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"type": "AntiCloudflareTask",
"websiteURL": "={{ $json.targetURL }}",
"proxy": "={{ $json.proxy }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [100, 500],
"id": "cf333333-3333-3333-3333-333333333313",
"name": "Solve Cloudflare Challenge [Webhook]",
"onError": "continueRegularOutput",
"credentials": { "capSolverApi": { "id": "YOUR_CREDENTIAL_ID", "name": "CapSolver account" } }
},
{
"parameters": {
"jsCode": "const config = $('Set Target Config [Webhook]').first().json;\nconst capResult = $input.first().json;\n\nfunction toProxyURL(proxy) {\n if (!proxy) return '';\n if (proxy.startsWith('http')) return proxy;\n const parts = proxy.split(':');\n if (parts.length === 4) {\n return `http://${parts[2]}:${parts[3]}@${parts[0]}:${parts[1]}`;\n }\n return proxy;\n}\n\nlet cookieStr = '';\nlet ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36';\n\nif (capResult.data && capResult.data.solution) {\n const solution = capResult.data.solution;\n const cookies = solution.cookies;\n cookieStr = cookies && typeof cookies === 'object'\n ? Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ')\n : (cookies || '');\n if (solution.userAgent) ua = solution.userAgent;\n}\n\nconst chromeMatch = ua.match(/Chrome\\/(\\d+)/);\nconst chromeVer = chromeMatch ? chromeMatch[1] : '145';\nconst secChUa = `\"Chromium\";v=\"${chromeVer}\", \"Not A(Brand\";v=\"8\", \"Google Chrome\";v=\"${chromeVer}\"`;\n\nconst headers = {\n 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',\n 'accept-language': 'en-US,en;q=0.9',\n 'sec-ch-ua': secChUa,\n 'sec-ch-ua-mobile': '?0',\n 'sec-ch-ua-platform': '\"Windows\"',\n 'sec-fetch-dest': 'document',\n 'sec-fetch-mode': 'navigate',\n 'sec-fetch-site': 'none',\n 'sec-fetch-user': '?1',\n 'upgrade-insecure-requests': '1',\n 'user-agent': ua\n};\n\nif (cookieStr) headers['cookie'] = cookieStr;\n\nreturn [{ json: {\n url: config.targetURL,\n method: 'GET',\n proxy: toProxyURL(config.proxy),\n headers\n}}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [400, 500],
"id": "cf333333-3333-3333-3333-333333333314",
"name": "Prepare TLS Request [Webhook]"
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:7878/fetch",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify($json) }}",
"options": { "timeout": 60000 }
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [700, 500],
"id": "cf333333-3333-3333-3333-333333333315",
"name": "Fetch via TLS Server [Webhook]"
},
{
"parameters": {
"operation": "extractHtmlContent",
"sourceData": "json",
"dataPropertyName": "body",
"extractionValues": {
"values": [
{ "key": "price", "cssSelector": ".product-price, [data-price], .price", "returnValue": "text", "returnArray": false },
{ "key": "productName", "cssSelector": "h1, .product-title", "returnValue": "text", "returnArray": false }
]
},
"options": {}
},
"type": "n8n-nodes-base.html",
"typeVersion": 1.2,
"position": [1000, 500],
"id": "cf333333-3333-3333-3333-333333333316",
"name": "Extract Data [Webhook]"
},
{
"parameters": {
"jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Product';\n\nconst parsePrice = (str) => {\n if (!str) return null;\n const match = str.match(/[\\d,]+\\.?\\d*/);\n return match ? parseFloat(match[0].replace(',', '')) : null;\n};\n\nconst currentNum = parsePrice(currentPrice);\nconst previousNum = parsePrice(previousPrice);\n\nstaticData.lastPrice = currentPrice;\nstaticData.lastChecked = new Date().toISOString();\n\nconst changed = previousNum !== null && currentNum !== null && currentNum !== previousNum;\nconst direction = changed ? (currentNum < previousNum ? 'dropped' : 'increased') : 'unchanged';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\n\nreturn [{\n json: {\n productName,\n currentPrice,\n previousPrice: previousPrice || 'first check',\n changed,\n direction,\n diff: changed ? `$${diff}` : null,\n checkedAt: new Date().toISOString()\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1300, 500],
"id": "cf333333-3333-3333-3333-333333333317",
"name": "Compare Data [Webhook]"
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 },
"conditions": [
{ "id": "price-if-002", "leftValue": "={{ $json.changed }}", "operator": { "type": "boolean", "operation": "true", "singleValue": true } }
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [1600, 500],
"id": "cf333333-3333-3333-3333-333333333318",
"name": "Data Changed? [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "alert-004", "name": "alert", "value": "=Price {{ $json.direction }} for {{ $json.productName }}: {{ $json.previousPrice }} → {{ $json.currentPrice }} ({{ $json.direction === 'dropped' ? '-' : '+' }}{{ $json.diff }})", "type": "string" },
{ "id": "alert-005", "name": "severity", "value": "={{ $json.direction === 'dropped' ? 'deal' : 'info' }}", "type": "string" },
{ "id": "alert-006", "name": "checkedAt", "value": "={{ $json.checkedAt }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1900, 420],
"id": "cf333333-3333-3333-3333-333333333319",
"name": "Build Alert [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "nc-004", "name": "status", "value": "no_change", "type": "string" },
{ "id": "nc-005", "name": "currentPrice", "value": "={{ $json.currentPrice }}", "type": "string" },
{ "id": "nc-006", "name": "checkedAt", "value": "={{ $json.checkedAt }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1900, 628],
"id": "cf333333-3333-3333-3333-333333333320",
"name": "No Change [Webhook]"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [2200, 500],
"id": "cf333333-3333-3333-3333-333333333321",
"name": "Respond to Webhook"
}
],
"connections": {
"Every 6 Hours": {
"main": [[{"node": "Set Target Config [Schedule]", "type": "main", "index": 0}]]
},
"Set Target Config [Schedule]": {
"main": [[{"node": "Solve Cloudflare Challenge [Schedule]", "type": "main", "index": 0}]]
},
"Solve Cloudflare Challenge [Schedule]": {
"main": [[{"node": "Prepare TLS Request [Schedule]", "type": "main", "index": 0}]]
},
"Prepare TLS Request [Schedule]": {
"main": [[{"node": "Fetch via TLS Server [Schedule]", "type": "main", "index": 0}]]
},
"Fetch via TLS Server [Schedule]": {
"main": [[{"node": "Extract Data", "type": "main", "index": 0}]]
},
"Extract Data": {
"main": [[{"node": "Compare Data", "type": "main", "index": 0}]]
},
"Compare Data": {
"main": [[{"node": "Data Changed?", "type": "main", "index": 0}]]
},
"Data Changed?": {
"main": [
[{"node": "Build Alert", "type": "main", "index": 0}],
[{"node": "No Change", "type": "main", "index": 0}]
]
},
"Webhook Trigger": {
"main": [[{"node": "Set Target Config [Webhook]", "type": "main", "index": 0}]]
},
"Set Target Config [Webhook]": {
"main": [[{"node": "Solve Cloudflare Challenge [Webhook]", "type": "main", "index": 0}]]
},
"Solve Cloudflare Challenge [Webhook]": {
"main": [[{"node": "Prepare TLS Request [Webhook]", "type": "main", "index": 0}]]
},
"Prepare TLS Request [Webhook]": {
"main": [[{"node": "Fetch via TLS Server [Webhook]", "type": "main", "index": 0}]]
},
"Fetch via TLS Server [Webhook]": {
"main": [[{"node": "Extract Data [Webhook]", "type": "main", "index": 0}]]
},
"Extract Data [Webhook]": {
"main": [[{"node": "Compare Data [Webhook]", "type": "main", "index": 0}]]
},
"Compare Data [Webhook]": {
"main": [[{"node": "Data Changed? [Webhook]", "type": "main", "index": 0}]]
},
"Data Changed? [Webhook]": {
"main": [
[{"node": "Build Alert [Webhook]", "type": "main", "index": 0}],
[{"node": "No Change [Webhook]", "type": "main", "index": 0}]
]
},
"Build Alert [Webhook]": {
"main": [[{"node": "Respond to Webhook", "type": "main", "index": 0}]]
},
"No Change [Webhook]": {
"main": [[{"node": "Respond to Webhook", "type": "main", "index": 0}]]
}
},
"active": false,
"settings": { "executionOrder": "v1" }
}
Example 2: Account Login
This workflow automates login to a Cloudflare-protected site. A Set Login Config node centralizes all parameters — [Schedule] for the schedule path and [Webhook] for the on-demand webhook path.
Schedule path:
Every 24 Hours → Set Login Config → Solve CF Challenge
→ Prepare TLS Login Request → Submit Login via TLS Server
→ Login Successful? → Mark Success / Mark Failed
Error handling: If CapSolver fails, the workflow continues without cookies (via
continueOnFail). The login request will likely fail, which the Login Successful? node catches.
Key behaviors:
- Uses
cf_clearancecookie +userAgentas HTTP headers (no token in form body — unlike reCAPTCHA login which submitsg-recaptcha-response) - Form fields via
URLSearchParams— edit field names (usernameField,passwordField) in Set Login Config to match your site - Login Successful? checks
status < 400ANDsuccessMarkerin response body - Webhook path returns result as JSON via Respond to Webhook
Click to expand full workflow JSON
json
{
"name": "Cloudflare Challenge Account Login — CapSolver + Schedule + Webhook",
"nodes": [
{
"parameters": {
"rule": { "interval": [{ "field": "hours", "hoursInterval": 24 }] }
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.3,
"position": [-640, 0],
"id": "cf666666-6666-6666-6666-666666666601",
"name": "Every 24 Hours"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "login-001", "name": "targetURL", "value": "https://YOUR_CF_PROTECTED_SITE.com/login", "type": "string" },
{ "id": "login-002", "name": "loginActionURL", "value": "https://YOUR_CF_PROTECTED_SITE.com/login", "type": "string" },
{ "id": "login-003", "name": "proxy", "value": "YOUR_PROXY_HOST:PORT:USER:PASS", "type": "string" },
{ "id": "login-004", "name": "usernameField", "value": "email", "type": "string" },
{ "id": "login-005", "name": "passwordField", "value": "password", "type": "string" },
{ "id": "login-006", "name": "usernameValue", "value": "[email protected]", "type": "string" },
{ "id": "login-007", "name": "passwordValue", "value": "YOUR_ACCOUNT_PASSWORD", "type": "string" },
{ "id": "login-008", "name": "successMarker", "value": "account-dashboard", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [-336, 0],
"id": "cf666666-6666-6666-6666-666666666602",
"name": "Set Login Config [Schedule]"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"type": "AntiCloudflareTask",
"websiteURL": "={{ $json.targetURL }}",
"proxy": "={{ $json.proxy }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [-32, 0],
"id": "cf666666-6666-6666-6666-666666666603",
"name": "Solve Cloudflare Challenge [Schedule]",
"credentials": { "capSolverApi": { "id": "YOUR_CREDENTIAL_ID", "name": "CapSolver account" } },
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "const config = $('Set Login Config [Schedule]').first().json;\nconst capResult = $input.first().json;\n\nfunction toProxyURL(proxy) {\n if (!proxy) return '';\n if (proxy.startsWith('http')) return proxy;\n const parts = proxy.split(':');\n if (parts.length === 4) {\n return `http://${parts[2]}:${parts[3]}@${parts[0]}:${parts[1]}`;\n }\n return proxy;\n}\n\nlet cookieStr = '';\nlet ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36';\n\nif (capResult.data && capResult.data.solution) {\n const solution = capResult.data.solution;\n const cookies = solution.cookies;\n cookieStr = cookies && typeof cookies === 'object'\n ? Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ')\n : (cookies || '');\n if (solution.userAgent) ua = solution.userAgent;\n}\n\nconst chromeMatch = ua.match(/Chrome\\/(\\d+)/);\nconst chromeVer = chromeMatch ? chromeMatch[1] : '145';\nconst secChUa = `\"Chromium\";v=\"${chromeVer}\", \"Not A(Brand\";v=\"8\", \"Google Chrome\";v=\"${chromeVer}\"`;\n\nconst params = new URLSearchParams();\nparams.set(config.usernameField, config.usernameValue);\nparams.set(config.passwordField, config.passwordValue);\n\nconst headers = {\n 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',\n 'accept-language': 'en-US,en;q=0.9',\n 'content-type': 'application/x-www-form-urlencoded',\n 'sec-ch-ua': secChUa,\n 'sec-ch-ua-mobile': '?0',\n 'sec-ch-ua-platform': '\"Windows\"',\n 'sec-fetch-dest': 'document',\n 'sec-fetch-mode': 'navigate',\n 'sec-fetch-site': 'same-origin',\n 'sec-fetch-user': '?1',\n 'upgrade-insecure-requests': '1',\n 'user-agent': ua\n};\n\nif (cookieStr) headers['cookie'] = cookieStr;\n\nreturn [{ json: {\n url: config.loginActionURL,\n method: 'POST',\n proxy: toProxyURL(config.proxy),\n headers,\n body: params.toString()\n}}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [272, 0],
"id": "cf666666-6666-6666-6666-666666666604",
"name": "Prepare TLS Login Request [Schedule]"
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:7878/fetch",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify($json) }}",
"options": { "timeout": 60000 }
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [576, 0],
"id": "cf666666-6666-6666-6666-666666666605",
"name": "Submit Login via TLS Server [Schedule]"
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": false, "leftValue": "", "typeValidation": "strict", "version": 2 },
"conditions": [
{ "id": "login-if-001", "leftValue": "={{ $json.status < 400 && String($json.body || '').includes($('Set Login Config [Schedule]').item.json.successMarker) }}", "operator": { "type": "boolean", "operation": "true", "singleValue": true } }
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [880, 0],
"id": "cf666666-6666-6666-6666-666666666606",
"name": "Login Successful? [Schedule]"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "login-010", "name": "action", "value": "account_login", "type": "string" },
{ "id": "login-011", "name": "status", "value": "success", "type": "string" },
{ "id": "login-012", "name": "message", "value": "Configured account login flow succeeded (via Cloudflare Challenge bypass)", "type": "string" },
{ "id": "login-013", "name": "checkedAt", "value": "={{ new Date().toISOString() }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1184, -80],
"id": "cf666666-6666-6666-6666-666666666607",
"name": "Mark Login Success [Schedule]"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "login-014", "name": "action", "value": "account_login", "type": "string" },
{ "id": "login-015", "name": "status", "value": "failed", "type": "string" },
{ "id": "login-016", "name": "statusCode", "value": "={{ $json.status }}", "type": "number" },
{ "id": "login-017", "name": "message", "value": "Login response did not match the configured success marker", "type": "string" },
{ "id": "login-018", "name": "checkedAt", "value": "={{ new Date().toISOString() }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1184, 120],
"id": "cf666666-6666-6666-6666-666666666608",
"name": "Mark Login Failed [Schedule]"
},
{
"parameters": {
"httpMethod": "POST",
"path": "cloudflare-account-login",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [-640, 420],
"id": "cf666666-6666-6666-6666-666666666609",
"name": "Webhook Trigger",
"webhookId": "cf666666-aaaa-bbbb-cccc-666666666609",
"onError": "continueRegularOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "login-019", "name": "targetURL", "value": "={{ $json.body.targetURL }}", "type": "string" },
{ "id": "login-020", "name": "loginActionURL", "value": "={{ $json.body.loginActionURL }}", "type": "string" },
{ "id": "login-021", "name": "proxy", "value": "={{ $json.body.proxy }}", "type": "string" },
{ "id": "login-022", "name": "usernameField", "value": "={{ $json.body.usernameField }}", "type": "string" },
{ "id": "login-023", "name": "passwordField", "value": "={{ $json.body.passwordField }}", "type": "string" },
{ "id": "login-024", "name": "usernameValue", "value": "={{ $json.body.usernameValue }}", "type": "string" },
{ "id": "login-025", "name": "passwordValue", "value": "={{ $json.body.passwordValue }}", "type": "string" },
{ "id": "login-026", "name": "successMarker", "value": "={{ $json.body.successMarker }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [-336, 420],
"id": "cf666666-6666-6666-6666-666666666610",
"name": "Set Login Config [Webhook]"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"type": "AntiCloudflareTask",
"websiteURL": "={{ $json.targetURL }}",
"proxy": "={{ $json.proxy }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [-32, 420],
"id": "cf666666-6666-6666-6666-666666666611",
"name": "Solve Cloudflare Challenge [Webhook]",
"credentials": { "capSolverApi": { "id": "YOUR_CREDENTIAL_ID", "name": "CapSolver account" } },
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "const config = $('Set Login Config [Webhook]').first().json;\nconst capResult = $input.first().json;\n\nfunction toProxyURL(proxy) {\n if (!proxy) return '';\n if (proxy.startsWith('http')) return proxy;\n const parts = proxy.split(':');\n if (parts.length === 4) {\n return `http://${parts[2]}:${parts[3]}@${parts[0]}:${parts[1]}`;\n }\n return proxy;\n}\n\nlet cookieStr = '';\nlet ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36';\n\nif (capResult.data && capResult.data.solution) {\n const solution = capResult.data.solution;\n const cookies = solution.cookies;\n cookieStr = cookies && typeof cookies === 'object'\n ? Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join('; ')\n : (cookies || '');\n if (solution.userAgent) ua = solution.userAgent;\n}\n\nconst chromeMatch = ua.match(/Chrome\\/(\\d+)/);\nconst chromeVer = chromeMatch ? chromeMatch[1] : '145';\nconst secChUa = `\"Chromium\";v=\"${chromeVer}\", \"Not A(Brand\";v=\"8\", \"Google Chrome\";v=\"${chromeVer}\"`;\n\nconst params = new URLSearchParams();\nparams.set(config.usernameField, config.usernameValue);\nparams.set(config.passwordField, config.passwordValue);\n\nconst headers = {\n 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',\n 'accept-language': 'en-US,en;q=0.9',\n 'content-type': 'application/x-www-form-urlencoded',\n 'sec-ch-ua': secChUa,\n 'sec-ch-ua-mobile': '?0',\n 'sec-ch-ua-platform': '\"Windows\"',\n 'sec-fetch-dest': 'document',\n 'sec-fetch-mode': 'navigate',\n 'sec-fetch-site': 'same-origin',\n 'sec-fetch-user': '?1',\n 'upgrade-insecure-requests': '1',\n 'user-agent': ua\n};\n\nif (cookieStr) headers['cookie'] = cookieStr;\n\nreturn [{ json: {\n url: config.loginActionURL,\n method: 'POST',\n proxy: toProxyURL(config.proxy),\n headers,\n body: params.toString()\n}}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [272, 420],
"id": "cf666666-6666-6666-6666-666666666612",
"name": "Prepare TLS Login Request [Webhook]"
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:7878/fetch",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify($json) }}",
"options": { "timeout": 60000 }
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [576, 420],
"id": "cf666666-6666-6666-6666-666666666613",
"name": "Submit Login via TLS Server [Webhook]"
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": false, "leftValue": "", "typeValidation": "strict", "version": 2 },
"conditions": [
{ "id": "login-if-002", "leftValue": "={{ $json.status < 400 && String($json.body || '').includes($('Set Login Config [Webhook]').item.json.successMarker) }}", "operator": { "type": "boolean", "operation": "true", "singleValue": true } }
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [880, 420],
"id": "cf666666-6666-6666-6666-666666666614",
"name": "Login Successful? [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "login-028", "name": "action", "value": "account_login", "type": "string" },
{ "id": "login-029", "name": "status", "value": "success", "type": "string" },
{ "id": "login-030", "name": "message", "value": "Configured account login flow succeeded (via Cloudflare Challenge bypass)", "type": "string" },
{ "id": "login-031", "name": "checkedAt", "value": "={{ new Date().toISOString() }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1184, 340],
"id": "cf666666-6666-6666-6666-666666666615",
"name": "Mark Login Success [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "login-032", "name": "action", "value": "account_login", "type": "string" },
{ "id": "login-033", "name": "status", "value": "failed", "type": "string" },
{ "id": "login-034", "name": "statusCode", "value": "={{ $json.status }}", "type": "number" },
{ "id": "login-035", "name": "message", "value": "Login response did not match the configured success marker", "type": "string" },
{ "id": "login-036", "name": "checkedAt", "value": "={{ new Date().toISOString() }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1184, 540],
"id": "cf666666-6666-6666-6666-666666666616",
"name": "Mark Login Failed [Webhook]"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [1488, 420],
"id": "cf666666-6666-6666-6666-666666666617",
"name": "Respond to Webhook"
}
],
"connections": {
"Every 24 Hours": {
"main": [[{"node": "Set Login Config [Schedule]", "type": "main", "index": 0}]]
},
"Set Login Config [Schedule]": {
"main": [[{"node": "Solve Cloudflare Challenge [Schedule]", "type": "main", "index": 0}]]
},
"Solve Cloudflare Challenge [Schedule]": {
"main": [[{"node": "Prepare TLS Login Request [Schedule]", "type": "main", "index": 0}]]
},
"Prepare TLS Login Request [Schedule]": {
"main": [[{"node": "Submit Login via TLS Server [Schedule]", "type": "main", "index": 0}]]
},
"Submit Login via TLS Server [Schedule]": {
"main": [[{"node": "Login Successful? [Schedule]", "type": "main", "index": 0}]]
},
"Login Successful? [Schedule]": {
"main": [
[{"node": "Mark Login Success [Schedule]", "type": "main", "index": 0}],
[{"node": "Mark Login Failed [Schedule]", "type": "main", "index": 0}]
]
},
"Webhook Trigger": {
"main": [[{"node": "Set Login Config [Webhook]", "type": "main", "index": 0}]]
},
"Set Login Config [Webhook]": {
"main": [[{"node": "Solve Cloudflare Challenge [Webhook]", "type": "main", "index": 0}]]
},
"Solve Cloudflare Challenge [Webhook]": {
"main": [[{"node": "Prepare TLS Login Request [Webhook]", "type": "main", "index": 0}]]
},
"Prepare TLS Login Request [Webhook]": {
"main": [[{"node": "Submit Login via TLS Server [Webhook]", "type": "main", "index": 0}]]
},
"Submit Login via TLS Server [Webhook]": {
"main": [[{"node": "Login Successful? [Webhook]", "type": "main", "index": 0}]]
},
"Login Successful? [Webhook]": {
"main": [
[{"node": "Mark Login Success [Webhook]", "type": "main", "index": 0}],
[{"node": "Mark Login Failed [Webhook]", "type": "main", "index": 0}]
]
},
"Mark Login Success [Webhook]": {
"main": [[{"node": "Respond to Webhook", "type": "main", "index": 0}]]
},
"Mark Login Failed [Webhook]": {
"main": [[{"node": "Respond to Webhook", "type": "main", "index": 0}]]
}
},
"active": false,
"settings": { "executionOrder": "v1" }
}
Conclusion
You've built a complete Cloudflare Challenge bypass pipeline in n8n — no browser automation, no Puppeteer, no Playwright. Just three components working together: CapSolver to solve the challenge, a Go TLS server to spoof Chrome's network fingerprint, and an n8n workflow to orchestrate everything.
The key insight is that solving the challenge is only half the problem. Without matching TLS fingerprints on the subsequent fetch, cf_clearance is useless — Cloudflare inspects the handshake, not just the cookie. The httpcloak TLS server handles that layer, making the fetch indistinguishable from a real Chrome browser at the network level.
The repo now gives you actual starting templates for Cloudflare-protected sites:
- Challenge Solver API — expose a webhook that returns raw
cf_clearance+userAgentfor external apps - Scraping — extract price and product data from Cloudflare-protected pages, with change detection
- Account login — log into your own account behind Cloudflare
The Solver API is the simplest entry point — 4 nodes, no TLS server needed. For workflows that fetch pages directly, CapSolver solves the challenge and the TLS server makes the actual request. Configure the placeholders, keep the workflows inactive until they match your target, then activate.
Tip: These workflows use Schedule + Webhook triggers, but you can swap the trigger node to any n8n trigger — manual, app event, form submission, etc. After fetching data, use n8n's built-in nodes to save results to Google Sheets, databases, cloud storage, or send alerts via Telegram/Slack/Email.
Ready to get started? Sign up for CapSolver and use bonus code n8n for an extra 8% bonus on your first recharge!

Frequently Asked Questions
What is AntiCloudflareTask, and how is it different from AntiTurnstileTaskProxyLess?
AntiCloudflareTask solves the full-page Cloudflare Bot Management challenge — the "Just a moment…" screen that blocks site access entirely. It requires a proxy because CapSolver must load the actual protected page through a browser. AntiTurnstileTaskProxyLess solves Turnstile widgets embedded inside pages (login forms, signup forms) and does not require a proxy. Different challenges, different task types.
Why can't I just use n8n's built-in HTTP Request node to fetch the page?
n8n's HTTP Request node uses Go's standard net/http library, which has a distinct TLS fingerprint that Cloudflare detects. Even with a valid cf_clearance cookie, Cloudflare will re-challenge any request that doesn't match a known browser TLS profile. The TLS server solves this by using httpcloak to spoof a real Chrome TLS stack.
Why does my datacenter proxy keep failing?
Cloudflare's bot scoring assigns risk scores to IP addresses. Datacenter IPs (from AWS, GCP, VPS providers, etc.) are well-known and get high risk scores. AntiCloudflareTask uses your proxy to load the challenge page, and if Cloudflare detects the IP as a datacenter, it either serves a harder challenge that CapSolver can't solve, or fails the challenge entirely. Residential and mobile IPs have lower risk scores and pass more reliably.
Does cf_clearance expire?
Yes. The expiration depends on the site's Cloudflare configuration — it can range from a few minutes to 24 hours. For recurring scraping jobs, the scheduled workflow (every 6 hours) re-solves the challenge regularly. For on-demand scraping, the webhook path solves a fresh challenge on every request.
Compliance Disclaimer: The information provided on this blog is for informational purposes only. CapSolver is committed to compliance with all applicable laws and regulations. The use of the CapSolver network for illegal, fraudulent, or abusive activities is strictly prohibited and will be investigated. Our captcha-solving solutions enhance user experience while ensuring 100% compliance in helping solve captcha difficulties during public data crawling. We encourage responsible use of our services. For more information, please visit our Terms of Service and Privacy Policy.
More

How to Use CapSolver in n8n: The Complete Guide to Solving CAPTCHA in Your Workflows
Learn how to integrate CapSolver with n8n to solve CAPTCHAs and build reliable automation workflows with ease.

Lucas Mitchell
18-Mar-2026

How to Solve Cloudflare Turnstile Using CapSolver and n8n
Build a Cloudflare Turnstile solver API using CapSolver and n8n. Learn how to automate token solving, submit it to websites, and extract protected data with no coding.

Ethan Collins
18-Mar-2026

How to Solve reCAPTCHA v2/v3 Using CapSolver and n8n
Build a eCAPTCHA v2/v3 solver API using CapSolver and n8n. Learn how to automate token solving, submit it to websites, and extract protected data with no coding.

Lucas Mitchell
18-Mar-2026

How to Solve TLS Fingerprinting in n8n with CapSolver
Solve TLS fingerprinting in n8n with CapSolver. Make requests appear as real browsers and avoid bot detection blocks.

Ethan Collins
18-Mar-2026

How to Solve Visual Puzzles in n8n with CapSolver
Solve visual CAPTCHAs with CapSolver Vision Engine in n8n. Handle sliders, rotation, object selection, and GIF OCR instantly.

Ethan Collins
18-Mar-2026

How to Solve GeeTest V3 in n8n with CapSolver: Complete Integration Guide
Learn how to integrate CapSolver with n8n to solve GeeTest V3 and build reliable automation workflows.

Ethan Collins
18-Mar-2026

