CAPSOLVER
Blog
How to solve AWS Captcha with NodeJS

How to solve AWS Captcha with NodeJS

Logo of CapSolver

Rajinder Singh

Deep Learning Researcher

03-Nov-2025

In the modern web landscape, protecting online resources from automated threats is paramount. AWS Web Application Firewall (WAF) is a robust security layer that often deploys challenges or managed captchas to filter out malicious bots. While effective for security, these mechanisms pose a significant hurdle for legitimate automation tasks, such as web scraping, monitoring, or testing.

This comprehensive guide provides a powerful, automated solution using Node.js and the CapSolver service. We will walk you through setting up the environment, implementing a modular Node.js script, and leveraging CapSolver's specialized AntiAwsWafTask to bypass both the WAF Challenge (HTTP 202) and the WAF Captcha (HTTP 405) scenarios. By the end of this tutorial, you will have a production-ready script capable of obtaining the necessary aws-waf-token cookie to access protected content.

⚙️ Prerequisites

Before you begin, ensure you have the following environment and information ready:

  1. Node.js Environment: Node.js is installed on your system (LTS version recommended).
  2. CapSolver API Key: You need a CapSolver account and your API key.
  3. Proxy (Optional): If the target website has geo-restrictions or you need to hide your real IP, prepare an HTTP/HTTPS proxy.

🛠️ Step One: Install Necessary Dependencies

In your project directory, execute the following command to install the required Node.js modules:

bash Copy
npm install axios cheerio
  • axios: Used for sending HTTP requests.
  • cheerio: Used for parsing HTML content and extracting parameters required for the AWS WAF challenge.

💻 Step Two: Node.js Core Code Implementation

Below is the Node.js script for solving AWS WAF Challenges and Captchas. It automatically detects the status code returned by the website and executes the corresponding CapSolver task as needed.

Please save the following code as aws_waf_solver.js.

javascript Copy
const axios = require('axios');
const cheerio = require('cheerio');
const { URL } = require('url');

// ⚠️ Configuration: Please replace with your actual values
const CLIENT_KEY = "YOUR_CAPSOLVER_API_KEY"; // Replace with your CapSolver API Key
const PAGE_URL = "https://norway-meetup.aws.wslab.no/"; // Replace with the target website URL
const PROXY = "YOUR_PROXY_ADDRESS"; // Replace with your proxy address (Format: user:pass@ip:port or ip:port)

// --- Helper Functions ---

/**
 * Pauses execution for a specified number of milliseconds
 * @param {number} ms Milliseconds
 */
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

/**
 * Creates a task with CapSolver
 * @param {object} payload Task payload
 * @returns {Promise<object>} Task creation result
 */
async function createTask(payload) {
    try {
        const res = await axios.post('https://api.capsolver.com/createTask', {
            clientKey: CLIENT_KEY,
            task: payload
        });
        if (res.data.errorId !== 0) {
            throw new Error(`CapSolver API Error: ${res.data.errorDescription}`);
        }
        return res.data;
    } catch (error) {
        console.error("Failed to create CapSolver task:", error.message);
        return null;
    }
}

/**
 * Gets the CapSolver task result until the task is completed
 * @param {string} taskId Task ID
 * @returns {Promise<object>} Task result
 */
async function getTaskResult(taskId) {
    if (!taskId) return null;
    console.log(`Waiting for task result (ID: ${taskId})...`);
    try {
        let success = false;
        let result = null;
        while (!success) {
            await sleep(3000); // Query every 3 seconds
            const res = await axios.post('https://api.capsolver.com/getTaskResult', {
                clientKey: CLIENT_KEY,
                taskId: taskId
            });

            if (res.data.errorId !== 0) {
                throw new Error(`CapSolver API Error: ${res.data.errorDescription}`);
            }

            if (res.data.status === "ready") {
                success = true;
                result = res.data;
                console.log("Task completed, solution obtained.");
            } else if (res.data.status === "processing") {
                console.log("Task is still processing...");
            }
        }
        return result;
    } catch (error) {
        console.error("Failed to get CapSolver task result:", error.message);
        return null;
    }
}

// --- Core Solver Functions ---

