API Tutorials

Node.js Promise.allSettled for Batch CAPTCHA Solving

Promise.all rejects on the first failure — if one CAPTCHA out of fifty fails, you lose all pending results. Promise.allSettled waits for every promise to complete, giving you every success and every failure. For batch CAPTCHA solving, this is the right tool.

Promise.all vs Promise.allSettled

// Promise.all — REJECTS if ANY task fails
const results = await Promise.all(tasks.map(solve)); // Throws on first error

// Promise.allSettled — RESOLVES always, with status for each
const results = await Promise.allSettled(tasks.map(solve));
// [{status: "fulfilled", value: "..."}, {status: "rejected", reason: Error}]
Method On first failure Returns Best for
Promise.all Rejects immediately Nothing (throws) All-or-nothing operations
Promise.allSettled Continues Every result Batch CAPTCHA solving

Core Implementation

const axios = require("axios");

const API_KEY = process.env.CAPTCHAAI_API_KEY;

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function solveCaptcha(sitekey, pageurl) {
  // Submit
  const submitResp = await axios.post(
    "https://ocr.captchaai.com/in.php",
    null,
    {
      params: {
        key: API_KEY,
        method: "userrecaptcha",
        googlekey: sitekey,
        pageurl: pageurl,
        json: 1,
      },
    }
  );

  if (submitResp.data.status !== 1) {
    throw new Error(submitResp.data.request);
  }

  const captchaId = submitResp.data.request;

  // Poll
  for (let i = 0; i < 60; i++) {
    await sleep(5000);
    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
    });

    if (result.data.status === 1) return result.data.request;
    if (result.data.request !== "CAPCHA_NOT_READY") {
      throw new Error(result.data.request);
    }
  }

  throw new Error("TIMEOUT");
}

async function batchSolve(tasks) {
  const promises = tasks.map((task) =>
    solveCaptcha(task.sitekey, task.pageurl).then((solution) => ({
      ...task,
      solution,
    }))
  );

  const results = await Promise.allSettled(promises);

  const solved = [];
  const failed = [];

  for (let i = 0; i < results.length; i++) {
    if (results[i].status === "fulfilled") {
      solved.push(results[i].value);
    } else {
      failed.push({
        task: tasks[i],
        error: results[i].reason.message,
      });
    }
  }

  return { solved, failed };
}

// Usage
(async () => {
  const tasks = [
    {
      sitekey: "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
      pageurl: "https://example.com/page/1",
    },
    {
      sitekey: "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
      pageurl: "https://example.com/page/2",
    },
    {
      sitekey: "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
      pageurl: "https://example.com/page/3",
    },
  ];

  const { solved, failed } = await batchSolve(tasks);
  console.log(`Solved: ${solved.length}, Failed: ${failed.length}`);

  for (const s of solved) {
    console.log(`  ✓ ${s.pageurl}: ${s.solution.substring(0, 30)}...`);
  }
  for (const f of failed) {
    console.log(`  ✗ ${f.task.pageurl}: ${f.error}`);
  }
})();

Controlling Concurrency

Sending 1,000 CAPTCHAs simultaneously overwhelms connections. Use a concurrency limiter:

async function batchSolveWithLimit(tasks, concurrency = 10) {
  const results = [];
  let index = 0;

  async function worker() {
    while (index < tasks.length) {
      const i = index++;
      const task = tasks[i];

      try {
        const solution = await solveCaptcha(task.sitekey, task.pageurl);
        results[i] = { status: "fulfilled", value: { ...task, solution } };
      } catch (err) {
        results[i] = { status: "rejected", reason: err };
      }
    }
  }

  // Launch concurrent workers
  const workers = Array.from({ length: concurrency }, () => worker());
  await Promise.allSettled(workers);

  const solved = results
    .filter((r) => r.status === "fulfilled")
    .map((r) => r.value);
  const failed = results
    .filter((r) => r.status === "rejected")
    .map((r, i) => ({ task: tasks[i], error: r.reason.message }));

  return { solved, failed };
}

// Solve 100 CAPTCHAs, 10 at a time
const { solved, failed } = await batchSolveWithLimit(tasks, 10);

Retry Failed Tasks

Re-submit failed CAPTCHAs automatically:

