ProdutosIntegraçõesRecursosDocumentaçãoPreços
Começar agora

© 2026 CapSolver. All rights reserved.

Contacte-nos

Slack: lola@capsolver.com

Produtos

  • reCAPTCHA v2
  • reCAPTCHA v3
  • Cloudflare Turnstile
  • Cloudflare Challenge
  • AWS WAF
  • Extensão de Navegador
  • Mais tipos de CAPTCHA

Integrações

  • Selenium
  • Playwright
  • Puppeteer
  • n8n
  • Parceiros
  • Ver todas as integrações

Recursos

  • Programa de Referenciação
  • Documentação
  • Referência da API
  • Blog
  • FAQ
  • Glossário
  • Estado

Legal

  • Termos de Serviço
  • Política de Privacidade
  • Política de Reembolso
  • Não vender os meus dados pessoais
//Como resolver o Cloudflare Challenge no n8n com o CapSolver
Mar10, 2026

Como resolver o Cloudflare Challenge no n8n com o CapSolver

Adélia Cruz

Adélia Cruz

Neural Network Developer

A proteção contra bots da Cloudflare vai muito além dos widgets CAPTCHA. O Cloudflare Challenge — a tela de "Verificando seu navegador…" em página cheia que bloqueia totalmente o acesso a um site — é uma das defesas contra bots mais agressivas na web. Ele executa um desafio JavaScript completo em um ambiente real de navegador, verifica sinais comportamentais e identifica digitalmente sua conexão TLS antes de permitir o acesso.

As ferramentas de automação padrão falham aqui. Não porque não consigam resolver o desafio, mas porque a Cloudflare faz a identificação digital do handshake TLS — e qualquer cliente HTTP não navegadore é bloqueado antes mesmo do desafio ser servido, ou é re-desafiado imediatamente depois, mesmo com um cookie válido cf_clearance.

Neste guia, você aprenderá como construir um scraper para o Cloudflare Challenge no n8n que realmente funciona — combinando o CapSolver para resolver o desafio, um servidor TLS local em Go para falsificar a digital TLS do Chrome, e um fluxo de trabalho n8n para integrar tudo.

O que você irá construir:

  • Um fluxo de trabalho com gatilhos duplos (agendamento + webhook) que contorna o Cloudflare Bot Management
  • Um servidor Go leve que faz requisições HTTP com uma digital TLS real do Chrome
  • Um template de scraper reutilizável que você pode usar em qualquer site protegido pelo CF
  • Fluxos de trabalho para scraping, login de contas, e uma API independente de solução de desafio — tudo atrás do Cloudflare Challenge
  • Fluxos Turnstile — uma API solucionadora, um template de scraping, e fluxo de login para sites usando Cloudflare Turnstile (sem necessidade de proxy ou servidor TLS)

O que é o Cloudflare Challenge?

O Cloudflare Challenge (também chamado de desafio JS ou desafio de Bot Management) é um intersticial em página cheia que a Cloudflare injeta antes que um visitante possa acessar um site protegido. Você já deve ter visto: uma tela preta ou branca com "Verificando seu navegador…" ou "Só um momento…" com uma barra de carregamento ou o logo da Cloudflare.

Diferente do Turnstile — que é um pequeno widget embutido dentro de uma página — o Cloudflare Challenge ocupa a página inteira. Você não pode acessar qualquer conteúdo até que ele seja concluído.

Cloudflare Challenge Cloudflare Turnstile
Onde aparece Intersticial em página cheia — bloqueia o acesso ao site totalmente Widget embutido dentro de uma página (ex: formulário de login)
Como é Tela de carregamento "Verificando seu navegador…" Uma pequena caixa de seleção ou widget invisível em um formulário
Quem adiciona Cloudflare adiciona automaticamente baseado em regras de segurança O dono do site embute no HTML
Abordagem para resolver AntiCloudflareTask — requer proxy AntiTurnstileTaskProxyLess — não precisa proxy
Cookie retornado cf_clearance (específico do domínio, ligado ao IP) Token Turnstile (curta duração, uso único)
Necessita proxy? Sim — o mesmo IP deve ser usado para resolver e buscar Não

Se você vir uma caixa de seleção embutida ou widget dentro de um formulário, isso é Turnstile — não este desafio. Confira o guia CapSolver sobre como identificar tipos de desafio se estiver em dúvida.


Por que clientes HTTP padrão falham

Aqui está o problema que a maioria dos guias ignora: a Cloudflare verifica a sua digital TLS, não apenas seus cookies.

Quando um navegador conecta-se a um site via HTTPS, ele envia um TLS ClientHello que inclui detalhes sobre seus cipher suites suportados, extensões e configurações. A Cloudflare registra essa digital (chamada de digital JA3 ou JA4) e compara com perfis de navegadores conhecidos.

As bibliotecas net/http do Go, requests do Python, curl, e a maioria das bibliotecas HTTP possuem digitais TLS distintas. Mesmo que o CapSolver resolva o desafio com sucesso e retorne um cookie válido cf_clearance, a Cloudflare irá re-chamar o desafio ou bloquear a requisição se detectar uma digital TLS não navegadora na busca subsequente.

A solução: um servidor Go usando httpcloak — uma biblioteca que falsifica uma pilha TLS real do Chrome incluindo:

  • Digital JA3 / JA4
  • Quadro SETTINGS do HTTP/2
  • Negociação ALPN
  • Ordenação e valores dos cabeçalhos

Isso faz a busca parecer exatamente como uma requisição de navegador Chrome no nível da rede.


Pré-requisitos

Requisito Observações
n8n self-hosted Necessário — o servidor TLS deve rodar na mesma máquina que o n8n. n8n Cloud não é adequado para esse caso.
Conta CapSolver Cadastre-se aqui e obtenha sua chave API
Go 1.21+ Deve estar instalado no servidor n8n. Verifique com go version.
Proxy residencial ou móvel Proxies de datacenter falharão na maioria dos sites protegidos pela Cloudflare. Veja Requisitos de proxy abaixo.

Configurando o CapSolver no n8n

CapSolver está disponível como uma integração oficial no n8n — não é necessário instalar um nó da comunidade.

Passo 1: Abra a página de Credenciais

Vá para a sua instância n8n e navegue até Settings → Credentials.

Página de credenciais n8n mostrando conta CapSolver

Passo 2: Crie a credencial CapSolver

  1. Clique em Create credential (no canto superior direito)
  2. Pesquise por "CapSolver" e selecione CapSolver API
  3. Cole sua API Key do Painel CapSolver
  4. Deixe Allowed HTTP Request Domains como All
  5. Clique em Save

Você deverá ver a faixa verde "Connection tested successfully".

Configuração da credencial CapSolver com teste de conexão bem-sucedido

Importante: Cada nó CapSolver em seus fluxos referencia esta credencial. Você só precisa criá-la uma vez — todos os seus fluxos de solução compartilharão esta credencial.


Passo 1 — Construindo o servidor TLS

Este servidor Go recebe requisições de fetch do n8n e as executa usando o perfil TLS do Chrome do httpcloak. É um binário pequeno e auto-contido que você roda junto do n8n.

Crie o arquivo fonte

Crie um diretório e salve o seguinte como main.go:

bash Copy
mkdir -p ~/tls-server && cd ~/tls-server
go Copy
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))
}

Inicialize e compile

bash Copy
go mod init tls-server
go get github.com/sardanioss/httpcloak/client
go build -o main main.go

Execute o servidor

bash Copy
./main

Verifique se está rodando (em um novo terminal)

bash Copy
curl http://localhost:7878/health

Esperado: {"status":"ok"}

Nota: O servidor TLS deve rodar na mesma máquina que sua instância n8n. O fluxo n8n o chama em http://localhost:7878/fetch. Se você usa n8n Cloud, precisará de uma instalação self-hosted — este é um dos motivos pelos quais o n8n self-hosted é fortemente recomendado para scraping com Cloudflare Challenge.


Passo 2 — Permitir que o n8n chame localhost

Por padrão, o n8n bloqueia nodos HTTP Request de fazer chamadas para endereços localhost (proteção SSRF). Você precisa desabilitar essa restrição.

Adicione a variável de ambiente N8N_BLOCK_ACCESS_TO_LOCALHOST=false e reinicie sua instância n8n. Como fazer isso depende de como você roda o n8n:

Se você roda o n8n diretamente:

bash Copy
export N8N_BLOCK_ACCESS_TO_LOCALHOST=false
n8n start

Se você usa Docker:

Adicione -e N8N_BLOCK_ACCESS_TO_LOCALHOST=false ao comando docker run, ou adicione na seção environment do seu docker-compose.yml.