/**
 * Solves AWS WAF Challenge (Status Code 202)
 * @param {string} awsChallengeJS AWS Challenge JavaScript URL
 * @returns {Promise<string|null>} Solved AWS WAF Cookie value
 */
async function solveAwsChallenge(awsChallengeJS) {
    console.log("AWS WAF Challenge detected (Status Code 202), starting to solve...");
    const taskPayload = {
        type: "AntiAwsWafTask",
        websiteURL: PAGE_URL,
        awsChallengeJS,
        proxy: PROXY
    };
    const taskData = await createTask(taskPayload);
    if (!taskData) return null;

    const result = await getTaskResult(taskData.taskId);
    if (result && result.solution && result.solution.cookie) {
        return result.solution.cookie;
    }
    return null;
}

/**
 * Solves AWS WAF Captcha + Challenge (Status Code 405)
 * @param {string} htmlContent HTML content containing Captcha parameters
 * @param {string} awsChallengeJS AWS Challenge JavaScript URL
 * @returns {Promise<string|null>} Solved AWS WAF Cookie value
 */
async function solveAwsCaptchaChallenge(htmlContent, awsChallengeJS) {
    console.log("AWS WAF Captcha detected (Status Code 405), starting to solve...");
    const $ = cheerio.load(htmlContent);
    const scriptContent = $("script[type='text/javascript']").last().html();

    if (!scriptContent) {
        console.error("Could not find the script content containing Captcha parameters.");
        return null;
    }

    // Use regular expressions to extract key parameters
    const keyMatch = /"key":"(.*?)"/.exec(scriptContent);
    const ivMatch = /"iv":"(.*?)"/.exec(scriptContent);
    const contextMatch = /"context":"(.*?)"/.exec(scriptContent);

    const key = keyMatch ? keyMatch[1] : null;
    const iv = ivMatch ? ivMatch[1] : null;
    const context = contextMatch ? contextMatch[1] : null;

    if (!key || !iv || !context) {
        console.error("Failed to extract all required Captcha parameters (key, iv, context) from the script.");
        return null;
    }

    console.log(`Extracted Parameters: Key=${key}, IV=${iv}, Context=${context}`);

    const taskPayload = {
        type: "AntiAwsWafTask", // CapSolver uses this task type uniformly
        websiteURL: PAGE_URL,
        awsKey: key,
        awsIv: iv,
        awsContext: context,
        awsChallengeJS,
        proxy: PROXY
    };

    const taskData = await createTask(taskPayload);
    if (!taskData) return null;

    const result = await getTaskResult(taskData.taskId);
    if (result && result.solution && result.solution.cookie) {
        return result.solution.cookie;
    }
    return null;
}

/**
 * Main execution function
 */
async function main() {
    let awsWafCookie = null;
    let initialResponse = null;

    // 1. Initial request to the target page
    try {
        console.log(`Requesting target page: ${PAGE_URL}`);
        initialResponse = await axios.get(PAGE_URL, {
            headers: {
                // Simulate browser request headers
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                "Accept-Encoding": "gzip, deflate, br",
                "Accept-Language": "en-US,en;q=0.9",
                "Cache-Control": "max-age=0",
                "Upgrade-Insecure-Requests": "1"
            },
            // Allow processing 2xx, 3xx, 4xx status codes
            validateStatus: (status) => status >= 200 && status < 500
        });
        console.log(`Initial response status code: ${initialResponse.status}`);
    } catch (error) {
        console.error(`Initial request failed: ${error.message}`);
        return;
    }

    const $ = cheerio.load(initialResponse.data);
    const scriptTags = $('script[src*="token.awswaf.com"]');
    const awsChallengeJS = scriptTags.attr('src');

    if (!awsChallengeJS) {
        console.log("AWS WAF challenge script not detected. The website may not be protected or has already passed.");
        // If no challenge script, use the initial response directly
        if (initialResponse.status === 200) {
            console.log("Website loaded successfully.");
            // console.log(initialResponse.data); // Print final content
            return;
        }
    } else {
        console.log(`AWS WAF challenge script URL detected: ${awsChallengeJS}`);
    }


    // 2. Determine and solve the challenge/captcha based on the status code
    if (initialResponse.status === 202) {
        // AWS WAF Challenge only
        awsWafCookie = await solveAwsChallenge(awsChallengeJS);
    } else if (initialResponse.status === 405) {
        // AWS WAF Captcha + Challenge
        awsWafCookie = await solveAwsCaptchaChallenge(initialResponse.data, awsChallengeJS);
    } else if (initialResponse.status === 200) {
        console.log("Website loaded successfully, no captcha solving required.");
        // console.log(initialResponse.data); // Print final content
        return;
    } else {
        console.log(`Encountered unhandled status code: ${initialResponse.status}.`);
        return;
    }

    // 3. Request the target page again using the obtained Cookie
    if (awsWafCookie) {
        try {
            console.log("\n--- Second Request: Using AWS WAF Cookie ---");
            console.log(`Cookie used: ${awsWafCookie}`);

            const finalResponse = await axios.get(PAGE_URL, {
                headers: {
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
                    "Cookie": `aws-waf-token=${awsWafCookie}`
                },
                validateStatus: (status) => status === 200 // Expect final success
            });

            console.log(`Final response status code: ${finalResponse.status}`);
            console.log("Website content retrieved successfully!");
            // console.log(finalResponse.data); // Print final content
        } catch (error) {
            console.error(`Final request failed: ${error.message}`);
        }
    } else {
        console.log("Failed to obtain AWS WAF Cookie, unable to perform the second request.");
    }
}