async function batchSolveWithRetry(tasks, maxRetries = 2, concurrency = 10) {
  let currentTasks = [...tasks];
  let allSolved = [];

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    if (currentTasks.length === 0) break;

    console.log(
      `Attempt ${attempt + 1}: solving ${currentTasks.length} tasks...`
    );

    const { solved, failed } = await batchSolveWithLimit(
      currentTasks,
      concurrency
    );

    allSolved = [...allSolved, ...solved];

    // Only retry transient errors
    const retryable = failed.filter(
      (f) =>
        f.error === "TIMEOUT" ||
        f.error === "ERROR_NO_SLOT_AVAILABLE" ||
        f.error === "ERROR_TOO_MUCH_REQUESTS"
    );

    currentTasks = retryable.map((f) => f.task);

    if (retryable.length > 0) {
      console.log(`  Retrying ${retryable.length} failed tasks...`);
    }
  }

  const finalFailed = currentTasks; // Anything left after all retries
  return { solved: allSolved, failed: finalFailed };
}

Progress Tracking

Report real-time progress during batch operations:

async function batchSolveWithProgress(tasks, concurrency = 10) {
  let completed = 0;
  let succeeded = 0;
  let failed = 0;

  const wrapped = tasks.map((task) =>
    solveCaptcha(task.sitekey, task.pageurl)
      .then((solution) => {
        succeeded++;
        completed++;
        process.stdout.write(
          `\rProgress: ${completed}/${tasks.length} (${succeeded} ok, ${failed} err)`
        );
        return { ...task, solution };
      })
      .catch((err) => {
        failed++;
        completed++;
        process.stdout.write(
          `\rProgress: ${completed}/${tasks.length} (${succeeded} ok, ${failed} err)`
        );
        throw err;
      })
  );

  const results = await Promise.allSettled(wrapped);
  console.log("\nDone.");
  return results;
}

Structured Result Processing

Parse Promise.allSettled results into actionable categories:

function categorizeResults(settled, originalTasks) {
  const categories = {
    solved: [],
    transientErrors: [],
    permanentErrors: [],
  };

  const TRANSIENT = new Set([
    "TIMEOUT",
    "ERROR_NO_SLOT_AVAILABLE",
    "ERROR_TOO_MUCH_REQUESTS",
  ]);

  for (let i = 0; i < settled.length; i++) {
    const r = settled[i];
    if (r.status === "fulfilled") {
      categories.solved.push(r.value);
    } else {
      const error = r.reason.message;
      const entry = { task: originalTasks[i], error };

      if (TRANSIENT.has(error)) {
        categories.transientErrors.push(entry);
      } else {
        categories.permanentErrors.push(entry);
      }
    }
  }

  return categories;
}

Troubleshooting

Issue Cause Fix
All tasks timeout Too many concurrent requests overwhelming CaptchaAI or proxy Reduce concurrency to 5-10
ERR_SOCKET_EXHAUSTION Too many simultaneous HTTP connections Use http.Agent with maxSockets limit
Results array out of order Async completion order differs from submission Use index-based result storage (shown above)
Memory growing during large batches Holding all promises in memory Process in chunks of 100-500

FAQ

What concurrency level should I use?

Start with 10 concurrent tasks. Increase until you see diminishing returns or error rates climb. Most setups perform well at 10–50 concurrent solves.

Should I use Promise.allSettled for small batches (< 5)?

For small batches, the difference between Promise.all and Promise.allSettled is negligible. Use Promise.allSettled anyway — it's a good habit that prevents data loss from partial failures.

How does this compare to async generators or streams?

Promise.allSettled is batch-oriented — you submit everything and wait. For continuous task streams (e.g., scraping pages endlessly), use an async generator or worker pool with a queue.

Next Steps

Solve CAPTCHAs in parallel — get your CaptchaAI API key and launch batch operations.

Related guides:

Full Working Code

Complete runnable examples for this article in Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin & Bash.

View on GitHub →

Discussions (0)

No comments yet.

Related Posts

Tutorials Building a CAPTCHA Solving Queue in Node.js
Build a production CAPTCHA solving queue in Node.js.

Build a production CAPTCHA solving queue in Node.js. Promise-based concurrency, p-queue, Event Emitter pattern...

Automation All CAPTCHA Types DevOps
Mar 24, 2026
Tutorials Node.js CAPTCHA Solving with Retry and Error Handling
Build robust CAPTCHA solving in Node.js with retry logic, exponential backoff, circuit breakers, and proper error classification for Captcha AI.

Build robust CAPTCHA solving in Node.js with retry logic, exponential backoff, circuit breakers, and proper er...