Fluxo de trabalho: API Solucionadora do Cloudflare Challenge

Este fluxo cria um endpoint POST que aceita uma URL protegida pela Cloudflare e proxy, resolve o desafio via CapSolver e retorna o cookie bruto cf_clearance e o userAgent. Nenhum servidor TLS necessário — sua aplicação faz o fetch.

Como funciona

Copy
Webhook (POST /solver-cloudflare-challenge) → Cloudflare Challenge (CapSolver)
                                             → Format Solution → Responder o Webhook

4 nós, apenas webhook, sem caminho de agendamento, sem dependência de servidor TLS.

  1. Webhook — Recebe requisições POST com websiteURL e proxy
  2. Cloudflare Challenge — CapSolver resolve o desafio usando AntiCloudflareTask
  3. Format Solution — Serializa o objeto cookies em string de cookie, trata erros com continueOnFail
  4. Respond to Webhook — Retorna cf_clearance, string de cookie serializada, e userAgent### Configuração do Nó

1. Nó Webhook

Configuração Valor
Método HTTP POST
Caminho solver-cloudflare-challenge
Responder Response Node

Isso cria um endpoint em: https://your-n8n-instance.com/webhook/solver-cloudflare-challenge

2. Nó CapSolver (Desafio Cloudflare)

Parâmetro Valor Descrição
Operação Cloudflare Challenge Seleciona AntiCloudflareTask
Tipo AntiCloudflareTask Desafio Cloudflare de página completa
URL do Site ={{ $json.body.websiteURL }} A URL protegida pelo Cloudflare
Proxy ={{ $json.body.proxy }} Proxy residencial no formato host:port:user:pass
Continuar em caso de Falha true Retorna erros estruturados ao invés de travar

O CapSolver lança um navegador real via seu proxy, carrega a URL alvo e resolve o desafio do Cloudflare. Quando bem-sucedido, retorna um objeto solution contendo:

  • cookies — um objeto { cf_clearance: "..." } com o cookie de permissão
  • userAgent — a string exata do User-Agent que o navegador usou durante a resolução

Nota: O campo é websiteURL (não targetURL) — combinando com o nome de campo usado por todas as outras APIs do Solver e pelo próprio nó CapSolver.

3. Formatar Solução (Nó de Código)

Este nó é necessário porque AntiCloudflareTask retorna cookies como um objeto ({ cf_clearance: "..." }), não uma simples string de token como reCAPTCHA ou Turnstile. Ele serializa o cookie, extrai cf_clearance e retorna um erro estruturado caso o CapSolver tenha falhado.

javascript Copy
const input = $input.first().json;

if (input.error || !input.data || !input.data.solution) {
  const errorMsg = input.error
    ? (input.error.message || JSON.stringify(input.error))
    : 'Nenhuma solução retornada — o site pode não estar mostrando um desafio';
  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. Responder ao Webhook

Configuração Valor
Responder Com JSON
Corpo da Resposta ={{ JSON.stringify($json) }}

Teste

bash Copy
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"
  }'

Resposta bem-sucedida:

json Copy
{
  "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"
}

Resposta falha (nenhum desafio encontrado, proxy ruim, etc.):

json Copy
{
  "success": false,
  "error": "Nenhuma solução retornada — o site pode não estar mostrando um desafio"
}

Importe este Workflow

Copie o JSON abaixo e importe-o no n8n via Menu → Importar do JSON. Após importar, selecione suas credenciais CapSolver no nó Cloudflare Challenge.

