
Aloísio Vítor
Image Processing Expert

La protección contra bots de Cloudflare va mucho más allá de los widgets CAPTCHA. El Desafío de Cloudflare — la pantalla de página completa "Verificando tu navegador…" que bloquea el acceso a un sitio completamente — es una de las defensas contra bots más agresivas en la web. Ejecuta un desafío completo de JavaScript en un entorno real de navegador, verifica señales de comportamiento y obtiene la huella digital de tu conexión TLS antes de permitirte el acceso.
Las herramientas de automatización estándar fallan aquí. No porque no puedan resolver el desafío, sino porque Cloudflare obtiene la huella digital del propio handshake TLS — y cualquier cliente HTTP no navegador es bloqueado antes de que se sirva el desafío, o vuelve a ser desafiado inmediatamente después, incluso con una cookie válida cf_clearance.
En esta guía, aprenderás cómo construir un scraper para el Desafío de Cloudflare en n8n que realmente funciona — combinando CapSolver para resolver el desafío, un servidor TLS local en Go para falsificar la huella digital TLS de Chrome, y un flujo de trabajo en n8n para unirlo todo.
Lo que construirás:
El Desafío de Cloudflare (también llamado desafío JS o desafío de Bot Management) es un intersticial de página completa que Cloudflare inserta antes de que un visitante pueda acceder a un sitio protegido. Lo has visto: una pantalla negra o blanca con "Verificando tu navegador…" o "Solo un momento…" y una barra de carga o el logo de Cloudflare.
A diferencia de Turnstile — que es un pequeño widget incrustado dentro de una página — el Desafío de Cloudflare ocupa toda la página. No puedes acceder a ningún contenido hasta que se complete.
| Desafío de Cloudflare | Cloudflare Turnstile | |
|---|---|---|
| Dónde aparece | Intersticial de página completa — bloquea el acceso al sitio completamente | Widget incrustado dentro de una página (por ejemplo, formulario de inicio de sesión) |
| Cómo luce | Pantalla de carga "Verificando tu navegador…" | Una pequeña casilla de verificación o widget invisible en un formulario |
| Quién lo añade | Cloudflare lo añade automáticamente basado en reglas de seguridad | El propietario del sitio lo inserta en su HTML |
| Enfoque para resolver | AntiCloudflareTask — requiere proxy |
AntiTurnstileTaskProxyLess — no requiere proxy |
| Cookie devuelta | cf_clearance (específica de dominio, vinculada a IP) |
Token de Turnstile (de corta duración, se usa una vez) |
| ¿Requiere proxy? | Sí — la misma IP debe usarse para resolver y para la obtención | No |
Si ves una casilla de verificación o widget incrustado dentro de un formulario, eso es Turnstile — no este desafío. Consulta la guía de CapSolver para identificar tipos de desafío si tienes dudas.
Aquí está el problema que la mayoría de las guías omiten: Cloudflare verifica tu huella digital TLS, no solo tus cookies.
Cuando un navegador se conecta a un sitio web vía HTTPS, envía un ClientHello TLS que incluye detalles sobre los conjuntos de cifrado soportados, extensiones y configuraciones. Cloudflare registra esta huella digital (llamada huella JA3 o JA4) y la compara con perfiles de navegadores conocidos.
Las bibliotecas net/http de Go, requests de Python, curl y la mayoría de librerías HTTP tienen huellas TLS distintas. Incluso si CapSolver resuelve exitosamente el desafío y devuelve una cookie válida cf_clearance, Cloudflare volverá a desafiar o bloqueará la solicitud si detecta una huella TLS no navegador en la petición subsecuente.
La solución: un servidor Go usando httpcloak — una librería que falsifica una pila TLS real de Chrome incluyendo:
Esto hace que la solicitud luzca exactamente como una solicitud del navegador Chrome a nivel de red.
| Requisito | Notas |
|---|---|
| n8n autohospedado | Requerido — el servidor TLS debe ejecutarse en la misma máquina que n8n. n8n Cloud no es adecuado para este caso. |
| Cuenta CapSolver | Regístrate aquí y obtén tu clave API |
| Go 1.21+ | Debe estar instalado en el servidor de n8n. Verifica con go version. |
| Proxy residencial o móvil | Los proxies de centro de datos fallarán en la mayoría de los sitios protegidos por Cloudflare. Ver Requisitos de Proxy abajo. |
CapSolver está disponible como una integración oficial en n8n — no se requiere instalar nodos de la comunidad.
Ve a tu instancia n8n y navega a Configuración → Credenciales.

AllDeberías ver un banner verde que indica "Conexión probada correctamente".