Automation All CAPTCHA Types Node.js
Apr 04, 2026
API Tutorials Building a Node.js SDK for CaptchaAI API
Build a production-ready Node.js SDK for the Captcha AI API — typed methods for each CAPTCHA type, promise-based polling, configurable timeouts, and proper erro...

Build a production-ready Node.js SDK for the Captcha AI API — typed methods for each CAPTCHA type, promise-bas...

Automation All CAPTCHA Types Node.js
Mar 11, 2026
Tutorials Building a CAPTCHA Solve Event Bus with Node.js and CaptchaAI
Build an in-process event bus in Node.js for CAPTCHA solve lifecycle events — submit, pending, solved, failed — with Captcha AI integration.

Build an in-process event bus in Node.js for CAPTCHA solve lifecycle events — submit, pending, solved, failed...

Automation Python All CAPTCHA Types
Feb 25, 2026
Comparisons Best CAPTCHA Solving Services Compared (2025)
Compare the top CAPTCHA solving APIs — Captcha AI, 2 Captcha, Anti-Captcha, Cap Solver, and — on pricing, speed, type support, and developer experience.

Compare the top CAPTCHA solving APIs — Captcha AI, 2 Captcha, Anti-Captcha, Cap Solver, and more — on pricing,...

Automation All CAPTCHA Types
Jan 26, 2026
API Tutorials Solve reCAPTCHA Invisible with Node.js and CaptchaAI
Step-by-step Node.js tutorial for solving invisible re CAPTCHA v 2 using the Captcha AI API.

Step-by-step Node.js tutorial for solving invisible re CAPTCHA v 2 using the Captcha AI API. Includes site key...

Automation Node.js reCAPTCHA Invisible
Jan 11, 2026
Tutorials Discord Webhook Alerts for CAPTCHA Pipeline Status
Send CAPTCHA pipeline alerts to Discord — webhook integration for balance warnings, error spikes, queue status, and daily summary reports with Captcha AI.

Send CAPTCHA pipeline alerts to Discord — webhook integration for balance warnings, error spikes, queue status...

Automation Python All CAPTCHA Types
Apr 09, 2026
DevOps & Scaling Ansible Playbooks for CaptchaAI Worker Deployment
Deploy and manage Captcha AI workers with Ansible — playbooks for provisioning, configuration, rolling updates, and health checks across your server fleet.

Deploy and manage Captcha AI workers with Ansible — playbooks for provisioning, configuration, rolling updates...

Automation Python All CAPTCHA Types
Apr 07, 2026
DevOps & Scaling Google Cloud Functions + CaptchaAI Integration
Deploy Captcha AI on Google Cloud Functions.

Deploy Captcha AI on Google Cloud Functions. HTTP-triggered solving, Secret Manager integration, Pub/Sub batch...

Automation Python All CAPTCHA Types
Jan 18, 2026
Integrations Axios + CaptchaAI: Solve CAPTCHAs Without a Browser
Use Axios and Captcha AI to solve re CAPTCHA, Turnstile, and image CAPTCHAs in Node.js without launching a browser.

Use Axios and Captcha AI to solve re CAPTCHA, Turnstile, and image CAPTCHAs in Node.js without launching a bro...

Automation All CAPTCHA Types
Apr 08, 2026
API Tutorials How to Solve reCAPTCHA v2 Enterprise Using API
Step-by-step guide to solving re CAPTCHA v 2 Enterprise using Captcha AI API.

Step-by-step guide to solving re CAPTCHA v 2 Enterprise using Captcha AI API. Detect Enterprise vs standard, e...

Automation reCAPTCHA v2 reCAPTCHA Enterprise
Jan 26, 2026
API Tutorials Case-Sensitive CAPTCHA API Parameter Guide
How to use the regsense parameter for case-sensitive CAPTCHA solving with Captcha AI.

How to use the regsense parameter for case-sensitive CAPTCHA solving with Captcha AI. Covers when to use, comm...

Python Web Scraping Image OCR
Apr 09, 2026
API Tutorials reCAPTCHA Data-S Parameter Explained
Understand the re CAPTCHA data-s parameter: what it is, when it appears, why it matters for solving, and how to extract and include it in API solver requests.

Understand the re CAPTCHA data-s parameter: what it is, when it appears, why it matters for solving, and how t...

Automation reCAPTCHA v2
Jan 23, 2026