CAPSOLVER
Blog
How to Solve GeeTest V3 in n8n with CapSolver: Complete Integration Guide

How to Solve GeeTest V3 in n8n with CapSolver: Complete Integration Guide

Logo of CapSolver

Ethan Collins

Pattern Recognition Specialist

18-Mar-2026

GeeTest V3 is one of the most widely deployed behavioral CAPTCHAs on the web. Unlike simple checkbox challenges, GeeTest V3 uses interactive puzzles -- slide-to-verify, icon selection, and word matching -- to distinguish humans from bots. It's commonly found on login pages, registration forms, and data-heavy sites across Asia and increasingly worldwide.

What if you could solve GeeTest V3 automatically inside your n8n workflows -- whether you're building a reusable solver API, scraping a captcha-protected site, or automating a login form -- all without writing a single line of traditional code?

In this guide, you'll learn how to combine n8n (a visual workflow automation tool) with CapSolver (an AI-powered captcha solving service) to solve GeeTest V3 challenges on demand -- either as a standalone API endpoint or as a step inside any automation workflow.

What you'll build:

Solver API -- a reusable endpoint your other tools can call:

  • A GeeTest V3 solver API

Direct-use workflows -- CapSolver embedded as a step inside larger automations:

  • A price & product scraper that solves GeeTest V3, fetches protected pages, and alerts on price changes
  • An account login automation that solves GeeTest V3 before submitting credentials

What is GeeTest V3?

GeeTest V3 is a challenge-response CAPTCHA system that verifies users through interactive tasks. Unlike reCAPTCHA (which uses a single token) or Cloudflare Turnstile (which runs invisibly), GeeTest V3 presents visible puzzles that require user interaction:

  • Slide puzzle -- Drag a slider to complete a jigsaw piece
  • Icon click -- Click specific icons in the correct order
  • Word match -- Select characters that match a prompt

From a solving perspective, GeeTest V3 has two critical parameters:

  • gt -- A per-site identifier (like a site key). This is static -- it doesn't change between sessions.
  • challenge -- A per-session token. This is dynamic -- it changes every time and expires in approximately 60-120 seconds.

This dynamic challenge parameter is the key difference from other CAPTCHA types. Every workflow that solves GeeTest V3 needs an extra step to fetch a fresh challenge before sending it to CapSolver.

Solution format: Unlike reCAPTCHA or Turnstile which return a single token, GeeTest V3 returns three separate values:

  • challenge -- The solved challenge string
  • validate -- The validation hash
  • seccode -- The security code

These are submitted as three form fields: geetest_challenge, geetest_validate, and geetest_seccode.

GeeTest V3 vs V4: GeeTest V4 uses a different API structure (captcha_id instead of gt, no separate challenge fetch). This guide covers V3 specifically. If you see captcha_id in the page source, you're dealing with V4.


Prerequisites

Before getting started, make sure you have the following:

  1. An n8n instance -- Either self-hosted or n8n Cloud
  2. A CapSolver account -- Sign up here and get your API key
  3. The CapSolver n8n node -- Already available as an official node in n8n (no installation needed)

Important: Make sure you have sufficient balance in your CapSolver account. GeeTest V3 solving tasks consume credits based on usage.


Setting Up CapSolver in n8n

CapSolver is available as an official integration in n8n -- no community node installation required. You can find it directly in the node panel when building your workflows.

Since it's an official integration, you need to create a credential in n8n so that the CapSolver node can authenticate with your account.

Step 1: Open the Credentials Page

Go to your n8n instance and navigate to Settings -> Credentials. You'll see all your configured credentials here.

n8n credentials page showing CapSolver account

Step 2: Create the CapSolver Credential

  1. Click Create credential (top right)
  2. Search for "CapSolver" and select CapSolver API
  3. Enter your API Key -- copy it directly from the CapSolver Dashboard
  4. Leave Allowed HTTP Request Domains set to All (default)
  5. Click Save

n8n will automatically test the connection. You should see a green "Connection tested successfully" banner confirming your API key is valid.

CapSolver credential configuration with successful connection test

Important: Every CapSolver node in your workflows will reference this credential. You only need to create it once -- all your solver workflows will share the same credential.

Now you're ready to build your GeeTest V3 solver workflow!


How to Identify GeeTest V3 Parameters

Before you can solve a GeeTest V3 challenge, you need to find three things: the gt parameter, the challenge API endpoint, and understand how the challenge value is fetched dynamically.

Method 1: DevTools Network Tab

  1. Open DevTools (F12) -> Network tab
  2. Trigger the GeeTest challenge on the page
  3. Look for requests containing gt= in the URL or responses containing "gt" and "challenge" fields
  4. Common endpoint patterns:
    • /api/geetest/register
    • /gt/register-slide
    • /captcha?gt=...
  5. The response typically looks like:
json Copy
{
  "gt": "81dc9bdb52d04dc20036dbd8313ed055",
  "challenge": "4a8a08f09d37b73795649038408b5f33ab",
  "success": 1,
  "new_captcha": true
}

Understanding the Dynamic Challenge