Importante: Cada nodo CapSolver en tus flujos de trabajo hará referencia a esta credencial. Solo necesitas crearla una vez — todos tus flujos solucionadores compartirán la misma credencial.
Este servidor Go recibe solicitudes de obtención de n8n y las ejecuta usando el perfil TLS Chrome de httpcloak. Es un binario pequeño y auto contenido que ejecutas junto a n8n.
Crea un directorio y guarda lo siguiente en main.go:
mkdir -p ~/tls-server && cd ~/tls-server
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))
}
go mod init tls-server
go get github.com/sardanioss/httpcloak/client
go build -o main main.go
./main
curl http://localhost:7878/health
Esperado: {"status":"ok"}
Nota: El servidor TLS debe ejecutarse en la misma máquina que tu instancia n8n. El flujo de trabajo de n8n lo llama en
http://localhost:7878/fetch. Si usas n8n Cloud, necesitarás una configuración autohospedada — esta es una de las razones por las que se recomienda fuertemente n8n autohospedado para scraping con el Desafío de Cloudflare.
Por defecto, n8n bloquea nodos de solicitud HTTP que llamen a direcciones localhost (protección SSRF). Necesitas deshabilitar esta restricción.
Agrega la variable de entorno N8N_BLOCK_ACCESS_TO_LOCALHOST=false y reinicia tu instancia n8n. Cómo lo hagas depende de cómo ejecutes n8n:
Si ejecutas n8n directamente:
export N8N_BLOCK_ACCESS_TO_LOCALHOST=false
n8n start
Si usas Docker:
Agrega -e N8N_BLOCK_ACCESS_TO_LOCALHOST=false a tu comando docker run, o añádelo en la sección environment de tu docker-compose.yml.
Este flujo crea un endpoint POST que acepta una URL protegida por Cloudflare y un proxy, resuelve el desafío usando CapSolver y devuelve la cookie cruda cf_clearance y el userAgent. No se necesita servidor TLS — tu aplicación maneja la obtención.
Webhook (POST /solver-cloudflare-challenge) → Desafío de Cloudflare (CapSolver)
→ Formatear solución → Responder al webhook
4 nodos, solo webhook, sin ruta programada, sin dependencia de servidor TLS.
websiteURL y proxyAntiCloudflareTaskcookies a una cadena de cookies, maneja errores con continueOnFailcf_clearance, cadena de cookies serializada y userAgent### Configuración del Nodo| Configuración | Valor |
|---|---|
| Método HTTP | POST |
| Ruta | solver-cloudflare-challenge |
| Responder | Response Node |
Esto crea un endpoint en: https://tu-instancia-n8n.com/webhook/solver-cloudflare-challenge
| Parámetro | Valor | Descripción |
|---|---|---|
| Operación | Cloudflare Challenge |
Selecciona AntiCloudflareTask |
| Tipo | AntiCloudflareTask |
Desafío completo de página de Cloudflare |
| URL del sitio web | ={{ $json.body.websiteURL }} |
La URL protegida por Cloudflare |
| Proxy | ={{ $json.body.proxy }} |
Proxy residencial en formato host:port:user:pass |
| Continuar en caso de error | true |
Devuelve errores estructurados en lugar de fallar |
CapSolver lanza un navegador real a través de tu proxy, carga la URL objetivo y resuelve el desafío de Cloudflare. Cuando tiene éxito, devuelve un objeto solution que contiene:
cookies — un objeto { cf_clearance: "..." } con la cookie de autorizaciónuserAgent — la cadena exacta del User-Agent que el navegador usó durante la resoluciónNota: El campo es
websiteURL(notargetURL) — coincide con el nombre del campo usado por todas las demás APIs de Solver y el propio nodo CapSolver.
Este nodo es necesario porque AntiCloudflareTask devuelve cookies como un objeto ({ cf_clearance: "..." }), no como una cadena simple de token como reCAPTCHA o Turnstile. Serializa la cookie, extrae cf_clearance y devuelve un error estructurado si CapSolver falló.
const input = $input.first().json;
if (input.error || !input.data || !input.data.solution) {
const errorMsg = input.error
? (input.error.message || JSON.stringify(input.error))
: 'No se devolvió solución — el sitio puede no estar mostrando un desafío';
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()
}}];
| Configuración | Valor |
|---|---|
| Responder con | JSON |
| Cuerpo de la respuesta | ={{ JSON.stringify($json) }} |
curl -X POST https://tu-instancia-n8n.com/webhook/solver-cloudflare-challenge \
-H "Content-Type: application/json" \
-d '{
"websiteURL": "https://protected-site.com",
"proxy": "host:port:user:pass"
}'
Respuesta exitosa:
{
"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"
}
Respuesta fallida (no se encontró desafío, proxy incorrecto, etc.):
{
"success": false,
"error": "No se devolvió solución — el sitio puede no estar mostrando un desafío"
}
Copia el JSON a continuación e impórtalo en n8n mediante Menu → Import from JSON. Después de importarlo, selecciona tus credenciales de CapSolver en el nodo Cloudflare Challenge.
{
"nodes": [
{
"parameters": {
"content": "## Cloudflare Challenge \u2014 Solver API\n\n### Cómo funciona\n\n1. Recibe una solicitud vía webhook para resolver un desafío de Cloudflare.\n2. Usa el nodo Cloudflare Challenge para intentar resolver el desafío.\n3. Formatea el token del desafío resuelto vía código personalizado.\n4. Responde a la solicitud original con el token resuelto.\n\n### Pasos para configurar\n\n- [ ] Configurar el nodo Webhook para recibir solicitudes.\n- [ ] Configurar las credenciales de CapSolver para habilitar la resolución de desafíos de Cloudflare.\n- [ ] Asegurarse que el nodo Response esté configurado correctamente para devolver el token resuelto.\n\n### Personalización\n\nPuedes personalizar el código en el nodo 'Format Solution' para cambiar el formato de la respuesta con el token resuelto.",
"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": "## Recibir y resolver desafío\n\nSe activa con una nueva solicitud e intenta resolver el desafío de Cloudflare.",
"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": "## Formatear y devolver solución\n\nFormatea la solución y responde con el token resuelto.",
"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": "Cuenta CapSolver"
}
},
"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 se devolvió solución \u2014 el sitio puede no estar mostrando un desafío';\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"
}
}
Hasta ahora, la API de Solver anterior muestra cómo obtener una cookie cf_clearance resuelta y el userAgent. Pero, ¿qué se hace realmente con ellos?
A diferencia de reCAPTCHA o Turnstile donde envías un token en un campo de formulario, el desafío de Cloudflare devuelve una cookie (cf_clearance) que debe enviarse como un encabezado en cada solicitud subsecuente. La cookie está ligada a la IP del proxy y al User-Agent usados durante la resolución — ambos deben coincidir exactamente en la petición.
Aquí está el patrón general:
cf_clearance y userAgent de CapSolversec-ch-uahttp://localhost:7878/fetch para igualar la huella TLS de ChromeConcepto clave: Los clientes HTTP estándar fallan aquí incluso con una cookie
cf_clearanceválida — Cloudflare fingerprintea la negociación TLS misma. El servidor TLS en Go (httpcloak) hace que la solicitud parezca exactamente Chrome a nivel de red. Todo flujo de trabajo que accede a una página protegida por Cloudflare debe pasar por el servidor TLS.### Ejemplo: Raspador de Desafíos de Cloudflare