main();

💡 Key Points Summary

Key Point Original Code Issue Optimized Improvement
Dependency Installation Missing cheerio, used incorrect Python syntax highlighting. Clearly stated the need to install axios and cheerio, used correct bash syntax highlighting.
Task Type Mixed use of FunCaptchaTaskProxyless and AntiAwsWafTask. Unified use of CapSolver's officially recommended AntiAwsWafTask for all AWS WAF scenarios.
Parameter Extraction Incomplete logic for extracting awsChallengeJS in the 405 logic, and not extracted in the 202 logic. Unified extraction of awsChallengeJS after the initial request in the main function, and called different solver functions based on the status code (202 or 405).
Error Handling Simple error handling, lacking API error checks and task waiting prompts. Added CapSolver API error checks (errorId !== 0) in createTask and getTaskResult, and provided status prompts during task processing.
Code Structure All logic was clustered in the main function, leading to poor readability. Separated into clear helper functions (sleep, createTask, getTaskResult) and core solver functions (solveAwsChallenge, solveAwsCaptchaChallenge), making the logic clearer.
Request Headers Original headers were redundant and incomplete. Simplified and used more standard browser-simulating request headers.

❓ Frequently Asked Questions (FAQ)

Q: Why do I need to handle both HTTP 202 and HTTP 405 status codes?

A: AWS WAF uses different security measures that result in different HTTP status codes:

  • HTTP 202 (Accepted): Typically indicates a WAF Challenge is required. This is a lighter security check that often involves running a JavaScript snippet.
  • HTTP 405 (Method Not Allowed): Often indicates a WAF Captcha is required, which is a more complex check that involves solving a visual or interactive puzzle, along with the challenge parameters. Our script is designed to automatically detect and handle both scenarios.

Q: Can I use this script without a proxy?

A: Yes, you can. The PROXY variable is optional. If you do not need a proxy, you can set const PROXY = ""; in the configuration. However, using a high-quality proxy is highly recommended for web scraping and automation tasks to avoid IP bans and ensure consistent access.

Q: What is the AntiAwsWafTask?

A: AntiAwsWafTask is a specialized task type provided by CapSolver designed specifically to handle the AWS WAF security mechanism. It intelligently processes the challenge parameters (including awsKey, awsIv, awsContext, and awsChallengeJS) extracted from the protected page and returns the valid aws-waf-token cookie required to bypass the protection.

📚 More Information

✅ Conclusion

This guide has demonstrated a robust and efficient method for programmatically solving AWS WAF Challenges and Captchas using Node.js and CapSolver. By implementing the modular script and leveraging CapSolver's specialized task type, you can seamlessly integrate this solution into your automation workflows. The key to success lies in correctly identifying the WAF status code (202 or 405), extracting the necessary parameters, and using the resulting aws-waf-token cookie for subsequent requests. This approach ensures your automation tasks can reliably access content protected by AWS WAF.

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