Clique para expandir o JSON do workflow
json Copy
{
  "nodes": [
    {
      "parameters": {
        "content": "## Cloudflare Challenge \u2014 Solver API\n\n### How it works\n\n1. Receives a request via webhook to solve a Cloudflare challenge.\n2. Uses the Cloudflare Challenge node to attempt solving the challenge.\n3. Formats the solved challenge token via custom code.\n4. Responds back to the original request with the solved token.\n\n### Setup steps\n\n- [ ] Configure the Webhook node to receive requests.\n- [ ] Set up CapSolver credentials to enable solving Cloudflare challenges.\n- [ ] Ensure the Response node is properly configured to send back the solved token.\n\n### Customization\n\nYou can customize the code in the 'Format Solution' node to change the formatting of the solved token response.",
        "width": 480,
        "height": 672
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -816,
        -128
      ],
      "id": "254f3829-0e6e-4ae3-bf83-85851be9a7bc",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## Receive and solve challenge\n\nTriggers on a new request and attempts to solve the Cloudflare challenge.",
        "width": 512,
        "height": 304,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -256,
        -128
      ],
      "id": "44e79738-a2f0-41ec-8ff0-514afbd6cc45",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "## Format and return solution\n\nFormats the solution and responds back with the solved token.",
        "width": 496,
        "height": 304,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        352,
        -128
      ],
      "id": "fc40112d-389d-4d4e-8872-af2ae533c513",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "solver-cloudflare-challenge",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -208,
        0
      ],
      "id": "cf770001-7777-7777-7777-777777777701",
      "name": "Receive Solver Request",
      "webhookId": "cf770001-aaaa-bbbb-cccc-777777777701",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "Cloudflare Challenge",
        "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": "BeBFMAsySMsMGeE9",
          "name": "CapSolver account"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "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 \u2014 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.5,
      "position": [
        700,
        0
      ],
      "id": "cf770001-7777-7777-7777-777777777704",
      "name": "Return Solved Token"
    }
  ],
  "connections": {
    "Receive Solver Request": {
      "main": [
        [
          {
            "node": "Cloudflare Challenge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cloudflare Challenge": {
      "main": [
        [
          {
            "node": "Format Solution",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Solution": {
      "main": [
        [
          {
            "node": "Return Solved Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
  }
}

Workflow: Usando Soluções do Desafio Cloudflare

Até agora, a API do Solver acima mostra como obter um cookie cf_clearance resolvido e o userAgent. Mas o que você realmente faz com eles?

Ao contrário do reCAPTCHA ou Turnstile, onde você envia um token em um campo de formulário, o Desafio Cloudflare retorna um cookie (cf_clearance) que deve ser enviado como um cabeçalho em todas as requisições subsequentes. O cookie está vinculado ao IP do proxy e ao User-Agent usados durante a solução — ambos devem coincidir exatamente na requisição.

Aqui está o padrão geral:

  1. Resolver o Desafio Cloudflare → Obter o cookie cf_clearance e o userAgent do CapSolver
  2. Preparar a requisição → Construir os cabeçalhos com o cookie, User-Agent correspondente e os cabeçalhos sec-ch-ua semelhantes ao Chrome
  3. Buscar via servidor TLS → Enviar a requisição via http://localhost:7878/fetch para combinar a impressão digital TLS do Chrome
  4. Verificar a resposta → Conferir se o site retornou conteúdo real (status 200 com HTML) versus uma página de novo desafio
  5. Processar o resultado → Extrair os dados que você precisa usando o nó HTML, Edit Fields ou Nó de Código

Conceito chave: Clientes HTTP padrão falham aqui mesmo com um cookie cf_clearance válido — Cloudflare identifica a negociação TLS em si. O servidor Go TLS (httpcloak) faz a busca parecer exatamente o Chrome no nível da rede. Todo workflow que busca uma página protegida pelo Cloudflare deve passar pelo servidor TLS.### Exemplo: Raspador de Desafios Cloudflare

Fluxo de trabalho do Desafio Cloudflare no n8n com caminhos de agendamento e webhook

Fluxo do Workflow

Caminho de agendamento:

Copy
A cada 6 horas → Definir Configuração do Alvo [Schedule] → Resolver Desafio Cloudflare
             → Preparar Requisição TLS → Buscar via Servidor TLS → Extrair Resultado

Caminho do webhook:

Copy
Gatilho do Webhook → Definir Configuração do Alvo [Webhook] → Resolver Desafio Cloudflare
               → Preparar Requisição TLS → Buscar via Servidor TLS → Extrair Resultado → Responder ao Webhook

Como Funciona

  1. Definir Configuração do Alvo — Armazena targetURL e proxy (no formato host:port:user:pass). O caminho de agendamento usa valores codificados; o caminho do webhook os lê do corpo do POST.
  2. Resolver Desafio Cloudflare — Nó CapSolver com onError: "continueRegularOutput" — continua mesmo se a página não estiver exibindo um desafio no momento.
  3. Preparar Requisição TLS — Nó de código que converte o proxy host:port:user:pass para o formato de URL http://user:pass@host:port, serializa solution.cookies para uma string de cabeçalho de cookies e monta cabeçalhos de requisição semelhantes ao Chrome com o userAgent exato da resolução.
  4. Buscar via Servidor TLS — Requisição HTTP para http://localhost:7878/fetch usando contentType: "raw" (não "json" — o modo JSON do n8n corrompe o corpo).
  5. Extrair Resultado — Obtém status, body e fetchedAt da resposta do servidor TLS.
  6. Responder ao Webhook — Retorna o resultado como JSON (apenas no caminho do webhook).

Por que contentType: "raw" e não "json"? O modo de tipo de conteúdo json do n8n espera parâmetros do corpo como pares de chave-valor. Se você passar JSON.stringify($json) como uma string, o n8n trata toda a string como um único parâmetro malformado e envia {"": ""} para o servidor. Usar o modo raw envia o corpo exatamente como a expressão é avaliada.

Clique para expandir o JSON do workflow
json Copy
{
  "nodes": [
    {
      "parameters": {
        "content": "## Desafio Cloudflare — CapSolver + Schedule + Webhook\n\n### Como funciona\n\n1. Aciona agendamento a cada 6 horas para resolver desafios Cloudflare.\n2. Webhook é acionado em requisição para resolver desafios Cloudflare.\n3. Define configuração do alvo e proxy para requisições.\n4. Resolve o desafio Cloudflare usando CapSolver.\n5. Envia resultados via TLS e processa a resposta HTTP.\n\n### Passos de configuração\n\n- Certifique-se de que as credenciais do CapSolver estão configuradas.\n- Confirme que a URL do webhook está definida e acessível.\n- Verifique a configuração do agendamento para acionamento a cada 6 horas.\n- Verifique se o endpoint http://localhost:7878/fetch está disponível.\n\n### Personalização\n\nConsidere personalizar a URL do alvo ou as configurações do proxy dentro dos nós definidos.",
        "width": 480,
        "height": 688
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1008,
        -112
      ],
      "id": "3c1c3e96-631a-4cf6-bbff-85fd8b1a01e8",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## Desafio Cloudflare Agendado\n\nAcionado a cada 6 horas para resolver o desafio Cloudflare.",
        "width": 1696,
        "height": 272,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -448,
        -112
      ],
      "id": "e9187404-7818-4233-af66-091c90a40476",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "## Desafio Cloudflare via Webhook\n\nResponde às solicitações do resolvedor via webhook para resolver o desafio Cloudflare.",
        "width": 2000,
        "height": 272,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -448,
        304
      ],
      "id": "b5d5ba23-8ed2-4afb-8113-3fa8f2fba51e",
      "name": "Sticky Note2"
    },
    {
      "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": "A cada 6 Horas"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "cfg-s-001",
              "name": "targetURL",
              "value": "https://www.listaspam.com/busca.php?Telefono=671484239",
              "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": "Definir Configuração do Alvo [Schedule]"
    },
    {
      "parameters": {
        "operation": "Cloudflare Challenge",
        "websiteURL": "={{ $json.targetURL }}",
        "proxy": "={{ $json.proxy }}"
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        208,
        0
      ],
      "id": "cf111111-1111-1111-1111-111111111103",
      "name": "Resolver Desafio Cloudflare [Schedule]",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Conta CapSolver"
        }
      },
      "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) {\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": [
        512,
        0
      ],
      "id": "cf111111-1111-1111-1111-111111111104",
      "name": "Preparar Requisição TLS [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": "Buscar via Servidor TLS [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": "Extrair Resultado [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": "Receber Solicitação do Resolvedor",
      "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": "Definir Configuração do Alvo [Webhook]"
    },
    {
      "parameters": {
        "operation": "Cloudflare Challenge",
        "websiteURL": "={{ $json.targetURL }}",
        "proxy": "={{ $json.proxy }}"
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        208,
        420
      ],
      "id": "cf111111-1111-1111-1111-111111111109",
      "name": "Resolver Desafio Cloudflare [Webhook]",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Conta CapSolver"
        }
      },
      "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) {\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": [
        512,
        420
      ],
      "id": "cf111111-1111-1111-1111-111111111110",
      "name": "Preparar Requisição TLS [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": "Buscar via Servidor TLS [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": "Extrair Resultado [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": "Retornar Token Resolvido"
    }
  ],
  "connections": {
    "A cada 6 Horas": {
      "main": [
        [
          {
            "node": "Definir Configuração do Alvo [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Definir Configuração do Alvo [Schedule]": {
      "main": [
        [
          {
            "node": "Resolver Desafio Cloudflare [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resolver Desafio Cloudflare [Schedule]": {
      "main": [
        [
          {
            "node": "Preparar Requisição TLS [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar Requisição TLS [Schedule]": {
      "main": [
        [
          {
            "node": "Buscar via Servidor TLS [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar via Servidor TLS [Schedule]": {
      "main": [
        [
          {
            "node": "Extrair Resultado [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receber Solicitação do Resolvedor": {
      "main": [
        [
          {
            "node": "Definir Configuração do Alvo [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Definir Configuração do Alvo [Webhook]": {
      "main": [
        [
          {
            "node": "Resolver Desafio Cloudflare [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resolver Desafio Cloudflare [Webhook]": {
      "main": [
        [
          {
            "node": "Preparar Requisição TLS [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar Requisição TLS [Webhook]": {
      "main": [
        [
          {
            "node": "Buscar via Servidor TLS [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar via Servidor TLS [Webhook]": {
      "main": [
        [
          {
            "node": "Extrair Resultado [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extrair Resultado [Webhook]": {
      "main": [
        [
          {
            "node": "Retornar Token Resolvido",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
  }
}

---## Workflow: Exemplos de Casos de Uso

A API do Solver e o exemplo do scraper acima mostram o padrão principal: resolver o desafio, usar a solução para buscar via TLS. Os fluxos de trabalho a seguir estendem esse padrão para casos de uso prontos para produção — cada um com gatilhos duplos (agendamento + webhook), rastreamento persistente de estado e saída estruturada. Cada um requer os mesmos pré-requisitos: uma instância auto-hospedada do n8n, o servidor TLS rodando na porta 7878, um proxy residencial e uma credencial CapSolver.

Workflow Propósito
Cloudflare Challenge Scraping — Price & Product Details — CapSolver + Schedule + Webhook Raspagem de preço e nome do produto de uma página protegida por CF a cada 6 horas, compara com valores anteriores e alerta em caso de mudanças
Cloudflare Challenge Account Login — CapSolver + Schedule + Webhook Faz login na sua própria conta em um site protegido por CF resolvendo primeiro o desafio, depois enviando as credenciais via POST através do servidor TLS
Turnstile — Solver API Expõe um webhook que resolve o Turnstile e retorna o token — não necessita proxy nem servidor TLS
Turnstile Scraping — Price & Product Monitor Resolve o Turnstile, busca uma página de produto com o token, extrai preço e nome, e alerta sobre mudanças
Turnstile Account Login Faz login na sua própria conta em um site protegido por Turnstile resolvendo primeiro o desafio, depois enviando as credenciais via POST com o token — não necessita proxy nem servidor TLS

Este fluxo de trabalho faz scraping de uma página de produto a cada 6 horas (agendamento) ou sob demanda (webhook), extrai o preço usando o nó HTML e compara com o valor armazenado anteriormente.

Caminho do agendamento:

Copy
A cada 6 horas → Configurar alvo → Resolver desafio CF → Preparar requisição TLS
              → Buscar via servidor TLS → Extrair dados → Comparar dados
              → Dados alterados? → Construir alerta / Sem alteração

Tratamento de erros: Se o CapSolver falhar, o fluxo continua sem cookies (via continueOnFail). A busca via servidor TLS ainda pode ter sucesso se a página não estiver exibindo um desafio no momento.

Comportamentos chave:

  • Usa dataPropertyName: "body" (não "data") porque o servidor TLS retorna { status, body, headers }
  • O nó HTML extrai preço e nome do produto via seletores CSS (.product-price, h1)
  • $workflow.staticData.lastPrice mantém o preço anterior entre execuções
  • A comparação de preços detecta tanto quedas (gravidade: deal) quanto aumentos (gravidade: info)
  • Conversão automática do formato do proxy: host:port:user:pass → http://user:pass@host:port via helper toProxyURL()
Clique para expandir o JSON completo do fluxo de trabalho
json Copy
{
  "nodes": [
    {
      "parameters": {
        "content": "## Scraping de desafio do Cloudflare — Preço e detalhes do produto — CapSolver + Agendamento + Webhook\n\n### Como funciona\n\n1. Gatilhos são configurados para verificar periodicamente o site alvo ou em resposta a um webhook externo.\n2. Configurações para URL alvo e proxies são aplicadas.\n3. Os desafios do Cloudflare são resolvidos para navegar pelas proteções do site.\n4. Requisições seguras são feitas para buscar dados do servidor alvo.\n5. Dados extraídos são comparados para verificar alterações.\n6. Alertas são construídos e enviados ou os dados são retornados com base nas mudanças detectadas.\n\n### Passos de configuração\n\n- [ ] Configure a URL e as configurações de proxy nos nós 'Set Target Config'.\n- [ ] Conecte credenciais do CapSolver para resolver os desafios do Cloudflare.\n- [ ] Certifique-se de que a URL do webhook esteja configurada corretamente para receber requisições externas.\n\n### Personalização\n\nPara ajustar a frequência de monitoramento, modifique o intervalo no nó 'Every 6 Hours' ou nas configurações do gatilho webhook.",
        "width": 480,
        "height": 896
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1104,
        -192
      ],
      "id": "85c55c3d-335a-47e5-8721-82fa4d633033",
      "name": "Nota Adesiva"
    },
    {
      "parameters": {
        "content": "## Configuração do gatilho agendado\n\nInicializa o agendamento a cada 6 horas para iniciar o processo de scraping de dados via agendamento.",
        "width": 1392,
        "height": 272,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -544,
        -112
      ],
      "id": "6ac3bd35-66ef-43ed-a8b5-5d5f6d367fba",
      "name": "Nota Adesiva1"
    },
    {
      "parameters": {
        "content": "## Processamento de dados agendado\n\nLida com a extração, comparação e construção de alertas após ser acionado pelo agendamento.",
        "width": 1088,
        "height": 480,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        960,
        -192
      ],
      "id": "a1c60513-ed8b-43f2-bff3-a7b19436337f",
      "name": "Nota Adesiva2"
    },
    {
      "parameters": {
        "content": "## Configuração do gatilho webhook\n\nMonitora requisições externas via webhook para iniciar o processo de scraping.",
        "width": 1392,
        "height": 272,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -544,
        384
      ],
      "id": "ee4d9a0d-3233-4b70-828b-078c9eee0086",
      "name": "Nota Adesiva3"
    },
    {
      "parameters": {
        "content": "## Processamento e resposta de dados do webhook\n\nExtrai e compara dados do gatilho webhook; retorna respostas baseadas em mudanças.",
        "width": 1392,
        "height": 480,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        960,
        336
      ],
      "id": "4ad55fbf-2882-4c63-9e09-37e674b00145",
      "name": "Nota Adesiva4"
    },
    {
      "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": "A cada 6 Horas"
    },
    {
      "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": "Configurar Alvo [Agendamento]"
    },
    {
      "parameters": {
        "operation": "Cloudflare Challenge",
        "websiteURL": "={{ $json.targetURL }}",
        "proxy": "={{ $json.proxy }}"
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        100,
        0
      ],
      "id": "cf333333-3333-3333-3333-333333333303",
      "name": "Resolver Desafio Cloudflare [Agendamento]",
      "onError": "continueRegularOutput",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Conta CapSolver"
        }
      }
    },
    {
      "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": "Preparar Requisição TLS [Agendamento]"
    },
    {
      "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": "Buscar via Servidor TLS [Agendamento]"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "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": "Extrair Dados"
    },
    {
      "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": "Comparar Dados"
    },
    {
      "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.3,
      "position": [
        1600,
        0
      ],
      "id": "cf333333-3333-3333-3333-333333333308",
      "name": "Dados Alterados?"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "alert-001",
              "name": "alert",
              "value": "=Preço {{ $json.direction }} para {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $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": "Construir Alerta"
    },
    {
      "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": "Sem Alteração"
    },
    {
      "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": "Receber Requisição de Monitoramento",
      "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": "Configurar Alvo [Webhook]"
    },
    {
      "parameters": {
        "operation": "Cloudflare Challenge",
        "websiteURL": "={{ $json.targetURL }}",
        "proxy": "={{ $json.proxy }}"
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        100,
        500
      ],
      "id": "cf333333-3333-3333-3333-333333333313",
      "name": "Resolver Desafio Cloudflare [Webhook]",
      "onError": "continueRegularOutput",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Conta CapSolver"
        }
      }
    },
    {
      "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": "Preparar Requisição TLS [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": "Buscar via Servidor TLS [Webhook]"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "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": [
        1008,
        528
      ],
      "id": "cf333333-3333-3333-3333-333333333316",
      "name": "Extrair Dados [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": [
        1296,
        528
      ],
      "id": "cf333333-3333-3333-3333-333333333317",
      "name": "Comparar Dados [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.3,
      "position": [
        1600,
        528
      ],
      "id": "cf333333-3333-3333-3333-333333333318",
      "name": "Dados Alterados? [Webhook]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "alert-004",
              "name": "alert",
              "value": "=Preço {{ $json.direction }} para {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $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": [
        1904,
        448
      ],
      "id": "cf333333-3333-3333-3333-333333333319",
      "name": "Construir Alerta [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": [
        1904,
        656
      ],
      "id": "cf333333-3333-3333-3333-333333333320",
      "name": "Sem Alteração [Webhook]"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        2208,
        528
      ],
      "id": "cf333333-3333-3333-3333-333333333321",
      "name": "Retornar Dados Raspados"
    }
  ],
  "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
          }
        ]
      ]
    },
    "Receive Monitor Request": {
      "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": "Return Scraped Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "No Change [Webhook]": {
      "main": [
        [
          {
            "node": "Return Scraped Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
  }
}
### Exemplo 2: Login de Conta

Este fluxo de trabalho automatiza o login em um site protegido pelo Cloudflare. Um nó Set Login Config centraliza todos os parâmetros — [Schedule] para o caminho da agenda e [Webhook] para o caminho do webhook sob demanda.

Caminho da agenda:

Copy
A cada 24 horas → Set Login Config → Solve CF Challenge
               → Prepare TLS Login Request → Submit Login via TLS Server
               → Login Successful? → Marcar Sucesso / Marcar Falha

Tratamento de erros: Se o CapSolver falhar, o fluxo de trabalho continua sem cookies (via continueOnFail). A requisição de login provavelmente falhará, o que o nó Login Successful? detecta.

Comportamentos principais:

  • Usa cookie cf_clearance + userAgent como cabeçalhos HTTP (sem token no corpo do formulário — ao contrário do login reCAPTCHA que envia g-recaptcha-response)
  • Campos do formulário via URLSearchParams — edite os nomes dos campos (usernameField, passwordField) no Set Login Config para corresponder ao seu site
  • Login Successful? verifica status < 400 E successMarker no corpo da resposta
  • O caminho do webhook retorna o resultado em JSON via Respond to Webhook
Clique para expandir o JSON completo do fluxo de trabalho
json Copy
{
  "nodes": [
    {
      "parameters": {
        "content": "## Cloudflare Challenge Account Login \u2014 CapSolver + Schedule + Webhook\n\n### How it works\n\n1. Schedule a login process every 24 hours and solve the Cloudflare challenge.\n2. Prepare and submit a TLS login request when initiated by schedule.\n3. Handle success or failure of the scheduled login including logging results.\n4. Receive login requests via webhook and solve the Cloudflare challenge.\n5. Prepare and submit a TLS login request when initiated by webhook.\n6. Handle success or failure of the webhook login and return results.\n\n### Setup steps\n\n- [ ] Ensure Cloudflare CapSolver API credentials are configured.\n- [ ] Set up locally running TLS server at http://localhost:7878.\n- [ ] Configure webhook URL to receive login requests.\n\n### Customization\n\nAdjust scheduled intervals to meet specific frequency needs.",
        "width": 480,
        "height": 896
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1248,
        -320
      ],
      "id": "ba1d6098-8cd2-40f1-b9ae-b945303e5d12",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## Scheduled login start\n\nStarts the login process every 24 hours as a trigger point for further actions.",
        "width": 240,
        "height": 336,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -688,
        -256
      ],
      "id": "acc8f2a2-298f-4d1b-9db7-8a98fe626abb",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "## Scheduled login workflow\n\nHandles the Cloudflare challenge, prepares and submits the login request, and checks if it was successful every 24 hours.",
        "width": 1328,
        "height": 480,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -416,
        -320
      ],
      "id": "1259d9f4-0b54-4693-89af-193f3ccda6a0",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "## Webhook login start\n\nAccepts login requests via webhook to start the subsequent workflow.",
        "width": 240,
        "height": 320,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -688,
        272
      ],
      "id": "e95374d2-4029-469d-8e8f-a9afb66ae2ed",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "content": "## Webhook login workflow\n\nProcesses received webhook login requests, handles Cloudflare challenge, prepares and submits the login request, checks for success, and logs results.",
        "width": 1216,
        "height": 528,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -416,
        192
      ],
      "id": "da56a87e-6675-439a-8c65-7da631a86df1",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "content": "## Return webhook result\n\nResponds to the initial webhook request with the result of the login attempt.",
        "width": 240,
        "height": 320,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        832,
        256
      ],
      "id": "7a3f246c-ebd5-419f-a955-b01669743b31",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -640,
        -80
      ],
      "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": "your-email@example.com",
              "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": [
        -368,
        -80
      ],
      "id": "cf666666-6666-6666-6666-666666666602",
      "name": "Set Login Config [Schedule]"
    },
    {
      "parameters": {
        "operation": "Cloudflare Challenge",
        "websiteURL": "={{ $json.targetURL }}",
        "proxy": "={{ $json.proxy }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        -144,
        -64
      ],
      "id": "cf666666-6666-6666-6666-666666666603",
      "name": "Solve Cloudflare Challenge [Schedule]",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "CapSolver account"
        }
      }
    },
    {
      "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": [
        48,
        -64
      ],
      "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": [
        240,
        -64
      ],
      "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.3,
      "position": [
        432,
        -64
      ],
      "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": [
        768,
        -208
      ],
      "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": [
        768,
        0
      ],
      "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,
        432
      ],
      "id": "cf666666-6666-6666-6666-666666666609",
      "name": "Receive Login Request",
      "webhookId": "cf666666-aaaa-bbbb-cccc-666666666609"
    },
    {
      "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": [
        -368,
        480
      ],
      "id": "cf666666-6666-6666-6666-666666666610",
      "name": "Set Login Config [Webhook]"
    },
    {
      "parameters": {
        "operation": "Cloudflare Challenge",
        "websiteURL": "={{ $json.targetURL }}",
        "proxy": "={{ $json.proxy }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        -144,
        480
      ],
      "id": "cf666666-6666-6666-6666-666666666611",
      "name": "Solve Cloudflare Challenge [Webhook]",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "CapSolver account"
        }
      }
    },
    {
      "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": [
        48,
        480
      ],
      "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": [
        256,
        480
      ],
      "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.3,
      "position": [
        448,
        496
      ],
      "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": [
        640,
        320
      ],
      "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": [
        656,
        544
      ],
      "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": [
        880,
        416
      ],
      "id": "cf666666-6666-6666-6666-666666666617",
      "name": "Return Login Result"
    }
  ],
  "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
          }
        ]
      ]
    },
    "Receive Login Request": {
      "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": "Return Login Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Login Failed [Webhook]": {
      "main": [
        [
          {
            "node": "Return Login Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
  }
}
### Exemplo 3: Turnstile — API de Solver

Este fluxo cria um endpoint POST que resolve um desafio Cloudflare Turnstile e retorna o token. É o equivalente do Turnstile à Cloudflare Challenge Solver API acima — mas mais simples: sem proxy, sem servidor TLS, apenas 3 nós.

Fluxo:

Copy
Webhook (POST /solver-turnstile) → Resolver Turnstile (CapSolver) → Responder ao Webhook
  1. Webhook — Recebe requisições POST com websiteURL e websiteKey
  2. Resolver Turnstile — CapSolver resolve o desafio Turnstile usando AntiTurnstileTaskProxyLess
  3. Responder ao Webhook — Retorna os dados da solução (incluindo token)

Diferença chave em relação ao Cloudflare Challenge: Turnstile retorna uma string token, e não um cookie cf_clearance. Você envia esse token como um cabeçalho cf-turnstile-response (ou campo de formulário, dependendo do site) nas requisições subsequentes. Nenhum proxy é necessário.

Teste

bash Copy
curl -X POST https://your-n8n-instance.com/webhook/solver-turnstile \
  -H "Content-Type: application/json" \
  -d '{
    "websiteURL": "https://target-site.com/page",
    "websiteKey": "0x4AAAAAAA..."
  }'

Importe este fluxo de trabalho

Copie o JSON abaixo e importe-o no n8n via Menu → Importar do JSON. Após importar, selecione sua credencial CapSolver no nó Resolver Turnstile.

Clique para expandir o JSON do fluxo
json Copy
{
  "nodes": [
    {
      "parameters": {
        "content": "## Turnstile \u2014 Solver API\n\n### Como funciona\n\n1. Recebe uma solicitação de solver através de um webhook.\n2. Resolve o CAPTCHA Turnstile usando um nó solver especializado.\n3. Envia a resposta de volta via resposta do webhook.\n\n### Passos de configuração\n\n- [ ] Configure a URL do webhook para receber as solicitações.\n- [ ] Configure as credenciais para o nó capSolver.\n- [ ] Garanta que a URL de resposta do webhook esteja corretamente configurada.\n\n### Customização\n\nA configuração do nó solver pode ser ajustada para lidar com diferentes tipos de CAPTCHAs Turnstile.",
        "width": 480,
        "height": 560
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -848,
        -80
      ],
      "id": "d52f67cb-cb00-430f-bd76-b74cf4fe6184",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## Gerenciar solicitação do solver\n\nRecebe e processa uma solicitação para resolver um CAPTCHA Turnstile, depois envia o resultado de volta.",
        "width": 832,
        "height": 272,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -288,
        -80
      ],
      "id": "21f62617-eaa2-41ae-8fb8-c8502f21c275",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "solver-turnstile",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -240,
        32
      ],
      "id": "ts-001",
      "name": "Receber Solicitação do Solver",
      "webhookId": "a7ef0297-8455-44bd-9305-26c179f040b5",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "Cloudflare Turnstile",
        "websiteURL": "={{ $json.body.websiteURL }}",
        "websiteKey": "={{ $json.body.websiteKey }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        80,
        32
      ],
      "id": "ts-002",
      "name": "Resolver Turnstile",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Conta CapSolver"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json.data) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        400,
        32
      ],
      "id": "ts-003",
      "name": "Responder ao Webhook"
    }
  ],
  "connections": {
    "Receber Solicitação do Solver": {
      "main": [
        [
          {
            "node": "Resolver Turnstile",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resolver Turnstile": {
      "main": [
        [
          {
            "node": "Responder ao Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
  }
}
### Exemplo 4: Raspagem Turnstile — Monitor de Preço e Produto

Este fluxo de trabalho resolve o Cloudflare Turnstile, acessa uma página de produto com o token resolvido, extrai o preço e o nome do produto, e compara com o valor anterior — emitindo alerta em caso de mudanças. Ele segue o mesmo padrão de gatilho duplo (agendamento + webhook) como o exemplo de raspagem do Cloudflare Challenge acima.

Diferença chave em relação à raspagem do Cloudflare Challenge: Sem servidor TLS, sem proxy, sem nó de código Prepare TLS Request. O token Turnstile é enviado como um cabeçalho cf-turnstile-response diretamente através do nó HTTP Request integrado do n8n.

Caminho pelo agendamento:

Copy
A cada 6 horas → Definir Config. Alvo → Resolver Turnstile → Buscar Página do Produto
              → Extrair Dados → Comparar Dados → Dados Alterados? → Construir Alerta / Sem Mudança

Caminho pelo webhook:

Copy
Gatilho Webhook → Resolver Turnstile → Buscar Página do Produto
               → Extrair Dados → Comparar Dados → Dados Alterados? → Construir Alerta / Sem Mudança
               → Responder ao Webhook

Comportamentos principais:

  • A operação CapSolver é Cloudflare Turnstile (não Cloudflare Challenge) — usa AntiTurnstileTaskProxyLess internamente
  • O token é enviado como cabeçalho cf-turnstile-response na requisição de busca
  • Não há necessidade de conversão de formato de proxy — resoluções Turnstile não usam proxies
  • Nó HTTP Request padrão do n8n — sem servidor TLS necessário, pois não existe cookie cf_clearance para emparelhar impressões digitais
  • Mesma lógica de comparação de preço da versão Challenge: $workflow.staticData.lastPrice para persistência entre execuções
  • O caminho do webhook lê websiteURL e websiteKey diretamente do corpo POST (não é necessário nó Set Target Config)
Clique para expandir o JSON do fluxo de trabalho
json Copy
{
  "nodes": [
    {
      "parameters": {
        "content": "## Raspagem Turnstile — Monitor de Preço e Produto\n\n### Como funciona\n\n1. O fluxo é acionado a cada 6 horas ou via webhook.\n2. Configuração do alvo é definida, incluindo o URL do site e a chave.\n3. O captcha Turnstile é resolvido para acessar a página do produto.\n4. Dados do produto são buscados e dados relevantes são extraídos.\n5. Os dados extraídos são comparados aos dados anteriores para identificar mudanças.\n6. Alertas são gerados se houver mudanças, e uma resposta é enviada para requisições via webhook.\n\n### Etapas de configuração\n\n- [ ] Configurar intervalo do gatilho agendado conforme necessário.\n- [ ] Configurar URL do webhook para acionamento em tempo real.\n- [ ] Garantir que as credenciais do resolvedor de captcha estejam válidas.\n- [ ] Configurar URL do site alvo e chave do produto.\n\n### Personalização\n\nO intervalo do gatilho agendado pode ser ajustado com base nas necessidades de monitoramento.",
        "width": 480,
        "height": 896
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1184,
        -240
      ],
      "id": "1824aba9-471e-4052-912e-888d939349df",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## Gatilho de raspagem agendada\n\nInicia o fluxo a cada 6 horas e define configurações do alvo.",
        "width": 512,
        "height": 304,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -624,
        -80
      ],
      "id": "89b7d6a2-b4bf-4a7d-8667-ce3f31d2eb92",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "## Captcha e busca agendada\n\nResolve o captcha e busca os dados da página do produto com base no agendamento.",
        "width": 1472,
        "height": 272,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        16,
        -64
      ],
      "id": "f39fc94b-d0ae-4141-9491-fa82702a72fc",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "## Avaliação dos dados agendada\n\nCompara os dados recém-buscados com os anteriores para detectar mudanças e constrói alertas.",
        "width": 240,
        "height": 528,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1536,
        -240
      ],
      "id": "0d31be95-f94c-40fd-99cd-7d988109d3f4",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "content": "## Gatilho de raspagem por webhook\n\nAciona o fluxo de raspagem via webhook para atualizações em tempo real.",
        "width": 240,
        "height": 352,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -624,
        256
      ],
      "id": "e4a50f47-180c-484e-bf70-09a46543e01b",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "content": "## Captcha e busca via webhook\n\nResolve o captcha e busca os dados da página do produto para o gatilho do webhook.",
        "width": 1472,
        "height": 272,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        16,
        336
      ],
      "id": "1167cf0e-d561-40fa-b366-331a20d99a31",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "content": "## Avaliação dos dados e resposta via webhook\n\nAvalia mudanças nos dados e responde ao webhook com os resultados.",
        "width": 672,
        "height": 432,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1536,
        320
      ],
      "id": "0dab95b9-d762-43cf-9a11-b92212a8c2a7",
      "name": "Sticky Note6"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -576,
        48
      ],
      "id": "ts-s-01",
      "name": "A cada 6 Horas"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "cfg-001",
              "name": "websiteURL",
              "value": "https://YOUR-TARGET-SITE.com/product-page",
              "type": "string"
            },
            {
              "id": "cfg-002",
              "name": "websiteKey",
              "value": "YOUR_SITE_KEY_HERE",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -256,
        48
      ],
      "id": "ts-s-02",
      "name": "Definir Config. Alvo [Agendamento]"
    },
    {
      "parameters": {
        "operation": "Cloudflare Turnstile",
        "websiteURL": "={{ $json.websiteURL }}",
        "websiteKey": "={{ $json.websiteKey }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        64,
        48
      ],
      "id": "ts-s-03",
      "name": "Resolver Turnstile",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Conta CapSolver"
        }
      }
    },
    {
      "parameters": {
        "url": "={{ $('Set Target Config [Schedule]').first().json.websiteURL }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "user-agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, como Gecko) Chrome/125.0.0.0 Safari/537.36"
            },
            {
              "name": "cf-turnstile-response",
              "value": "={{ $json.data.solution.token }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {}
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        384,
        48
      ],
      "id": "ts-s-04",
      "name": "Buscar Página do Produto"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "extractionValues": {
          "values": [
            {
              "key": "price",
              "cssSelector": ".product-price, [data-price], .price"
            },
            {
              "key": "productName",
              "cssSelector": "h1, .product-title"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        704,
        48
      ],
      "id": "ts-s-05",
      "name": "Extrair Dados"
    },
    {
      "parameters": {
        "jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Produto';\nconst parsePrice = (str) => { if (!str) return null; const match = str.match(/[\\d]+\\.?\\d*/); return match ? parseFloat(match[0].replace(',', '')) : null; };\nconst currentNum = parsePrice(currentPrice);\nconst previousNum = parsePrice(previousPrice);\nstaticData.lastPrice = currentPrice;\nstaticData.lastChecked = new Date().toISOString();\nconst changed = previousNum !== null && currentNum !== null && currentNum !== previousNum;\nconst direction = changed ? (currentNum < previousNum ? 'diminuiu' : 'aumentou') : 'inalterado';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\nreturn [{ json: { productName, currentPrice, previousPrice: previousPrice || 'verificação inicial', changed, direction, diff: changed ? `$${diff}` : null, checkedAt: new Date().toISOString() } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1072,
        48
      ],
      "id": "ts-s-06",
      "name": "Comparar Dados"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "if-1",
              "leftValue": "={{ $json.changed }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1344,
        48
      ],
      "id": "ts-s-07",
      "name": "Dados Alterados?"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "alert",
              "value": "=Preço {{ $json.direction }} para {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $json.currentPrice }}",
              "type": "string"
            },
            {
              "id": "a2",
              "name": "severity",
              "value": "={{ $json.direction === 'diminuiu' ? 'oferta' : 'info' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1584,
        -48
      ],
      "id": "ts-s-08",
      "name": "Construir Alerta"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "n1",
              "name": "status",
              "value": "sem_mudança",
              "type": "string"
            },
            {
              "id": "n2",
              "name": "currentPrice",
              "value": "={{ $json.currentPrice }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1584,
        128
      ],
      "id": "ts-s-09",
      "name": "Sem Mudança"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "price-monitor-turnstile",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -576,
        448
      ],
      "id": "ts-s-10",
      "name": "Gatilho Webhook",
      "webhookId": "6a4f76c7-fc5c-440d-96cb-75c9c3bebcdb",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "Cloudflare Turnstile",
        "websiteURL": "={{ $json.body.websiteURL }}",
        "websiteKey": "={{ $json.body.websiteKey }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        64,
        448
      ],
      "id": "ts-s-11",
      "name": "Resolver Turnstile [W]",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Conta CapSolver"
        }
      }
    },
    {
      "parameters": {
        "url": "={{ $('Webhook Trigger').item.json.body.websiteURL }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "user-agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, como Gecko) Chrome/125.0.0.0 Safari/537.36"
            },
            {
              "name": "cf-turnstile-response",
              "value": "={{ $json.data.solution.token }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {}
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        384,
        448
      ],
      "id": "ts-s-12",
      "name": "Buscar Página do Produto [W]"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "extractionValues": {
          "values": [
            {
              "key": "price",
              "cssSelector": ".product-price, [data-price], .price"
            },
            {
              "key": "productName",
              "cssSelector": "h1, .product-title"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        704,
        448
      ],
      "id": "ts-s-13",
      "name": "Extrair Dados [W]"
    },
    {
      "parameters": {
        "jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Produto';\nconst parsePrice = (str) => { if (!str) return null; const match = str.match(/[\\d]+\\.?\\d*/); return match ? parseFloat(match[0].replace(',', '')) : null; };\nconst currentNum = parsePrice(currentPrice);\nconst previousNum = parsePrice(previousPrice);\nstaticData.lastPrice = currentPrice;\nstaticData.lastChecked = new Date().toISOString();\nconst changed = previousNum !== null && currentNum !== null && currentNum !== previousNum;\nconst direction = changed ? (currentNum < previousNum ? 'diminuiu' : 'aumentou') : 'inalterado';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\nreturn [{ json: { productName, currentPrice, previousPrice: previousPrice || 'verificação inicial', changed, direction, diff: changed ? `$${diff}` : null, checkedAt: new Date().toISOString() } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1040,
        448
      ],
      "id": "ts-s-14",
      "name": "Comparar Dados [W]"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "if-2",
              "leftValue": "={{ $json.changed }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1344,
        448
      ],
      "id": "ts-s-15",
      "name": "Dados Alterados? [W]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a4",
              "name": "alert",
              "value": "=Preço {{ $json.direction }} para {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $json.currentPrice }}",
              "type": "string"
            },
            {
              "id": "a5",
              "name": "severity",
              "value": "={{ $json.direction === 'diminuiu' ? 'oferta' : 'info' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1584,
        432
      ],
      "id": "ts-s-16",
      "name": "Construir Alerta [W]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "n4",
              "name": "status",
              "value": "sem_mudança",
              "type": "string"
            },
            {
              "id": "n5",
              "name": "currentPrice",
              "value": "={{ $json.currentPrice }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1584,
        592
      ],
      "id": "ts-s-17",
      "name": "Sem Mudança [W]"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        2064,
        544
      ],
      "id": "ts-s-18",
      "name": "Responder ao Webhook"
    }
  ],
  "connections": {
    "Every 6 Hours": {
      "main": [
        [
          {
            "node": "Set Target Config [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Target Config [Schedule]": {
      "main": [
        [
          {
            "node": "Solve Turnstile",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solve Turnstile": {
      "main": [
        [
          {
            "node": "Fetch Product Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Product Page": {
      "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": "Solve Turnstile [W]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solve Turnstile [W]": {
      "main": [
        [
          {
            "node": "Fetch Product Page [W]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Product Page [W]": {
      "main": [
        [
          {
            "node": "Extract Data [W]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Data [W]": {
      "main": [
        [
          {
            "node": "Compare Data [W]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare Data [W]": {
      "main": [
        [
          {
            "node": "Data Changed? [W]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Changed? [W]": {
      "main": [
        [
          {
            "node": "Build Alert [W]",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Change [W]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Alert [W]": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "No Change [W]": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
  }
}
### Exemplo 5: Login de Conta Turnstile

Este fluxo de trabalho automatiza o login em um site protegido pelo Turnstile. Ele segue o mesmo padrão de gatilho duplo (agenda + webhook) como o Login de Conta Cloudflare Challenge acima — mas sem o servidor TLS, proxy ou nó de código personalizado.

Diferença chave em relação ao login Cloudflare Challenge: Sem servidor TLS, sem proxy, sem nó de código Prepare TLS Login Request. O token Turnstile é enviado como um campo de formulário cf-turnstile-response diretamente pelo nó HTTP Request integrado do n8n. As credenciais são enviadas como parâmetros padrão no corpo form-urlencoded.

Caminho da agenda:

Copy
A cada 24 horas → Definir Configuração de Login → Resolver Turnstile → Submeter Login
                 → Login OK? → Marcar Sucesso / Marcar Falha

Caminho do webhook:

Copy
Gatilho Webhook → Resolver Turnstile → Submeter Login
                → Login OK? → Marcar Sucesso / Marcar Falha → Responder ao Webhook

Comportamentos principais:

  • A operação CapSolver é Cloudflare Turnstile (não Cloudflare Challenge) — usa AntiTurnstileTaskProxyLess, não requer proxy
  • O token é enviado como campo de formulário cf-turnstile-response no corpo POST (não como cookie header como no CF Challenge)
  • Não é necessário nó de código personalizado — o nó HTTP Request lida com a submissão form-urlencoded diretamente com campos email, password e cf-turnstile-response
  • Login OK? verifica statusCode < 400 E successMarker no corpo da resposta — mesmo padrão do login CF Challenge
  • O caminho da agenda usa credenciais fixas em Definir Configuração de Login; o caminho do webhook lê usernameValue, passwordValue, usernameField, passwordField, loginActionURL, successMarker do corpo POST
  • O caminho do webhook suporta nomes de campos dinâmicos — o parâmetro name de cada campo de formulário é uma expressão ($('Webhook Trigger').item.json.body.usernameField || 'email'), para que os chamadores possam especificar os nomes dos campos do site deles
Clique para expandir o JSON do fluxo de trabalho
json Copy
{
  "nodes": [
    {
      "parameters": {
        "content": "## Turnstile Account Login\n\n### How it works\n\n1. Triggers a login process every 24 hours using a schedule.\n2. Sets up the login configuration and solves Turnstile challenges.\n3. Submits the login form and checks if the login was successful.\n4. Marks the login attempt as success or failure in the schedule flow.\n5. Alternatively, starts a login process via a webhook trigger and executes similar steps for webhook-based logins.\n\n### Setup steps\n\n- [ ] Schedule a periodic execution by setting up a scheduler.\n- [ ] Configure webhook endpoint for external triggers.\n- [ ] Set login credentials and URL configurations.\n\n### Customization\n\nAdjust timing in the scheduler or modify webhook response handling as needed.",
        "width": 480,
        "height": 896
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1168,
        -160
      ],
      "id": "8ca80c21-2de5-41e7-b3e4-de184fc1d8fe",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## Scheduled login flow\n\nTriggers every 24 hours to perform login steps",
        "width": 1920,
        "height": 448,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -608,
        -160
      ],
      "id": "533be07a-6fe7-4ada-a40c-7a7749ba968d",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "## Webhook login flow\n\nHandles login requests triggered by a webhook",
        "width": 2288,
        "height": 416,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -608,
        320
      ],
      "id": "c6a8e296-2bfb-4ffa-8819-aa420e936589",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -560,
        48
      ],
      "id": "ts-l-01",
      "name": "Every 24 Hours"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "l1",
              "name": "websiteURL",
              "value": "https://YOUR-LOGIN-PAGE.com",
              "type": "string"
            },
            {
              "id": "l2",
              "name": "websiteKey",
              "value": "YOUR_SITE_KEY_HERE",
              "type": "string"
            },
            {
              "id": "l3",
              "name": "successMarker",
              "value": "account-dashboard",
              "type": "string"
            },
            {
              "id": "l4",
              "name": "userAgent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -240,
        48
      ],
      "id": "ts-l-02",
      "name": "Set Login Config [Schedule]"
    },
    {
      "parameters": {
        "operation": "Cloudflare Turnstile",
        "websiteURL": "={{ $json.websiteURL }}",
        "websiteKey": "={{ $json.websiteKey }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        256,
        48
      ],
      "id": "ts-l-03",
      "name": "Solve Turnstile [Schedule]",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "CapSolver account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Set Login Config [Schedule]').item.json.websiteURL }}/login",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/x-www-form-urlencoded"
            },
            {
              "name": "user-agent",
              "value": "={{ $('Set Login Config [Schedule]').item.json.userAgent }}"
            }
          ]
        },
        "sendBody": true,
        "contentType": "form-urlencoded",
        "bodyParameters": {
          "parameters": [
            {
              "name": "email",
              "value": "your-email@example.com"
            },
            {
              "name": "password",
              "value": "YOUR_ACCOUNT_PASSWORD"
            },
            {
              "name": "cf-turnstile-response",
              "value": "={{ $json.data.solution.token }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        576,
        48
      ],
      "id": "ts-l-04",
      "name": "Submit Login [Schedule]"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "lif1",
              "leftValue": "={{ $json.statusCode < 400 && String($json.body || $json.data || '').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": [
        896,
        48
      ],
      "id": "ts-l-05",
      "name": "Login OK? [Schedule]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "s1",
              "name": "status",
              "value": "success",
              "type": "string"
            },
            {
              "id": "s2",
              "name": "checkedAt",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1168,
        -48
      ],
      "id": "ts-l-06",
      "name": "Mark Success"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "f1",
              "name": "status",
              "value": "failed",
              "type": "string"
            },
            {
              "id": "f2",
              "name": "statusCode",
              "value": "={{ $json.statusCode }}",
              "type": "number"
            },
            {
              "id": "f3",
              "name": "checkedAt",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1168,
        128
      ],
      "id": "ts-l-07",
      "name": "Mark Failed"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "account-login-turnstile",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -560,
        544
      ],
      "id": "ts-l-08",
      "name": "Webhook Trigger",
      "webhookId": "9c7a53a4-d3ee-495b-9381-3a9425bb1b36"
    },
    {
      "parameters": {
        "operation": "Cloudflare Turnstile",
        "websiteURL": "={{ $json.body.websiteURL }}",
        "websiteKey": "={{ $json.body.websiteKey }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        256,
        544
      ],
      "id": "ts-l-09",
      "name": "Solve Turnstile [Webhook]",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "CapSolver account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Webhook Trigger').item.json.body.loginActionURL }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/x-www-form-urlencoded"
            },
            {
              "name": "user-agent",
              "value": "={{ $('Webhook Trigger').item.json.body.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36' }}"
            }
          ]
        },
        "sendBody": true,
        "contentType": "form-urlencoded",
        "bodyParameters": {
          "parameters": [
            {
              "name": "={{ $('Webhook Trigger').item.json.body.usernameField || 'email' }}",
              "value": "={{ $('Webhook Trigger').item.json.body.usernameValue }}"
            },
            {
              "name": "={{ $('Webhook Trigger').item.json.body.passwordField || 'password' }}",
              "value": "={{ $('Webhook Trigger').item.json.body.passwordValue }}"
            },
            {
              "name": "cf-turnstile-response",
              "value": "={{ $json.data.solution.token }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        576,
        544
      ],
      "id": "ts-l-10",
      "name": "Submit Login [Webhook]"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "lif2",
              "leftValue": "={{ $json.statusCode < 400 && String($json.body || $json.data || '').includes($('Webhook Trigger').item.json.body.successMarker) }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        896,
        544
      ],
      "id": "ts-l-11",
      "name": "Login OK? [Webhook]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "ws1",
              "name": "status",
              "value": "success",
              "type": "string"
            },
            {
              "id": "ws2",
              "name": "checkedAt",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1168,
        432
      ],
      "id": "ts-l-12",
      "name": "Mark Success [W]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "wf1",
              "name": "status",
              "value": "failed",
              "type": "string"
            },
            {
              "id": "wf2",
              "name": "statusCode",
              "value": "={{ $json.statusCode }}",
              "type": "number"
            },
            {
              "id": "wf3",
              "name": "checkedAt",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1168,
        576
      ],
      "id": "ts-l-13",
      "name": "Mark Failed [W]"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        1536,
        544
      ],
      "id": "ts-l-14",
      "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 Turnstile [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solve Turnstile [Schedule]": {
      "main": [
        [
          {
            "node": "Submit Login [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit Login [Schedule]": {
      "main": [
        [
          {
            "node": "Login OK? [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Login OK? [Schedule]": {
      "main": [
        [
          {
            "node": "Mark Success",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Solve Turnstile [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solve Turnstile [Webhook]": {
      "main": [
        [
          {
            "node": "Submit Login [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit Login [Webhook]": {
      "main": [
        [
          {
            "node": "Login OK? [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Login OK? [Webhook]": {
      "main": [
        [
          {
            "node": "Mark Success [W]",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Failed [W]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Success [W]": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Failed [W]": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
  }
}
## Conclusão

Você construiu uma pipeline completa para contornar o Cloudflare Challenge no n8n — sem automação de navegador, sem Puppeteer, sem Playwright. Apenas três componentes trabalhando juntos: CapSolver para resolver o desafio, um servidor TLS em Go para falsificar a impressão digital de rede do Chrome, e um fluxo de trabalho n8n para orquestrar tudo.

A chave é que resolver o desafio é apenas metade do problema. Sem corresponder as impressões digitais TLS na busca subsequente, o cf_clearance é inútil — o Cloudflare inspeciona o handshake, não só o cookie. O servidor TLS httpcloak lida com essa camada, fazendo com que a busca seja indistinguível de um navegador Chrome real em nível de rede.

O repositório agora oferece templates reais para sites protegidos pelo Cloudflare:

  • Challenge Solver API — expõe um webhook que retorna o cf_clearance bruto + userAgent para aplicações externas
  • Scraping — extrai dados de preço e produto de páginas protegidas pelo Cloudflare, com detecção de mudanças
  • Login de conta — faça login na sua própria conta protegida pelo Cloudflare
  • Turnstile Solver API — um webhook com 3 nós que retorna um token Turnstile (sem proxy, sem servidor TLS)
  • Turnstile Scraping — monitoramento de preços em páginas protegidas pelo Turnstile usando o nó HTTP Request embutido do n8n
  • Turnstile Account Login — login em sites protegidos pelo Turnstile com credenciais form-urlencoded e token resolvido

A Solver API é o ponto de entrada mais simples — 4 nós, sem necessidade de servidor TLS. Os fluxos Turnstile são ainda mais simples — não há necessidade de proxy ou servidor TLS, pois o Turnstile retorna um token (não um cookie vinculado a IP) e não faz fingerprint TLS. Para fluxos Cloudflare Challenge que buscam páginas diretamente, o CapSolver resolve o desafio e o servidor TLS faz a requisição real. Configure os placeholders, mantenha os fluxos inativos até que estejam adaptados ao seu alvo, e então ative.

Dica: Esses fluxos usam triggers Schedule + Webhook, mas você pode trocar o nó trigger para qualquer gatilho do n8n — manual, evento de app, submissão de formulário, etc. Depois de buscar os dados, use os nós internos do n8n para salvar resultados no Google Sheets, bancos de dados, armazenamento em nuvem, ou enviar alertas via Telegram/Slack/Email.


Pronto para começar? Cadastre-se no CapSolver e use o código bônus n8n para um bônus extra de 8% no seu primeiro recarregamento!

Banner do código bônus CapSolver

Perguntas Frequentes

O que é AntiCloudflareTask, e como ele difere do AntiTurnstileTaskProxyLess?

AntiCloudflareTask resolve o desafio completo de Bot Management do Cloudflare — a tela "Just a moment…" que bloqueia totalmente o acesso ao site. Ele requer um proxy porque o CapSolver precisa carregar a página protegida real através de um navegador. AntiTurnstileTaskProxyLess resolve widgets Turnstile embutidos em páginas (formulários de login, cadastro) e não requer proxy. Desafios diferentes, tipos de tarefas diferentes.

Por que não posso usar apenas o nó HTTP Request embutido do n8n para buscar a página?

O nó HTTP Request do n8n usa a biblioteca padrão Go net/http, que tem uma impressão digital TLS distinta que o Cloudflare detecta. Mesmo com um cookie cf_clearance válido, o Cloudflare vai desafiar novamente qualquer requisição que não combine com um perfil TLS conhecido de navegador. O servidor TLS resolve isso usando o httpcloak para falsificar a pilha TLS de um Chrome real.

Por que meu proxy de datacenter continua falhando?

A pontuação de bots do Cloudflare atribui scores de risco a endereços IP. IPs de datacenter (AWS, GCP, provedores VPS etc.) são bem conhecidos e recebem scores altos de risco. O AntiCloudflareTask usa seu proxy para carregar a página do desafio, e se o Cloudflare detecta que o IP é de datacenter, ele serve um desafio mais difícil que o CapSolver não consegue resolver, ou falha completamente. IPs residenciais e móveis têm scores de risco mais baixos e passam com mais confiabilidade.

Os fluxos Turnstile precisam do servidor TLS ou de um proxy?

Não. Turnstile é fundamentalmente diferente do Cloudflare Challenge. Turnstile retorna um token de curta duração que você envia como header ou campo de formulário — não está vinculado a um IP ou impressão digital TLS. O CapSolver resolve Turnstile usando AntiTurnstileTaskProxyLess, que não requer proxy. E como você envia um token (não um cookie vinculado a IP), o nó HTTP Request embutido do n8n funciona bem — não é necessário falsificação da impressão digital TLS.

O cf_clearance expira?

Sim. O prazo depende da configuração do Cloudflare do site — pode variar de alguns minutos até 24 horas. Para trabalhos recorrentes de scraping, o fluxo agendado (a cada 6 horas) resolve o desafio regularmente. Para scraping sob demanda, o caminho webhook resolve um novo desafio a cada requisição.

Ver mais

Web ScrapingApr 22, 2026

Arquitetura de Web Scraping em Rust para Extração de Dados Escalável

Aprenda arquitetura de raspagem web escalável em Rust com reqwest, scraper, raspagem assíncrona, raspagem de navegador headless, rotação de proxies e tratamento de CAPTCHA compatível.

Adélia Cruz
Adélia Cruz
Web ScrapingApr 08, 2026

Selenium vs Puppeteer para Resolução de CAPTCHA: Comparação de Desempenho e Caso de Uso

Compare o Selenium vs Puppeteer para resolver CAPTCHA. Descubra benchmarks de desempenho, notas de estabilidade e como integrar o CapSolver para o máximo de sucesso.

Ethan Collins
Ethan Collins
Web ScrapingFeb 10, 2026

Dados como Serviço (DaaS): O que é e por que importa em 2026

Entenda Dados como Serviço (DaaS) em 2026. Descubra seus benefícios, casos de uso e como transforma os negócios com visões em tempo real e escalabilidade.

Ethan Collins
Ethan Collins
Web ScrapingFeb 05, 2026

Como corrigir erros comuns de raspagem da web em 2026

Dominar a correção de diversos erros de raspagem de web, como 400, 401, 402, 403, 429, 5xx e 1001 do Cloudflare em 2026. Aprenda estratégias avançadas para rotação de IPs, cabeçalhos e limitação de taxa adaptativa com o CapSolver.

Rajinder Singh
Rajinder Singh

Índice

Blog
Web Scraping