Ruta de programación:
Cada 6 horas → Configurar objetivo [Programación] → Resolver Desafío Cloudflare
→ Preparar solicitud TLS → Obtener vía servidor TLS → Extraer resultado
Ruta de webhook:
Activador de Webhook → Configurar objetivo [Webhook] → Resolver Desafío Cloudflare
→ Preparar solicitud TLS → Obtener vía servidor TLS → Extraer resultado → Responder al Webhook
targetURL y proxy (en formato host:port:user:pass). La ruta de programación usa valores codificados; la ruta de webhook los lee desde el cuerpo del POST.onError: "continueRegularOutput" — continúa incluso si la página no muestra un desafío actualmente.host:port:user:pass en formato URL http://user:pass@host:port, serializa solution.cookies a una cadena de encabezado de cookies y construye encabezados de solicitud similares a Chrome con el userAgent exacto de la solución.http://localhost:7878/fetch usando contentType: "raw" (no "json" — el modo JSON de n8n corrompe el cuerpo).status, body y fetchedAt de la respuesta del servidor TLS.¿Por qué
contentType: "raw"y no"json"? El modo de contenidojsonde n8n espera parámetros del cuerpo como pares clave-valor. Si se pasaJSON.stringify($json)como cadena, n8n trata la cadena completa como un solo parámetro malformado y envía{"": ""}al servidor. Usar modorawenvía el cuerpo exactamente como evalúa la expresión.
{
"nodes": [
{
"parameters": {
"content": "## Desafío Cloudflare \u2014 CapSolver + Programación + Webhook\n\n### Cómo funciona\n\n1. Activa la programación cada 6 horas para resolver desafíos de Cloudflare.\n2. Webhook se activa al recibir solicitud para resolver desafíos de Cloudflare.\n3. Configura objetivo y proxy para las solicitudes.\n4. Resuelve el desafío Cloudflare usando CapSolver.\n5. Envía resultados vía TLS y procesa la respuesta HTTP.\n\n### Pasos de configuración\n\n- Asegurarse de que las credenciales de CapSolver estén configuradas.\n- Confirmar que la URL del webhook esté configurada y accesible.\n- Verificar configuración de programación para activarse cada 6 horas.\n- Verificar que el endpoint http://localhost:7878/fetch esté disponible.\n\n### Personalización\n\nConsidere personalizar la URL objetivo o la configuración del proxy dentro de los nodos establecidos.",
"width": 480,
"height": 688
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1008,
-112
],
"id": "3c1c3e96-631a-4cf6-bbff-85fd8b1a01e8",
"name": "Nota Adhesiva"
},
{
"parameters": {
"content": "## Desafío Cloudflare programado\n\nSe activa cada 6 horas para resolver desafío Cloudflare.",
"width": 1696,
"height": 272,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-448,
-112
],
"id": "e9187404-7818-4233-af66-091c90a40476",
"name": "Nota Adhesiva1"
},
{
"parameters": {
"content": "## Desafío Cloudflare vía webhook\n\nResponde a solicitudes del solucionador vía webhook para resolver desafío Cloudflare.",
"width": 2000,
"height": 272,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-448,
304
],
"id": "b5d5ba23-8ed2-4afb-8113-3fa8f2fba51e",
"name": "Nota Adhesiva2"
},
{
"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": "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": "Configurar Objetivo [Programación]"
},
{
"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 Desafío Cloudflare [Programación]",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "Cuenta 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 Solicitud TLS [Programación]"
},
{
"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": "Obtener vía Servidor TLS [Programación]"
},
{
"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": "Extraer Resultado [Programación]"
},
{
"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": "Recibir Solicitud del Solucionador",
"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": "Configurar Objetivo [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 Desafío Cloudflare [Webhook]",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "Cuenta 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 Solicitud 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": "Obtener vía 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": "Extraer 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": "Devolver Token Resuelto"
}
],
"connections": {
"Every 6 Hours": {
"main": [
[
{
"node": "Set Target Config [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Set Target Config [Schedule]": {
"main": [
[
{
"node": "Solve Cloudflare Challenge [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Solve Cloudflare Challenge [Schedule]": {
"main": [
[
{
"node": "Prepare TLS Request [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Prepare TLS Request [Schedule]": {
"main": [
[
{
"node": "Fetch via TLS Server [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Fetch via TLS Server [Schedule]": {
"main": [
[
{
"node": "Extract Result [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Receive Solver 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 Result [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"Extract Result [Webhook]": {
"main": [
[
{
"node": "Return Solved Token",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
}
}
---## Flujo de trabajo: Ejemplos de casos de uso
El ejemplo de API de Solver y scraper mostrado arriba muestra el patrón central: resolver el desafío, usar la solución para realizar la obtención a través de TLS. Los siguientes flujos de trabajo extienden este patrón a casos de uso listos para producción — cada uno con disparadores dobles (programación + webhook), seguimiento persistente del estado y salida estructurada. Todos requieren los mismos prerrequisitos: una instancia self-hosted de n8n, el servidor TLS corriendo en el puerto 7878, un proxy residencial y una credencial de CapSolver.
| Flujo de trabajo | Propósito |
|---|---|
Cloudflare Challenge Scraping — Price & Product Details — CapSolver + Schedule + Webhook |
Extrae el precio y el nombre del producto de una página protegida por CF cada 6 horas, compara con valores anteriores y alerta sobre cambios |
Cloudflare Challenge Account Login — CapSolver + Schedule + Webhook |
Inicia sesión en tu propia cuenta en un sitio protegido por CF resolviendo primero el desafío y luego enviando las credenciales mediante POST a través del servidor TLS |
Turnstile — Solver API |
Expone un webhook que resuelve Turnstile y devuelve el token — no se necesita proxy ni servidor TLS |
Turnstile Scraping — Price & Product Monitor |
Resuelve Turnstile, obtiene una página de producto con el token, extrae precio y nombre, y alerta sobre cambios |
Turnstile Account Login |
Inicia sesión en tu propia cuenta en un sitio protegido por Turnstile resolviendo primero el desafío y luego enviando las credenciales con el token — no se necesita proxy ni servidor TLS |
Este flujo de trabajo raspa una página de producto cada 6 horas (programación) o bajo demanda (webhook), extrae el precio usando el nodo HTML, y lo compara contra el valor almacenado previamente.
Ruta de programación:
Cada 6 horas → Configurar Objetivo → Resolver el desafío de CF → Preparar solicitud TLS
→ Obtener vía servidor TLS → Extraer datos → Comparar datos
→ ¿Datos cambiados? → Crear alerta / Sin cambios
Manejo de errores: Si CapSolver falla, el flujo continúa sin cookies (mediante
continueOnFail). La obtención desde el servidor TLS puede aún tener éxito si la página no está mostrando un desafío actualmente.
Comportamientos clave:
dataPropertyName: "body" (no "data") porque el servidor TLS devuelve { status, body, headers }.product-price, h1)$workflow.staticData.lastPrice mantiene el precio previo entre ejecucionesdeal) como aumentos (severidad: info)host:port:user:pass → http://user:pass@host:port a través del ayudante toProxyURL(){
"nodes": [
{
"parameters": {
"content": "## Cloudflare Challenge Scraping \u2014 Price & Product Details \u2014 CapSolver + Schedule + Webhook\n\n### Cómo funciona\n\n1. Los disparadores están configurados para verificar periódicamente el sitio web objetivo o en respuesta a un webhook externo.\n2. Se aplican configuraciones para la URL objetivo y proxies.\n3. Se resuelven los desafíos de Cloudflare para navegar las protecciones del sitio web.\n4. Se realizan solicitudes seguras para obtener datos del servidor objetivo.\n5. Los datos extraídos se comparan para detectar cambios.\n6. Se construyen y envían alertas o se retornan datos basado en los cambios detectados.\n\n### Pasos de configuración\n\n- [ ] Configure la URL y los ajustes de proxy en los nodos 'Set Target Config'.\n- [ ] Conecte las credenciales de CapSolver para resolver desafíos de Cloudflare.\n- [ ] Asegúrese de que la URL del webhook está configurada correctamente para recibir solicitudes externas.\n\n### Personalización\n\nPara ajustar la frecuencia de monitoreo, modifique el intervalo en el nodo 'Every 6 Hours' o la configuración del disparador webhook.",
"width": 480,
"height": 896
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1104,
-192
],
"id": "85c55c3d-335a-47e5-8721-82fa4d633033",
"name": "Sticky Note"
},
{
"parameters": {
"content": "## Configuración del disparador programado\n\nInicializa la programación cada 6 horas para comenzar el proceso de raspado de datos mediante agendamiento.",
"width": 1392,
"height": 272,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-544,
-112
],
"id": "6ac3bd35-66ef-43ed-a8b5-5d5f6d367fba",
"name": "Sticky Note1"
},
{
"parameters": {
"content": "## Procesamiento de datos programado\n\nManeja la extracción de datos, comparación y creación de alertas tras ser activado por la programación.",
"width": 1088,
"height": 480,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
960,
-192
],
"id": "a1c60513-ed8b-43f2-bff3-a7b19436337f",
"name": "Sticky Note2"
},
{
"parameters": {
"content": "## Configuración del disparador webhook\n\nMonitorea solicitudes externas vía webhook para iniciar el proceso de raspado.",
"width": 1392,
"height": 272,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-544,
384
],
"id": "ee4d9a0d-3233-4b70-828b-078c9eee0086",
"name": "Sticky Note3"
},
{
"parameters": {
"content": "## Procesamiento y respuesta de datos por webhook\n\nExtrae y compara datos desde el disparador webhook; retorna respuestas basadas en cambios.",
"width": 1392,
"height": 480,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
960,
336
],
"id": "4ad55fbf-2882-4c63-9e09-37e674b00145",
"name": "Sticky Note4"
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 6
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.3,
"position": [
-500,
0
],
"id": "cf333333-3333-3333-3333-333333333301",
"name": "Every 6 Hours"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "cfg-s-001",
"name": "targetURL",
"value": "https://YOUR_CF_PROTECTED_SITE.com/product-page",
"type": "string"
},
{
"id": "cfg-s-002",
"name": "proxy",
"value": "YOUR_PROXY_HOST:PORT:USER:PASS",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-200,
0
],
"id": "cf333333-3333-3333-3333-333333333302",
"name": "Set Target Config [Schedule]"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"websiteURL": "={{ $json.targetURL }}",
"proxy": "={{ $json.proxy }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [
100,
0
],
"id": "cf333333-3333-3333-3333-333333333303",
"name": "Solve Cloudflare Challenge [Schedule]",
"onError": "continueRegularOutput",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "Cuenta 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, como 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 solicitud 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": [
700,
0
],
"id": "cf333333-3333-3333-3333-333333333305",
"name": "Obtener vía servidor TLS [Schedule]"
},
{
"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": "Extraer Datos"
},
{
"parameters": {
"jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Producto';\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 ? 'bajó' : 'subió') : 'sin cambios';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\n\nreturn [{\n json: {\n productName,\n currentPrice,\n previousPrice: previousPrice || 'primera revisión',\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 Datos"
},
{
"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": "¿Datos Cambiados?"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "alert-001",
"name": "alert",
"value": "=Precio {{ $json.direction }} para {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $json.currentPrice }} ({{ $json.direction === 'bajó' ? '-' : '+' }}{{ $json.diff }})",
"type": "string"
},
{
"id": "alert-002",
"name": "severity",
"value": "={{ $json.direction === 'bajó' ? '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": "Crear Alerta"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "nc-001",
"name": "status",
"value": "sin_cambios",
"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": "Sin Cambios"
},
{
"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": "Recibir Solicitud de Monitoreo",
"webhookId": "cf333333-aaaa-bbbb-cccc-333333333311",
"onError": "continueRegularOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "cfg-w-001",
"name": "targetURL",
"value": "={{ $json.body.targetURL }}",
"type": "string"
},
{
"id": "cfg-w-002",
"name": "proxy",
"value": "={{ $json.body.proxy }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-200,
500
],
"id": "cf333333-3333-3333-3333-333333333312",
"name": "Set Target Config [Webhook]"
},
{
"parameters": {
"operation": "Cloudflare Challenge",
"websiteURL": "={{ $json.targetURL }}",
"proxy": "={{ $json.proxy }}"
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [
100,
500
],
"id": "cf333333-3333-3333-3333-333333333313",
"name": "Resolver desafío Cloudflare [Webhook]",
"onError": "continueRegularOutput",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "Cuenta 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, como 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 solicitud 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": "Obtener vía 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": "Extraer Datos [Webhook]"
},
{
"parameters": {
"jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Producto';\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 ? 'bajó' : 'subió') : 'sin cambios';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\n\nreturn [{\n json: {\n productName,\n currentPrice,\n previousPrice: previousPrice || 'primera revisión',\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 Datos [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": "¿Datos Cambiados? [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "alert-004",
"name": "alert",
"value": "=Precio {{ $json.direction }} para {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $json.currentPrice }} ({{ $json.direction === 'bajó' ? '-' : '+' }}{{ $json.diff }})",
"type": "string"
},
{
"id": "alert-005",
"name": "severity",
"value": "={{ $json.direction === 'bajó' ? '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": "Crear Alerta [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "nc-004",
"name": "status",
"value": "sin_cambios",
"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": "Sin Cambios [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": "Devolver Datos 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"
}
}
Este flujo de trabajo automatiza el inicio de sesión en un sitio protegido por Cloudflare. Un nodo Set Login Config centraliza todos los parámetros: [Schedule] para la ruta programada y [Webhook] para la ruta bajo demanda por webhook.
Ruta programada:
Cada 24 horas → Set Login Config → Resolver desafío CF
→ Preparar solicitud de inicio de sesión TLS → Enviar inicio de sesión vía servidor TLS
→ ¿Inicio de sesión exitoso? → Marcar éxito / Marcar fallo
Manejo de errores: Si CapSolver falla, el flujo de trabajo continúa sin cookies (mediante
continueOnFail). La solicitud de inicio de sesión probablemente fallará, lo cual detecta el nodo ¿Inicio de sesión exitoso?.
Comportamientos clave:
cf_clearance + userAgent como encabezados HTTP (sin token en el cuerpo del formulario — a diferencia del inicio de sesión reCAPTCHA que envía g-recaptcha-response)URLSearchParams — edite los nombres de campos (usernameField, passwordField) en Set Login Config para que coincidan con su sitiostatus < 400 Y successMarker en el cuerpo de la respuesta{
"nodes": [
{
"parameters": {
"content": "## Inicio de sesión en cuenta con desafío Cloudflare \u2014 CapSolver + Schedule + Webhook\n\n### Cómo funciona\n\n1. Programar un proceso de inicio de sesión cada 24 horas y resolver el desafío de Cloudflare.\n2. Preparar y enviar una solicitud de inicio de sesión TLS cuando sea iniciado por el programador.\n3. Manejar el éxito o fracaso del inicio de sesión programado, incluyendo registrar resultados.\n4. Recibir solicitudes de inicio de sesión vía webhook y resolver el desafío Cloudflare.\n5. Preparar y enviar una solicitud TLS de inicio de sesión cuando sea iniciada por el webhook.\n6. Manejar éxito o fracaso del inicio de sesión vía webhook y devolver resultados.\n\n### Pasos de configuración\n\n- [ ] Asegúrese de que las credenciales API de CapSolver para Cloudflare estén configuradas.\n- [ ] Configurar un servidor TLS corriendo localmente en http://localhost:7878.\n- [ ] Configurar la URL del webhook para recibir solicitudes de inicio de sesión.\n\n### Personalización\n\nAjuste los intervalos programados para cumplir con necesidades específicas de frecuencia.",
"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": "## Inicio del login programado\n\nInicia el proceso de inicio de sesión cada 24 horas como punto de disparo para acciones posteriores.",
"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": "## Flujo de trabajo de login programado\n\nManeja el desafío Cloudflare, prepara y envía la solicitud de login, y verifica si fue exitosa cada 24 horas.",
"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": "## Inicio del login vía webhook\n\nAcepta solicitudes de inicio de sesión mediante webhook para iniciar el flujo de trabajo subsecuente.",
"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": "## Flujo de trabajo de login vía webhook\n\nProcesa las solicitudes de login recibidas por webhook, maneja el desafío Cloudflare, prepara y envía la solicitud de inicio de sesión, verifica el éxito y registra los resultados.",
"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": "## Devolver resultado del webhook\n\nResponde a la solicitud inicial de webhook con el resultado del intento de inicio de sesión.",
"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": "Cada 24 horas"
},
{
"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": "Resolver desafío Cloudflare [Schedule]",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "Cuenta CapSolver"
}
}
},
{
"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, como 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": "Preparar solicitud TLS de inicio de sesión [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": "Enviar inicio de sesión vía servidor TLS [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": "¿Inicio de sesión exitoso? [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": "Flujo de inicio de sesión configurado exitosamente (mediante evasión del desafío Cloudflare)",
"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": "Marcar éxito de inicio de sesión [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": "La respuesta de inicio de sesión no coincidió con el marcador de éxito configurado",
"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": "Marcar fallo de inicio de sesión [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": "Recibir solicitud de login",
"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": "Resolver desafío Cloudflare [Webhook]",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "Cuenta CapSolver"
}
}
},
{
"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, como 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": "Preparar solicitud TLS de inicio de sesión [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": "Enviar inicio de sesión vía servidor TLS [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": "¿Inicio de sesión exitoso? [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": "Flujo de inicio de sesión configurado exitosamente (mediante evasión del desafío Cloudflare)",
"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": "Marcar éxito de inicio de sesión [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": "La respuesta de inicio de sesión no coincidió con el marcador de éxito configurado",
"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": "Marcar fallo de inicio de sesión [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": "Devolver resultado del login"
}
],
"connections": {
"Cada 24 horas": {
"main": [
[
{
"node": "Set Login Config [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Set Login Config [Schedule]": {
"main": [
[
{
"node": "Resolver desafío Cloudflare [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Resolver desafío Cloudflare [Schedule]": {
"main": [
[
{
"node": "Preparar solicitud TLS de inicio de sesión [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Preparar solicitud TLS de inicio de sesión [Schedule]": {
"main": [
[
{
"node": "Enviar inicio de sesión vía servidor TLS [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Enviar inicio de sesión vía servidor TLS [Schedule]": {
"main": [
[
{
"node": "¿Inicio de sesión exitoso? [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"¿Inicio de sesión exitoso? [Schedule]": {
"main": [
[
{
"node": "Marcar éxito de inicio de sesión [Schedule]",
"type": "main",
"index": 0
}
],
[
{
"node": "Marcar fallo de inicio de sesión [Schedule]",
"type": "main",
"index": 0
}
]
]
},
"Recibir solicitud de login": {
"main": [
[
{
"node": "Set Login Config [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"Set Login Config [Webhook]": {
"main": [
[
{
"node": "Resolver desafío Cloudflare [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"Resolver desafío Cloudflare [Webhook]": {
"main": [
[
{
"node": "Preparar solicitud TLS de inicio de sesión [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"Preparar solicitud TLS de inicio de sesión [Webhook]": {
"main": [
[
{
"node": "Enviar inicio de sesión vía servidor TLS [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"Enviar inicio de sesión vía servidor TLS [Webhook]": {
"main": [
[
{
"node": "¿Inicio de sesión exitoso? [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"¿Inicio de sesión exitoso? [Webhook]": {
"main": [
[
{
"node": "Marcar éxito de inicio de sesión [Webhook]",
"type": "main",
"index": 0
}
],
[
{
"node": "Marcar fallo de inicio de sesión [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"Marcar éxito de inicio de sesión [Webhook]": {
"main": [
[
{
"node": "Devolver resultado del login",
"type": "main",
"index": 0
}
]
]
},
"Marcar fallo de inicio de sesión [Webhook]": {
"main": [
[
{
"node": "Devolver resultado del login",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
}
}
Este flujo crea un endpoint POST que resuelve un desafío Cloudflare Turnstile y devuelve el token. Es el equivalente a Turnstile de la API de solución de desafíos de Cloudflare anterior, pero más simple: sin proxy, sin servidor TLS, solo 3 nodos.
Flujo:
Webhook (POST /solver-turnstile) → Resolver Turnstile (CapSolver) → Responder al Webhook
websiteURL y websiteKeyAntiTurnstileTaskProxyLesstoken)Diferencia clave respecto al desafío de Cloudflare: Turnstile devuelve una cadena
token, no una cookiecf_clearance. En solicitudes posteriores, envías este token como encabezadocf-turnstile-response(o campo de formulario, dependiendo del sitio). No se requiere proxy.
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..."
}'
Copia el JSON a continuación e impórtalo en n8n vía Menú → Importar desde JSON. Después de importarlo, selecciona tu credencial de CapSolver en el nodo Resolver Turnstile.
{
"nodes": [
{
"parameters": {
"content": "## Turnstile \u2014 API del solucionador\n\n### Cómo funciona\n\n1. Recibe una solicitud de solución a través de un webhook.\n2. Resuelve el CAPTCHA Turnstile usando un nodo solucionador especializado.\n3. Envía la respuesta de vuelta mediante la respuesta al webhook.\n\n### Pasos de configuración\n\n- [ ] Configurar la URL del webhook para recibir solicitudes.\n- [ ] Configurar las credenciales para el nodo capSolver.\n- [ ] Asegurarse de que la URL del webhook de respuesta esté correctamente configurada.\n\n### Personalización\n\nLa configuración del nodo solucionador puede ajustarse para manejar 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": "## Manejar solicitud del solucionador\n\nRecibe y procesa una solicitud para resolver un CAPTCHA Turnstile, luego envía el resultado de vuelta.",
"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": "Recibir solicitud de solucionador",
"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": "Cuenta 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 al Webhook"
}
],
"connections": {
"Recibir solicitud de solucionador": {
"main": [
[
{
"node": "Resolver Turnstile",
"type": "main",
"index": 0
}
]
]
},
"Resolver Turnstile": {
"main": [
[
{
"node": "Responder al Webhook",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
}
}
Este flujo de trabajo resuelve Cloudflare Turnstile, obtiene una página de producto con el token resuelto, extrae el precio y el nombre del producto, y compara con el valor anterior — alertando sobre cambios. Sigue el mismo patrón de activación dual (programación + webhook) que el ejemplo de raspado de Cloudflare Challenge anterior.
Diferencia clave con el raspado de Cloudflare Challenge: No hay servidor TLS, no hay proxy, no hay nodo de código
Prepare TLS Request. El token Turnstile se envía como cabeceracf-turnstile-responsedirectamente a través del nodo HTTP Request incorporado de n8n.
Ruta de programación:
Cada 6 horas → Configurar destino → Resolver Turnstile → Obtener página de producto
→ Extraer datos → Comparar datos → ¿Datos cambiaron? → Generar alerta / Sin cambio
Ruta de webhook:
Disparador webhook → Resolver Turnstile → Obtener página de producto
→ Extraer datos → Comparar datos → ¿Datos cambiaron? → Generar alerta / Sin cambio
→ Responder al webhook
Comportamientos clave:
Cloudflare Turnstile (no Cloudflare Challenge) — usa AntiTurnstileTaskProxyLess internamentecf-turnstile-response en la solicitud de obtencióncf_clearance para verificación de huella digital$workflow.staticData.lastPrice para persistencia entre ejecucioneswebsiteURL y websiteKey directamente del cuerpo POST (no se necesita nodo Set Target Config){
"nodes": [
{
"parameters": {
"content": "## Turnstile Scraping \u2014 Price & Product Monitor\n\n### How it works\n\n1. The workflow is triggered every 6 hours or via a webhook.\n2. Target configuration is set including website URL and key.\n3. The Turnstile captcha is solved to access the product page.\n4. Product data is fetched and relevant data is extracted.\n5. Extracted data is compared to previous data to identify changes.\n6. Alerts are generated if there are changes, and a response is sent for webhook requests.\n\n### Setup steps\n\n- [ ] Configure schedule trigger interval as required.\n- [ ] Set up webhook URL for real-time triggering.\n- [ ] Ensure credentials for captcha solver are valid.\n- [ ] Configure target website URL and product key.\n\n### Customization\n\nThe interval for the schedule trigger can be adjusted based on monitoring needs.",
"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": "## Scheduled scraping trigger\n\nInitiates the workflow every 6 hours and sets target configurations.",
"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": "## Scheduled captcha and fetch\n\nSolves captcha and fetches product page data based on schedule.",
"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": "## Schedule data evaluation\n\nCompares newly fetched data to previous for changes and builds alerts.",
"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": "## Webhook scraping trigger\n\nTriggers the scraping workflow via a webhook for real-time updates.",
"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": "## Webhook captcha and fetch\n\nSolves captcha and fetches product page data for webhook trigger.",
"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": "## Webhook data evaluation and response\n\nEvaluates data changes and responds to the webhook with results.",
"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": "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": "Configurar Destino [Programación]"
},
{
"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": "Cuenta 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": "Obtener página de producto"
},
{
"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": "Extraer Datos"
},
{
"parameters": {
"jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Producto';\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 ? 'bajó' : 'subió') : 'sin cambios';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\nreturn [{ json: { productName, currentPrice, previousPrice: previousPrice || 'primera revisión', 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 Datos"
},
{
"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": "¿Datos cambiaron?"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "a1",
"name": "alert",
"value": "=Precio {{ $json.direction }} para {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $json.currentPrice }}",
"type": "string"
},
{
"id": "a2",
"name": "severity",
"value": "={{ $json.direction === 'bajó' ? 'deal' : 'info' }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1584,
-48
],
"id": "ts-s-08",
"name": "Generar Alerta"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "n1",
"name": "status",
"value": "sin_cambios",
"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": "Sin Cambios"
},
{
"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": "Disparador 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": "Cuenta 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": "Obtener página de producto [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": "Extraer Datos [W]"
},
{
"parameters": {
"jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Producto';\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 ? 'bajó' : 'subió') : 'sin cambios';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\nreturn [{ json: { productName, currentPrice, previousPrice: previousPrice || 'primera revisión', 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 Datos [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": "¿Datos cambiaron? [W]"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "a4",
"name": "alert",
"value": "=Precio {{ $json.direction }} para {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $json.currentPrice }}",
"type": "string"
},
{
"id": "a5",
"name": "severity",
"value": "={{ $json.direction === 'bajó' ? 'deal' : 'info' }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1584,
432
],
"id": "ts-s-16",
"name": "Generar Alerta [W]"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "n4",
"name": "status",
"value": "sin_cambios",
"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": "Sin Cambios [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 al 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"
}
}
Este flujo de trabajo automatiza el inicio de sesión en un sitio protegido por Turnstile. Sigue el mismo patrón de activación dual (programación + webhook) que el inicio de sesión con cuenta Cloudflare Challenge mencionado anteriormente, pero sin servidor TLS, proxy ni nodo de código personalizado.
Diferencia clave respecto al inicio de sesión con Cloudflare Challenge: No hay servidor TLS, ni proxy, ni nodo de código
Prepare TLS Login Request. El token Turnstile se envía como un campo de formulariocf-turnstile-responsedirectamente a través del nodo HTTP Request incorporado en n8n. Las credenciales se envían como parámetros habituales en el cuerpo con formatoform-urlencoded.
Ruta de programación:
Cada 24 horas → Configurar inicio de sesión → Resolver Turnstile → Enviar inicio de sesión
→ ¿Inicio de sesión OK? → Marcar éxito / Marcar fallo
Ruta de webhook:
Disparador de webhook → Resolver Turnstile → Enviar inicio de sesión
→ ¿Inicio de sesión OK? → Marcar éxito / Marcar fallo → Responder al webhook
Comportamientos clave:
Cloudflare Turnstile (no Cloudflare Challenge) — usa AntiTurnstileTaskProxyLess, no se requiere proxycf-turnstile-response en el cuerpo POST (no en un encabezado cookie como en CF Challenge)email, password y cf-turnstile-responsestatusCode < 400 Y que successMarker esté en el cuerpo de la respuesta — mismo patrón que el inicio de sesión CF ChallengeusernameValue, passwordValue, usernameField, passwordField, loginActionURL, successMarker del cuerpo POSTname de cada campo de formulario es una expresión ($('Webhook Trigger').item.json.body.usernameField || 'email'), por lo que los llamadores pueden especificar los nombres de campo de su sitio{
"nodes": [
{
"parameters": {
"content": "## Inicio de sesión en cuenta Turnstile\n\n### Cómo funciona\n\n1. Dispara un proceso de inicio de sesión cada 24 horas usando una programación.\n2. Configura la configuración de inicio de sesión y resuelve los desafíos Turnstile.\n3. Envía el formulario de inicio de sesión y verifica si fue exitoso.\n4. Marca el intento de inicio de sesión como éxito o fallo en el flujo de programación.\n5. Alternativamente, inicia un proceso de inicio de sesión mediante un disparador webhook y ejecuta pasos similares para inicios de sesión basados en webhook.\n\n### Pasos de configuración\n\n- [ ] Programar una ejecución periódica configurando un programador.\n- [ ] Configurar el endpoint webhook para disparadores externos.\n- [ ] Establecer las credenciales de inicio de sesión y configuraciones de URL.\n\n### Personalización\n\nAjuste el tiempo en el programador o modifique el manejo de respuestas del webhook según sea necesario.",
"width": 480,
"height": 896
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1168,
-160
],
"id": "8ca80c21-2de5-41e7-b3e4-de184fc1d8fe",
"name": "Nota adhesiva"
},
{
"parameters": {
"content": "## Flujo de inicio de sesión programado\n\nDispara cada 24 horas para realizar los pasos de inicio de sesión",
"width": 1920,
"height": 448,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-608,
-160
],
"id": "533be07a-6fe7-4ada-a40c-7a7749ba968d",
"name": "Nota adhesiva1"
},
{
"parameters": {
"content": "## Flujo de inicio de sesión vía webhook\n\nManeja solicitudes de inicio de sesión disparadas por un webhook",
"width": 2288,
"height": 416,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-608,
320
],
"id": "c6a8e296-2bfb-4ffa-8819-aa420e936589",
"name": "Nota adhesiva2"
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 24
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.3,
"position": [
-560,
48
],
"id": "ts-l-01",
"name": "Cada 24 horas"
},
{
"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, como 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": "Configurar inicio de sesión [Programación]"
},
{
"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": "Resolver Turnstile [Programación]",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "Cuenta CapSolver"
}
}
},
{
"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": "Enviar inicio de sesión [Programación]"
},
{
"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": "¿Inicio de sesión OK? [Programación]"
},
{
"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": "Marcar éxito"
},
{
"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": "Marcar fallo"
},
{
"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": "Disparador webhook",
"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": "Resolver Turnstile [Webhook]",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "Cuenta CapSolver"
}
}
},
{
"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, como 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": "Enviar inicio de sesión [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": "¿Inicio de sesión 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": "Marcar éxito [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": "Marcar fallo [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": "Responder al 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"
}
}
Has construido una canalización completa para evitar el desafío de Cloudflare en n8n — sin automatización de navegador, sin Puppeteer, sin Playwright. Solo tres componentes trabajando juntos: CapSolver para resolver el desafío, un servidor TLS en Go para falsificar la huella digital de red de Chrome, y un flujo de trabajo n8n para orquestar todo.
La idea clave es que resolver el desafío es solo la mitad del problema. Sin hacer coincidir las huellas TLS en la siguiente solicitud fetch, cf_clearance es inútil — Cloudflare inspecciona el handshake, no solo la cookie. El servidor TLS httpcloak maneja esa capa, haciendo que la solicitud sea indistinguible de un navegador Chrome real a nivel de red.
El repositorio ahora te ofrece plantillas iniciales reales para sitios protegidos por Cloudflare:
cf_clearance en bruto + userAgent para aplicaciones externasLa API Solver es el punto de entrada más simple — 4 nodos, no se necesita servidor TLS. Los flujos de trabajo Turnstile son aún más simples — no se requiere proxy ni servidor TLS en absoluto, ya que Turnstile devuelve un token (no una cookie ligada a IP) y no hace huellas TLS. Para los flujos de trabajo del desafío Cloudflare que recuperan páginas directamente, CapSolver resuelve el desafío y el servidor TLS hace la solicitud real. Configura los marcadores, mantén los flujos de trabajo inactivos hasta que coincidan con tu objetivo, luego actívalos.
Consejo: Estos flujos de trabajo usan activadores Schedule + Webhook, pero puedes cambiar el nodo de activación a cualquier disparador de n8n — manual, evento de app, envío de formulario, etc. Después de obtener los datos, usa los nodos incorporados de n8n para guardar resultados en Google Sheets, bases de datos, almacenamiento en la nube, o enviar alertas vía Telegram/Slack/Email.
¿Listo para comenzar? Regístrate en CapSolver y usa el código de bonificación n8n para un 8% extra en tu primer recargo.

AntiCloudflareTask resuelve el desafío completo de gestión de bots de Cloudflare en toda la página — la pantalla de "Just a moment…" que bloquea el acceso al sitio entero. Requiere un proxy porque CapSolver debe cargar la página protegida real a través de un navegador. AntiTurnstileTaskProxyLess resuelve widgets Turnstile incrustados dentro de páginas (formularios de inicio de sesión, formularios de registro) y no requiere proxy. Diferentes desafíos, diferentes tipos de tarea.
El nodo HTTP Request de n8n usa la librería estándar net/http de Go, que tiene una huella TLS distinta que Cloudflare detecta. Incluso con una cookie válida cf_clearance, Cloudflare volverá a desafiar cualquier solicitud que no coincida con el perfil TLS de un navegador conocido. El servidor TLS resuelve esto usando httpcloak para falsificar la pila TLS de Chrome real.
La puntuación de bots de Cloudflare asigna puntajes de riesgo a direcciones IP. Las IP de centros de datos (de AWS, GCP, proveedores VPS, etc.) son bien conocidas y obtienen puntajes de riesgo altos. AntiCloudflareTask usa tu proxy para cargar la página del desafío, y si Cloudflare detecta la IP como de centro de datos, entrega un desafío más difícil que CapSolver no puede resolver, o falla el desafío completamente. Las IP residenciales y móviles tienen puntajes de riesgo menores y pasan de forma más confiable.
No. Turnstile es fundamentalmente distinto del desafío Cloudflare. Turnstile devuelve un token de corta duración que se envía como cabecera o campo de formulario — no está ligado a una IP específica ni a una huella TLS. CapSolver resuelve Turnstile usando AntiTurnstileTaskProxyLess, que no requiere proxy. Y como envías un token (no una cookie ligada a IP), el nodo HTTP Request incorporado de n8n funciona perfectamente — no se necesita falsificación de huella TLS.
cf_clearance expira?Sí. La expiración depende de la configuración de Cloudflare del sitio — puede variar desde unos minutos hasta 24 horas. Para trabajos de scraping recurrentes, el flujo programado (cada 6 horas) vuelve a resolver el desafío regularmente. Para scraping bajo demanda, el path del webhook resuelve un desafío nuevo en cada solicitud.
Aprende una arquitectura de raspado web escalable en Rust con reqwest, scraper, raspado asíncrono, raspado con navegador sin cabeza, rotación de proxies y manejo de CAPTCHA conforme.

Automatiza la resolución de CAPTCHA con Nanobot y CapSolver. Utiliza Playwright para resolver reCAPTCHA y Cloudflare autónomamente.

Comprender Datos como Servicio (DaaS) en 2026. Explora sus beneficios, casos de uso y cómo transforma los negocios con insights en tiempo real y escalabilidad.

Dominar la resolución de diversos errores de scrapers web como 400, 401, 402, 403, 429, 5xx y Cloudflare 1001 en 2026. Aprender estrategias avanzadas para la rotación de IPs, encabezados y limitación de tasa adaptativa con CapSolver.