This is the most important concept for GeeTest V3 automation:

  • The gt value is static per site -- it stays the same across sessions
  • The challenge value is dynamic -- it changes every time and expires in ~60-120 seconds
  • You must fetch a fresh challenge immediately before sending the solve request to CapSolver
  • The challenge API endpoint is site-specific (e.g., https://example.com/api/geetest/register)

This means every GeeTest V3 workflow needs an extra HTTP Request node before the CapSolver node to fetch the fresh challenge. This is the key structural difference from reCAPTCHA or Turnstile workflows.

Tip: Add ?t={{ Date.now() }} to the challenge API URL as a cache-busting parameter to ensure you always get a fresh challenge.

For a detailed guide on identifying captcha parameters, check out the official CapSolver documentation.


Workflow: GeeTest V3 Solver API

This workflow creates a POST endpoint that accepts GeeTest V3 parameters and returns a solved challenge. Unlike reCAPTCHA or Turnstile solvers, the caller must provide the challenge value (freshly fetched) along with the gt and websiteURL.

GeeTest V3 solver workflow in n8n

How It Works

The workflow consists of four nodes:

  1. Webhook -- Receives incoming POST requests with GeeTest V3 parameters
  2. GeeTest V3 -- Sends the challenge to CapSolver and waits for a solution
  3. CapSolver Error? -- IF node that branches on whether solving failed ($json.error is not empty)
  4. Respond to Webhook -- Returns the solution on success, or {"error": "..."} on failure

Node Configuration

1. Webhook Node

Setting Value
HTTP Method POST
Path solver-geetest-v3
Respond Response Node

This creates an endpoint at: https://your-n8n-instance.com/webhook/solver-geetest-v3

2. CapSolver GeeTest V3 Node

Parameter Value Description
Operation GeeTest V3 Must be set to GeeTest V3
Type GeeTestTaskProxyLess Only available option -- no proxy variant
Website URL ={{ $json.body.websiteURL }} The URL of the page with the GeeTest challenge
GT ={{ $json.body.gt }} The per-site GeeTest identifier
Challenge ={{ $json.body.challenge }} The dynamic per-session challenge (must be fresh)
GeeTest API Server Subdomain (Optional) Custom GeeTest API server if the site uses one

Also select your CapSolver credentials in the node.

3. CapSolver Error? Node (IF)

Setting Value
Condition ={{ $json.error }} is not empty
True branch Routes to the Error Respond to Webhook node
False branch Routes to the Success Respond to Webhook node

This makes the error path explicit on the canvas. The CapSolver node continues on error (onError: continueRegularOutput), so failures arrive here as { "error": "..." } rather than crashing the workflow.

4. Respond to Webhook Nodes

Success branch (false output of CapSolver Error?):

Setting Value
Respond With JSON
Response Body ={{ JSON.stringify($json.data) }}

Test It

Send a POST request to your webhook endpoint:

bash Copy
curl -X POST https://your-n8n-instance.com/webhook/solver-geetest-v3 \
  -H "Content-Type: application/json" \
  -d '{
    "websiteURL": "https://example.com/login",
    "gt": "81dc9bdb52d04dc20036dbd8313ed055",
    "challenge": "4a8a08f09d37b73795649038408b5f33ab"
  }'

Expected Response:

json Copy
{
  "taskId": "abc123...",
  "solution": {
    "challenge": "4a8a08f09d37b73795649038408b5f33",
    "validate": "68f0c05d0c8a8b2b1e2f3a4b5c6d7e8f",
    "seccode": "68f0c05d0c8a8b2b1e2f3a4b5c6d7e8f|jordan"
  },
  "status": "ready"
}

Important: The challenge in the request body must be freshly fetched. If you send an expired challenge, CapSolver will fail to solve it. Challenges typically expire in 60-120 seconds.

Import This Workflow

Copy the JSON below and import it into n8n via Menu -> Import from JSON:

Click to expand workflow JSON
json Copy
{
  "name": "GeeTest V3 โ€” Solver API",
  "nodes": [
    {
      "parameters": {
        "content": "## GeeTest V3 โ€” Solver API\n\n**Who it's for:** Developers who need to solve GeeTest V3 challenges via a simple POST endpoint.\n\n**What it does:** Exposes a webhook that accepts captcha parameters, solves the challenge with CapSolver, and returns the token or error as JSON.\n\n**How it works:**\n1. Webhook receives POST with target URL, site key, and optional params\n2. CapSolver node solves the GeeTest V3 challenge\n3. IF node checks for errors โ†’ returns success token or error JSON\n\n**Setup:**\n1. Add your CapSolver API key under **Settings โ†’ Credentials โ†’ CapSolver API**\n2. Activate the workflow\n3. POST to the webhook URL with your captcha parameters",
        "height": 494,
        "width": 460,
        "color": 1
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -712,
        -400
      ],
      "id": "sticky-blog-main-1773678228108-1",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "solver-geetest-v3",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -192,
        0
      ],
      "id": "88888888-1111-1111-1111-888888880001",
      "name": "Receive Solver Request",
      "webhookId": "88888888-1111-aaaa-bbbb-888888880001"
    },
    {
      "parameters": {
        "operation": "GeeTest V3",
        "websiteURL": "={{ $json.body.websiteURL }}",
        "gt": "={{ $json.body.gt }}",
        "challenge": "={{ $json.body.challenge }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        112,
        0
      ],
      "id": "88888888-1111-1111-1111-888888880002",
      "name": "GeeTest V3",
      "onError": "continueRegularOutput",
      "credentials": {
        "capSolverApi": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "CapSolver account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "capsolver-err-001",
              "leftValue": "={{ $json.error }}",
              "operator": {
                "type": "string",
                "operation": "isNotEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        400,
        0
      ],
      "id": "88888888-1111-1111-1111-888888880003",
      "name": "CapSolver Error?"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ error: $json.error }) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        700,
        -100
      ],
      "id": "88888888-1111-1111-1111-888888880004",
      "name": "Respond to Webhook (Error)"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json.data) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        700,
        100
      ],
      "id": "88888888-1111-1111-1111-888888880005",
      "name": "Respond to Webhook"
    }
  ],
  "connections": {
    "Receive Solver Request": {
      "main": [
        [
          {
            "node": "GeeTest V3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GeeTest V3": {
      "main": [
        [
          {
            "node": "CapSolver Error?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CapSolver Error?": {
      "main": [
        [
          {
            "node": "Respond to Webhook (Error)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  }
}

API Parameter Reference

The GeeTest V3 solver API endpoint accepts the following parameters:

Parameter Required Description
websiteURL Yes The URL of the page hosting the GeeTest challenge
gt Yes The per-site GeeTest identifier (static)
challenge Yes The dynamic per-session challenge token (must be freshly fetched)
geetestApiServerSubdomain No Custom GeeTest API server subdomain

Tip: The gt parameter is typically found in the page source or in network requests to GeeTest's API. The challenge must be fetched from the site's challenge endpoint immediately before solving.

Compared to reCAPTCHA or Turnstile, GeeTest V3 has an additional required parameter (challenge) and returns three solution values instead of one token. The dynamic nature of the challenge parameter means you cannot cache or reuse it.


Workflow: Submitting GeeTest V3 Tokens to a Website

The API workflow above shows how to get a solved GeeTest V3 challenge. But what do you actually do with it?

In real-world automation, solving the challenge is only half the job. You need to submit the three solution values to the target website -- exactly as a browser would -- to unlock the data or action behind the GeeTest protection.

Here's the general pattern:

  1. Fetch the challenge -> GET the challenge API endpoint to get fresh gt and challenge values
  2. Solve the challenge -> Send gt, challenge, and websiteURL to CapSolver
  3. Submit the solution -> POST three form fields: geetest_challenge, geetest_validate, geetest_seccode
  4. Verify the response -> Check if the website accepted the solution
  5. Process the result -> Extract the data you need

Example: Solving & Submitting GeeTest V3

Workflow Flow

Copy
Manual Trigger -> Fetch Challenge -> CapSolver GeeTest V3 -> HTTP POST Request (3 fields) -> IF (check success) -> Edit Fields

How It Works

  1. Manual Trigger -- Starts the workflow manually. You can replace this with any trigger.
  2. Fetch GeeTest Challenge -- HTTP GET to the site's challenge API endpoint (e.g., https://example.com/api/geetest/register?t={{ Date.now() }}). Returns gt and challenge.
  3. CapSolver GeeTest V3 -- Solves the challenge:
    • Operation: GeeTest V3
    • Website URL: https://example.com/login
    • GT: ={{ $json.gt }}
    • Challenge: ={{ $json.challenge }}
  4. HTTP POST Request -- Submits the three solution values to the target website:
    • geetest_challenge: ={{ $json.data.solution.challenge }}
    • geetest_validate: ={{ $json.data.solution.validate }}
    • geetest_seccode: ={{ $json.data.solution.seccode }}
    • Include any other form fields the site expects (e.g., username, password)
  5. IF Node -- Checks if the response indicates success
  6. Edit Fields -- Extracts the data you need from the response

Key concept: Every website handles GeeTest token submission differently. In this example, the three values go in form-urlencoded POST body fields. Other sites may expect them as JSON fields, query parameters, or through a separate verification endpoint. Always inspect the site's actual form submission (using DevTools Network tab) to see exactly how the values need to be sent.


Workflow: Use-Case Examples

The solver API and submission example above show the core pattern: fetch the challenge, solve it, submit the three values, process the result. The following workflows extend this pattern to production-ready use cases -- each with dual triggers (schedule + webhook), persistent state tracking, and structured output.

Workflow Purpose
GeeTest V3 Scraping -- Price & Product Details Scrapes price and product name every 6 hours, compares against previous values stored in staticData, alerts on changes
GeeTest V3 Account Login Logs into your own account on a GeeTest-protected site by fetching the challenge, solving it, then POSTing credentials with the three solution values

Example 1: Scraping

This workflow scrapes a product page every 6 hours (schedule) or on demand (webhook), fetches a fresh GeeTest challenge, solves it via CapSolver, extracts the price using the HTML node, and compares it against the previously stored value.

Schedule path:

Copy
Every 6 Hours -> Fetch GeeTest Challenge -> Solve GeeTest V3 -> Fetch Product Page
  -> Extract Data -> Compare Data -> Data Changed? -> Build Alert / No Change

Key behaviors:

  • An extra HTTP Request node fetches a fresh GeeTest challenge before each solve (this is the key difference from Turnstile/reCAPTCHA workflows)
  • The three solution values (geetest_challenge, geetest_validate, geetest_seccode) are sent as form-urlencoded POST body fields
  • The HTML node extracts price and product name via CSS selectors (.product-price, h1)
  • $workflow.staticData.lastPrice persists the previous price across executions
  • Price comparison detects both drops (severity: deal) and increases (severity: info)
Click to expand full workflow JSON (19 nodes)
json Copy
{
  "name": "GeeTest V3 Scraping โ€” Price & Product Details โ€” CapSolver + Schedule + Webhook",
  "nodes": [
    {
      "parameters": {
        "content": "## GeeTest V3 Scraping โ€” Price & Product Monitor\n\n**Who it's for:** Teams monitoring prices or product data on GeeTest V3-protected sites.\n\n**What it does:** Solves GeeTest V3, fetches a product page, extracts price & name via CSS selectors, compares against stored values, and alerts on changes.\n\n**How it works:**\n1. Schedule (every 6h) or Webhook triggers the flow\n2. CapSolver solves the GeeTest V3 challenge\n3. HTTP Request fetches the product page with the solved token\n4. HTML node extracts price and product name\n5. Code node compares current vs. stored price โ†’ alerts on change\n\n**Setup:**\n1. Add your CapSolver API key under **Settings โ†’ Credentials**\n2. Replace placeholder URLs and site keys\n3. Update CSS selectors in Extract Data to match your target page\n4. Connect the Build Alert output to your notification channel",
        "height": 560,
        "width": 460,
        "color": 1
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1220,
        -380
      ],
      "id": "sticky-blog-main-1773678228108-1",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "### Schedule Path\nRuns automatically every 6 hours.\nResults stored in workflow static data for cross-execution comparison.",
        "height": 480,
        "width": 2200,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -740,
        -280
      ],
      "id": "sticky-blog-section-1773678228108-2",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "### Webhook Path\nOn-demand trigger โ€” same logic, returns result as JSON response.",
        "height": 480,
        "width": 2200,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -740,
        140
      ],
      "id": "sticky-blog-section-1773678228108-3",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -700,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888801",
      "name": "Every 6 Hours"
    },
    {
      "parameters": {
        "url": "https://YOUR-TARGET-SITE.com/api/geetest/register?t={{ Date.now() }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -400,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888802",
      "name": "Fetch GeeTest Challenge"
    },
    {
      "parameters": {
        "operation": "GeeTest V3",
        "websiteURL": "https://YOUR-TARGET-SITE.com/product-page",
        "gt": "={{ $json.gt }}",
        "challenge": "={{ $json.challenge }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        -96,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888803",
      "name": "Solve GeeTest V3",
      "credentials": {
        "capSolverApi": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "CapSolver account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://YOUR-TARGET-SITE.com/product-page",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "user-agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
            },
            {
              "name": "content-type",
              "value": "application/x-www-form-urlencoded"
            }
          ]
        },
        "sendBody": true,
        "contentType": "form-urlencoded",
        "bodyParameters": {
          "parameters": [
            {
              "name": "geetest_challenge",
              "value": "={{ $('Solve GeeTest V3').item.json.data.solution.challenge }}"
            },
            {
              "name": "geetest_validate",
              "value": "={{ $('Solve GeeTest V3').item.json.data.solution.validate }}"
            },
            {
              "name": "geetest_seccode",
              "value": "={{ $('Solve GeeTest V3').item.json.data.solution.seccode }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        208,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888804",
      "name": "Fetch Product Page"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "sourceData": "json",
        "dataPropertyName": "data",
        "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": [
        512,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888805",
      "name": "Extract Data"
    },
    {
      "parameters": {
        "jsCode": "// Get current and previous price from workflow static data\nconst staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Product';\n\n// Parse numeric values for comparison\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\n// Update stored price\nstaticData.lastPrice = currentPrice;\nstaticData.lastChecked = new Date().toISOString();\n\nconst changed = previousNum !== null && currentNum !== null && currentNum !== previousNum;\nconst direction = changed ? (currentNum < previousNum ? 'dropped' : 'increased') : 'unchanged';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\n\nreturn [{\n  json: {\n    productName,\n    currentPrice,\n    previousPrice: previousPrice || 'first check',\n    changed,\n    direction,\n    diff: changed ? `$${diff}` : null,\n    checkedAt: new Date().toISOString()\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888806",
      "name": "Compare Data"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "price-if-001",
              "leftValue": "={{ $json.changed }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1104,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888807",
      "name": "Data Changed?"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "alert-001",
              "name": "alert",
              "value": "=Price {{ $json.direction }} for {{ $json.productName }}: {{ $json.previousPrice }} โ†’ {{ $json.currentPrice }} ({{ $json.direction === 'dropped' ? '-' : '+' }}{{ $json.diff }})",
              "type": "string"
            },
            {
              "id": "alert-002",
              "name": "severity",
              "value": "={{ $json.direction === 'dropped' ? 'deal' : 'info' }}",
              "type": "string"
            },
            {
              "id": "alert-003",
              "name": "checkedAt",
              "value": "={{ $json.checkedAt }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1408,
        -80
      ],
      "id": "88888888-8888-8888-8888-888888888808",
      "name": "Build Alert"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "nc-001",
              "name": "status",
              "value": "no_change",
              "type": "string"
            },
            {
              "id": "nc-002",
              "name": "currentPrice",
              "value": "={{ $json.currentPrice }}",
              "type": "string"
            },
            {
              "id": "nc-003",
              "name": "checkedAt",
              "value": "={{ $json.checkedAt }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1408,
        128
      ],
      "id": "88888888-8888-8888-8888-888888888809",
      "name": "No Change"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "price-monitor-geetest-v3",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -700,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888810",
      "name": "Webhook Trigger",
      "webhookId": "88888888-aaaa-bbbb-cccc-888888888810",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "url": "https://YOUR-TARGET-SITE.com/api/geetest/register?t={{ Date.now() }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -400,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888811",
      "name": "Fetch GeeTest Challenge [Webhook]"
    },
    {
      "parameters": {
        "operation": "GeeTest V3",
        "websiteURL": "https://YOUR-TARGET-SITE.com/product-page",
        "gt": "={{ $json.gt }}",
        "challenge": "={{ $json.challenge }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        -96,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888812",
      "name": "Solve GeeTest V3 [Webhook]",
      "credentials": {
        "capSolverApi": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "CapSolver account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://YOUR-TARGET-SITE.com/product-page",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "user-agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
            },
            {
              "name": "content-type",
              "value": "application/x-www-form-urlencoded"
            }
          ]
        },
        "sendBody": true,
        "contentType": "form-urlencoded",
        "bodyParameters": {
          "parameters": [
            {
              "name": "geetest_challenge",
              "value": "={{ $('Solve GeeTest V3 [Webhook]').item.json.data.solution.challenge }}"
            },
            {
              "name": "geetest_validate",
              "value": "={{ $('Solve GeeTest V3 [Webhook]').item.json.data.solution.validate }}"
            },
            {
              "name": "geetest_seccode",
              "value": "={{ $('Solve GeeTest V3 [Webhook]').item.json.data.solution.seccode }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        208,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888813",
      "name": "Fetch Product Page [Webhook]"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "sourceData": "json",
        "dataPropertyName": "data",
        "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": [
        512,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888814",
      "name": "Extract Data [Webhook]"
    },
    {
      "parameters": {
        "jsCode": "// Get current and previous price from workflow static data\nconst staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Product';\n\n// Parse numeric values for comparison\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\n// Update stored price\nstaticData.lastPrice = currentPrice;\nstaticData.lastChecked = new Date().toISOString();\n\nconst changed = previousNum !== null && currentNum !== null && currentNum !== previousNum;\nconst direction = changed ? (currentNum < previousNum ? 'dropped' : 'increased') : 'unchanged';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\n\nreturn [{\n  json: {\n    productName,\n    currentPrice,\n    previousPrice: previousPrice || 'first check',\n    changed,\n    direction,\n    diff: changed ? `$${diff}` : null,\n    checkedAt: new Date().toISOString()\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888815",
      "name": "Compare Data [Webhook]"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "price-if-002",
              "leftValue": "={{ $json.changed }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1104,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888816",
      "name": "Data Changed? [Webhook]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "alert-004",
              "name": "alert",
              "value": "=Price {{ $json.direction }} for {{ $json.productName }}: {{ $json.previousPrice }} โ†’ {{ $json.currentPrice }} ({{ $json.direction === 'dropped' ? '-' : '+' }}{{ $json.diff }})",
              "type": "string"
            },
            {
              "id": "alert-005",
              "name": "severity",
              "value": "={{ $json.direction === 'dropped' ? 'deal' : 'info' }}",
              "type": "string"
            },
            {
              "id": "alert-006",
              "name": "checkedAt",
              "value": "={{ $json.checkedAt }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1408,
        340
      ],
      "id": "88888888-8888-8888-8888-888888888817",
      "name": "Build Alert [Webhook]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "nc-004",
              "name": "status",
              "value": "no_change",
              "type": "string"
            },
            {
              "id": "nc-005",
              "name": "currentPrice",
              "value": "={{ $json.currentPrice }}",
              "type": "string"
            },
            {
              "id": "nc-006",
              "name": "checkedAt",
              "value": "={{ $json.checkedAt }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1408,
        548
      ],
      "id": "88888888-8888-8888-8888-888888888818",
      "name": "No Change [Webhook]"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        1712,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888819",
      "name": "Respond to Webhook"
    }
  ],
  "connections": {
    "Every 6 Hours": {
      "main": [
        [
          {
            "node": "Fetch GeeTest Challenge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GeeTest Challenge": {
      "main": [
        [
          {
            "node": "Solve GeeTest V3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solve GeeTest V3": {
      "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": "Fetch GeeTest Challenge [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GeeTest Challenge [Webhook]": {
      "main": [
        [
          {
            "node": "Solve GeeTest V3 [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solve GeeTest V3 [Webhook]": {
      "main": [
        [
          {
            "node": "Fetch Product Page [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Product Page [Webhook]": {
      "main": [
        [
          {
            "node": "Extract Data [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Data [Webhook]": {
      "main": [
        [
          {
            "node": "Compare Data [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare Data [Webhook]": {
      "main": [
        [
          {
            "node": "Data Changed? [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Changed? [Webhook]": {
      "main": [
        [
          {
            "node": "Build Alert [Webhook]",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Change [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Alert [Webhook]": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "No Change [Webhook]": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  }
}

Example 2: Account Login

This workflow automates login to a GeeTest V3-protected site. A Set Login Config node centralizes all parameters -- including the challengeAPIURL for fetching the dynamic challenge. The Fetch GeeTest Challenge node runs before each solve to get a fresh challenge value.

Schedule path:

Copy
Every 24 Hours -> Set Login Config -> Fetch GeeTest Challenge -> Solve GeeTest V3
  -> Submit Login -> Login Successful? -> Mark Login Success / Mark Login Failed

Key behaviors:

  • The Set Login Config node includes challengeAPIURL (the endpoint to fetch fresh gt + challenge values) and gt (static per site)
  • A Fetch GeeTest Challenge node fetches a fresh challenge before each solve attempt
  • Body parameters include username, password, plus three GeeTest fields: geetest_challenge, geetest_validate, geetest_seccode
  • No websiteKey or tokenFieldName -- GeeTest V3 uses gt + challenge and always submits via three fixed field names
  • The Login Successful? check evaluates both statusCode < 400 and the presence of a configurable successMarker in the response body
  • Webhook path fetches the challenge from the URL provided in the request body
Click to expand full workflow JSON (17 nodes)
json Copy
{
  "name": "GeeTest V3 Account Login โ€” CapSolver + Schedule + Webhook",
  "nodes": [
    {
      "parameters": {
        "content": "## GeeTest V3 Account Login\n\n**Who it's for:** Anyone automating login to a GeeTest V3-protected website.\n\n**What it does:** Solves GeeTest V3 before submitting login credentials, then checks whether login succeeded.\n\n**How it works:**\n1. Schedule (every 24h) or Webhook triggers the flow\n2. Set Login Config centralizes all parameters (URL, keys, credentials, task type)\n3. CapSolver solves the GeeTest V3 challenge\n4. Submit Login POSTs credentials with the solved token\n5. Login Successful? checks status code and response body\n\n**Setup:**\n1. Add your CapSolver API key under **Settings โ†’ Credentials**\n2. Edit **Set Login Config** โ€” replace URL, site key, email, password, and success marker\n3. Edit **Submit Login** to match your target site's form field names\n4. Change task type if needed",
        "height": 560,
        "width": 460,
        "color": 1
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1460,
        -380
      ],
      "id": "sticky-blog-main-1773678228108-1",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "### Schedule Path\nRuns every 24 hours to keep the session alive or verify access.",
        "height": 480,
        "width": 2200,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -980,
        -280
      ],
      "id": "sticky-blog-section-1773678228108-2",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "### Webhook Path\nOn-demand login trigger โ€” returns result as JSON response.",
        "height": 480,
        "width": 2200,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -980,
        140
      ],
      "id": "sticky-blog-section-1773678228108-3",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -940,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888821",
      "name": "Every 24 Hours"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "login-001",
              "name": "websiteURL",
              "value": "https://YOUR-LOGIN-PAGE.com",
              "type": "string"
            },
            {
              "id": "login-002",
              "name": "gt",
              "value": "YOUR_GT_PARAMETER_HERE",
              "type": "string"
            },
            {
              "id": "login-003",
              "name": "challengeAPIURL",
              "value": "https://YOUR-LOGIN-PAGE.com/api/geetest/register",
              "type": "string"
            },
            {
              "id": "login-004",
              "name": "usernameField",
              "value": "email",
              "type": "string"
            },
            {
              "id": "login-005",
              "name": "passwordField",
              "value": "password",
              "type": "string"
            },
            {
              "id": "login-006",
              "name": "usernameValue",
              "value": "[email protected]",
              "type": "string"
            },
            {
              "id": "login-007",
              "name": "passwordValue",
              "value": "YOUR_ACCOUNT_PASSWORD",
              "type": "string"
            },
            {
              "id": "login-008",
              "name": "successMarker",
              "value": "account-dashboard",
              "type": "string"
            },
            {
              "id": "login-009",
              "name": "userAgent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -636,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888822",
      "name": "Set Login Config [Schedule]"
    },
    {
      "parameters": {
        "url": "={{ $json.challengeAPIURL }}?t={{ Date.now() }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -336,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888823",
      "name": "Fetch GeeTest Challenge [Schedule]"
    },
    {
      "parameters": {
        "operation": "GeeTest V3",
        "websiteURL": "={{ $('Set Login Config [Schedule]').item.json.websiteURL }}",
        "gt": "={{ $json.gt }}",
        "challenge": "={{ $json.challenge }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        -32,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888824",
      "name": "Solve GeeTest V3 [Schedule]",
      "credentials": {
        "capSolverApi": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "CapSolver account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Set Login Config [Schedule]').item.json.websiteURL }}/login",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/x-www-form-urlencoded"
            },
            {
              "name": "user-agent",
              "value": "={{ $('Set Login Config [Schedule]').item.json.userAgent }}"
            }
          ]
        },
        "sendBody": true,
        "contentType": "form-urlencoded",
        "bodyParameters": {
          "parameters": [
            {
              "name": "={{ $('Set Login Config [Schedule]').item.json.usernameField }}",
              "value": "={{ $('Set Login Config [Schedule]').item.json.usernameValue }}"
            },
            {
              "name": "={{ $('Set Login Config [Schedule]').item.json.passwordField }}",
              "value": "={{ $('Set Login Config [Schedule]').item.json.passwordValue }}"
            },
            {
              "name": "geetest_challenge",
              "value": "={{ $json.data.solution.challenge }}"
            },
            {
              "name": "geetest_validate",
              "value": "={{ $json.data.solution.validate }}"
            },
            {
              "name": "geetest_seccode",
              "value": "={{ $json.data.solution.seccode }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        272,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888825",
      "name": "Submit Login [Schedule]"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "login-if-001",
              "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": [
        576,
        0
      ],
      "id": "88888888-8888-8888-8888-888888888826",
      "name": "Login Successful? [Schedule]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "login-015",
              "name": "action",
              "value": "account_login",
              "type": "string"
            },
            {
              "id": "login-016",
              "name": "status",
              "value": "success",
              "type": "string"
            },
            {
              "id": "login-017",
              "name": "message",
              "value": "Configured account login flow succeeded",
              "type": "string"
            },
            {
              "id": "login-018",
              "name": "checkedAt",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        880,
        -80
      ],
      "id": "88888888-8888-8888-8888-888888888827",
      "name": "Mark Login Success [Schedule]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "login-019",
              "name": "action",
              "value": "account_login",
              "type": "string"
            },
            {
              "id": "login-020",
              "name": "status",
              "value": "failed",
              "type": "string"
            },
            {
              "id": "login-021",
              "name": "statusCode",
              "value": "={{ $json.statusCode }}",
              "type": "number"
            },
            {
              "id": "login-022",
              "name": "message",
              "value": "Login response did not match the configured success marker",
              "type": "string"
            },
            {
              "id": "login-023",
              "name": "checkedAt",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        880,
        120
      ],
      "id": "88888888-8888-8888-8888-888888888828",
      "name": "Mark Login Failed [Schedule]"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "account-login-geetest-v3",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -940,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888829",
      "name": "Webhook Trigger",
      "webhookId": "88888888-aaaa-bbbb-cccc-888888888829",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "url": "={{ $json.body.challengeAPIURL || 'https://YOUR-LOGIN-PAGE.com/api/geetest/register' }}?t={{ Date.now() }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -336,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888830",
      "name": "Fetch GeeTest Challenge [Webhook]"
    },
    {
      "parameters": {
        "operation": "GeeTest V3",
        "websiteURL": "={{ $('Webhook Trigger').item.json.body.websiteURL }}",
        "gt": "={{ $json.gt }}",
        "challenge": "={{ $json.challenge }}",
        "optional": {}
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        -32,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888831",
      "name": "Solve GeeTest V3 [Webhook]",
      "credentials": {
        "capSolverApi": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "CapSolver account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Webhook Trigger').item.json.body.loginActionURL }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/x-www-form-urlencoded"
            },
            {
              "name": "user-agent",
              "value": "={{ $('Webhook Trigger').item.json.body.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36' }}"
            }
          ]
        },
        "sendBody": true,
        "contentType": "form-urlencoded",
        "bodyParameters": {
          "parameters": [
            {
              "name": "={{ $('Webhook Trigger').item.json.body.usernameField || 'email' }}",
              "value": "={{ $('Webhook Trigger').item.json.body.usernameValue }}"
            },
            {
              "name": "={{ $('Webhook Trigger').item.json.body.passwordField || 'password' }}",
              "value": "={{ $('Webhook Trigger').item.json.body.passwordValue }}"
            },
            {
              "name": "geetest_challenge",
              "value": "={{ $json.data.solution.challenge }}"
            },
            {
              "name": "geetest_validate",
              "value": "={{ $json.data.solution.validate }}"
            },
            {
              "name": "geetest_seccode",
              "value": "={{ $json.data.solution.seccode }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        272,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888832",
      "name": "Submit Login [Webhook]"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "login-if-002",
              "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": [
        576,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888833",
      "name": "Login Successful? [Webhook]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "login-038",
              "name": "action",
              "value": "account_login",
              "type": "string"
            },
            {
              "id": "login-039",
              "name": "status",
              "value": "success",
              "type": "string"
            },
            {
              "id": "login-040",
              "name": "message",
              "value": "Configured account login flow succeeded",
              "type": "string"
            },
            {
              "id": "login-041",
              "name": "checkedAt",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        880,
        340
      ],
      "id": "88888888-8888-8888-8888-888888888834",
      "name": "Mark Login Success [Webhook]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "login-042",
              "name": "action",
              "value": "account_login",
              "type": "string"
            },
            {
              "id": "login-043",
              "name": "status",
              "value": "failed",
              "type": "string"
            },
            {
              "id": "login-044",
              "name": "statusCode",
              "value": "={{ $json.statusCode }}",
              "type": "number"
            },
            {
              "id": "login-045",
              "name": "message",
              "value": "Login response did not match the configured success marker",
              "type": "string"
            },
            {
              "id": "login-046",
              "name": "checkedAt",
              "value": "={{ new Date().toISOString() }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        880,
        540
      ],
      "id": "88888888-8888-8888-8888-888888888835",
      "name": "Mark Login Failed [Webhook]"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        1184,
        420
      ],
      "id": "88888888-8888-8888-8888-888888888836",
      "name": "Respond to Webhook"
    }
  ],
  "connections": {
    "Every 24 Hours": {
      "main": [
        [
          {
            "node": "Set Login Config [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Login Config [Schedule]": {
      "main": [
        [
          {
            "node": "Fetch GeeTest Challenge [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GeeTest Challenge [Schedule]": {
      "main": [
        [
          {
            "node": "Solve GeeTest V3 [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solve GeeTest V3 [Schedule]": {
      "main": [
        [
          {
            "node": "Submit Login [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit Login [Schedule]": {
      "main": [
        [
          {
            "node": "Login Successful? [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Login Successful? [Schedule]": {
      "main": [
        [
          {
            "node": "Mark Login Success [Schedule]",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Login Failed [Schedule]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Fetch GeeTest Challenge [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GeeTest Challenge [Webhook]": {
      "main": [
        [
          {
            "node": "Solve GeeTest V3 [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Solve GeeTest V3 [Webhook]": {
      "main": [
        [
          {
            "node": "Submit Login [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit Login [Webhook]": {
      "main": [
        [
          {
            "node": "Login Successful? [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Login Successful? [Webhook]": {
      "main": [
        [
          {
            "node": "Mark Login Success [Webhook]",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Login Failed [Webhook]",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Login Success [Webhook]": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Login Failed [Webhook]": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  }
}

Conclusion

You've learned how to build a GeeTest V3-solving API and production-ready scraping and login workflows using n8n and CapSolver -- no traditional coding required.

In this guide, we covered:

  • An API solver endpoint for GeeTest V3 using a webhook-based workflow
  • Use-case examples -- scraping and account login -- showing how to fetch dynamic challenges, submit solved tokens, and process protected data
  • How to identify GeeTest V3 parameters (gt, challenge, and the challenge API endpoint)
  • The key difference from other CAPTCHAs -- GeeTest V3's challenge is dynamic and must be fetched fresh before each solve, and the solution returns 3 values instead of 1

The key takeaway: GeeTest V3 requires an extra step compared to reCAPTCHA or Turnstile -- you must fetch a fresh challenge value before each solve. The solution is also 3 fields (geetest_challenge, geetest_validate, geetest_seccode) rather than a single token.

Tip: These workflows use Schedule + Webhook triggers, but you can swap the trigger node to any n8n trigger -- manual, app event, form submission, etc. After fetching data, use n8n's built-in nodes to save results to Google Sheets, databases, cloud storage, or send alerts via Telegram/Slack/Email.


Ready to get started? Sign up for CapSolver and use bonus code n8n for an extra 8% bonus on your first recharge!

CapSolver bonus code banner

Frequently Asked Questions

What is GeeTest V3?

GeeTest V3 is a challenge-response CAPTCHA system that verifies users through interactive tasks like slide puzzles, icon clicks, and word matching. It uses two key parameters: gt (static per site) and challenge (dynamic per session), and returns three solution values instead of a single token.

How much does it cost to solve a GeeTest V3 challenge?

Pricing varies based on usage. Check the CapSolver pricing page for current GeeTest rates.

How long does it take to solve a GeeTest V3 challenge?

GeeTest V3 challenges are typically solved in 5-15 seconds depending on the challenge type and complexity.

Can I use this workflow with n8n Cloud?

Yes! This workflow works with both self-hosted n8n and n8n Cloud. The CapSolver node is already available as an official integration -- just add your API credentials.

How do I find the gt and challenge API endpoint for a website?

Open DevTools (F12) -> Network tab and look for requests containing gt= in the URL or responses with "gt" and "challenge" JSON fields. Common endpoint patterns include /api/geetest/register, /gt/register-slide, and /captcha?gt=....

What is the difference between GeeTest V3 and V4?

GeeTest V3 uses gt + challenge parameters and requires fetching a fresh challenge before each solve. GeeTest V4 uses a captcha_id parameter instead and has a different API structure. If you see captcha_id in the page source, you're dealing with V4, not V3.

CapSolver returned solution values but the website still rejected them -- why?

Several things can cause this. First, the challenge expires quickly (60-120 seconds) -- make sure you're fetching a fresh challenge immediately before solving and submitting the solution immediately after. Second, verify the three form field names match what the site expects: most sites use geetest_challenge, geetest_validate, and geetest_seccode, but some may use different names. Inspect the actual form submission in DevTools -> Network tab. Third, some sites require the optional geetestApiServerSubdomain parameter. If the solution is still rejected, contact CapSolver support for site-specific help.

Compliance Disclaimer: The information provided on this blog is for informational purposes only. CapSolver is committed to compliance with all applicable laws and regulations. The use of the CapSolver network for illegal, fraudulent, or abusive activities is strictly prohibited and will be investigated. Our captcha-solving solutions enhance user experience while ensuring 100% compliance in helping solve captcha difficulties during public data crawling. We encourage responsible use of our services. For more information, please visit our Terms of Service and Privacy Policy.

More