CAPSOLVER
Blog
How to Solve Captcha in Maxun with CapSolver Integration

How to Solve Captcha in Maxun with CapSolver Integration

Logo of CapSolver

Ethan Collins

Pattern Recognition Specialist

21-Jan-2026

In web data extraction, Maxun is gaining attention as an open-source, no-code platform that simplifies how teams collect data from the web. Its robot-based workflows and SDK make it possible for both developers and non-technical users to build and maintain scraping pipelines without heavy engineering effort.

That said, many real-world websites are protected by CAPTCHAs, which often become the main bottleneck during data extraction. CapSolver works well alongside Maxun by handling these challenges at the infrastructure level. With CapSolver in place, Maxun robots can continue operating on CAPTCHA-protected pages more reliably, combining ease of use with practical, production-ready scraping capabilities.


What is Maxun?

Maxun is an open-source, no-code web data extraction platform that allows users to train robots to scrape websites without writing code. It features a visual robot builder, a powerful SDK for programmatic control, and supports both cloud and self-hosted deployments.

Key Features of Maxun

  • No-Code Robot Builder: Visual interface to train extraction robots without programming
  • Powerful SDK: TypeScript/Node.js SDK for programmatic robot execution
  • Multiple Extraction Modes: Extract, Scrape, Crawl, and Search capabilities
  • Intelligent Selectors: Automatic element detection and smart selector generation
  • Cloud & Self-Hosted: Deploy on Maxun Cloud or your own infrastructure
  • Proxy Support: Built-in proxy rotation and management
  • Scheduled Runs: Automate robot execution with cron-based scheduling

Core SDK Classes

Class Description
Extract Build structured data extraction workflows with LLM or CSS selectors
Scrape Convert webpages into clean Markdown, HTML, or screenshots
Crawl Automatically discover and scrape multiple pages using sitemaps and links
Search Perform web searches and extract content from results (DuckDuckGo)

What Makes Maxun Different

Maxun bridges the gap between no-code simplicity and developer flexibility:

  • Visual + Code: Train robots visually, then control them programmatically via SDK
  • Robot-Based Architecture: Reusable, shareable extraction templates
  • TypeScript Native: Built for modern Node.js applications
  • Open Source: Full transparency and community-driven development

What is CapSolver?

CapSolver is a leading CAPTCHA solving service that provides AI-powered solutions for bypassing various CAPTCHA challenges. With support for multiple CAPTCHA types and lightning-fast response times, CapSolver integrates seamlessly into automated workflows.

Supported CAPTCHA Types

CapSolver helps automation workflows handle most of the mainstream CAPTCHA and verification challenges commonly encountered during web scraping and browser automation, including:

Why Integrate CapSolver with Maxun?

When building Maxun robots that interact with protected websitesโ€”whether for data extraction, price monitoring, or market researchโ€”CAPTCHA challenges become a significant obstacle. Here's why the integration matters:

  1. Uninterrupted Data Extraction: Robots can complete their missions without manual intervention
  2. Scalable Operations: Handle CAPTCHA challenges across multiple concurrent robot executions
  3. Seamless Workflow: Solve CAPTCHAs as part of your extraction pipeline
  4. Cost-Effective: Pay only for successfully solved CAPTCHAs
  5. High Success Rates: Industry-leading accuracy for all supported CAPTCHA types

Installation

Prerequisites

Installing Maxun SDK

bash Copy
# Install Maxun SDK
npm install maxun-sdk

# Install additional dependencies for CapSolver integration
npm install axios

Docker Installation (Self-Hosted Maxun)

bash Copy
# Clone the Maxun repository
git clone https://github.com/getmaxun/maxun.git
cd maxun

# Start with Docker Compose
docker-compose up -d

Environment Setup

Create a .env file with your configuration:

env Copy
CAPSOLVER_API_KEY=your_capsolver_api_key
MAXUN_API_KEY=your_maxun_api_key

# For Maxun Cloud (app.maxun.dev)
MAXUN_BASE_URL=https://app.maxun.dev/api/sdk

# For Self-Hosted Maxun (default)
# MAXUN_BASE_URL=http://localhost:8080/api/sdk

Note: The baseUrl configuration is required when using Maxun Cloud. Self-hosted installations default to http://localhost:8080/api/sdk.


Creating a CapSolver Service for Maxun

Here's a reusable TypeScript service that integrates CapSolver with Maxun:

Basic CapSolver Service

typescript Copy
import axios, { AxiosInstance } from 'axios';

interface TaskResult {
  gRecaptchaResponse?: string;
  token?: string;
  cookies?: Array<{ name: string; value: string }>;
  userAgent?: string;
}

interface CapSolverConfig {
  apiKey: string;
  timeout?: number;
  maxAttempts?: number;
}

class CapSolverService {
  private client: AxiosInstance;
  private apiKey: string;
  private maxAttempts: number;

  constructor(config: CapSolverConfig) {
    this.apiKey = config.apiKey;
    this.maxAttempts = config.maxAttempts || 60;

    this.client = axios.create({
      baseURL: 'https://api.capsolver.com',
      timeout: config.timeout || 30000,
      headers: { 'Content-Type': 'application/json' },
    });
  }

  private async createTask(taskData: Record<string, unknown>): Promise<string> {
    const response = await this.client.post('/createTask', {
      clientKey: this.apiKey,
      task: taskData,
    });

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

    return response.data.taskId;
  }

  private async getTaskResult(taskId: string): Promise<TaskResult> {
    for (let attempt = 0; attempt < this.maxAttempts; attempt++) {
      await this.delay(2000);

      const response = await this.client.post('/getTaskResult', {
        clientKey: this.apiKey,
        taskId,
      });

      const { status, solution, errorDescription } = response.data;

      if (status === 'ready') {
        return solution as TaskResult;
      }

      if (status === 'failed') {
        throw new Error(`Task failed: ${errorDescription}`);
      }
    }

    throw new Error('Timeout waiting for CAPTCHA solution');
  }

  private delay(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  async solveReCaptchaV2(websiteUrl: string, websiteKey: string): Promise<string> {
    const taskId = await this.createTask({
      type: 'ReCaptchaV2TaskProxyLess',
      websiteURL: websiteUrl,
      websiteKey,
    });

    const solution = await this.getTaskResult(taskId);
    return solution.gRecaptchaResponse || '';
  }

  async solveReCaptchaV3(
    websiteUrl: string,
    websiteKey: string,
    pageAction: string = 'submit'
  ): Promise<string> {
    const taskId = await this.createTask({
      type: 'ReCaptchaV3TaskProxyLess',
      websiteURL: websiteUrl,
      websiteKey,
      pageAction,
    });

    const solution = await this.getTaskResult(taskId);
    return solution.gRecaptchaResponse || '';
  }

  async solveTurnstile(
    websiteUrl: string,
    websiteKey: string,
    action?: string,
    cdata?: string
  ): Promise<string> {
    const taskData: Record<string, unknown> = {
      type: 'AntiTurnstileTaskProxyLess',
      websiteURL: websiteUrl,
      websiteKey,
    };

    // Add optional metadata
    if (action || cdata) {
      taskData.metadata = {};
      if (action) (taskData.metadata as Record<string, string>).action = action;
      if (cdata) (taskData.metadata as Record<string, string>).cdata = cdata;
    }

    const taskId = await this.createTask(taskData);
    const solution = await this.getTaskResult(taskId);
    return solution.token || '';
  }

  async checkBalance(): Promise<number> {
    const response = await this.client.post('/getBalance', {
      clientKey: this.apiKey,
    });

    return response.data.balance || 0;
  }
}

export { CapSolverService, CapSolverConfig, TaskResult };

โ˜… Insight โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
The CapSolver service uses a polling pattern (getTaskResult) because CAPTCHA solving is asynchronousโ€”the API accepts a task, processes it on their servers, and returns a result when ready. The 2-second delay between polls balances responsiveness with API rate limits.
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€


Solving Different CAPTCHA Types

reCAPTCHA v2 with Maxun

Since Maxun operates at a higher level than raw browser automation, the integration approach focuses on solving CAPTCHAs before or during robot execution:

typescript Copy
import { Extract } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const CAPSOLVER_API_KEY = process.env.CAPSOLVER_API_KEY!;
const MAXUN_API_KEY = process.env.MAXUN_API_KEY!;
const MAXUN_BASE_URL = process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk';

const capSolver = new CapSolverService({ apiKey: CAPSOLVER_API_KEY });
const extractor = new Extract({
  apiKey: MAXUN_API_KEY,
  baseUrl: MAXUN_BASE_URL,
});

async function extractWithRecaptchaV2() {
  const targetUrl = 'https://example.com/protected-page';
  const recaptchaSiteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC';

  console.log('Solving reCAPTCHA v2...');

  // Solve the CAPTCHA first
  const token = await capSolver.solveReCaptchaV2(targetUrl, recaptchaSiteKey);

  console.log('CAPTCHA solved, creating extraction robot...');

  // Create a robot using method chaining
  const robot = await extractor
    .create('Product Extractor')
    .navigate(targetUrl)
    .type('#g-recaptcha-response', token)
    .click('button[type="submit"]')
    .wait(2000)
    .captureList({ selector: '.product-item' });

  // Run the robot
  const result = await robot.run({ timeout: 30000 });

  console.log('Extraction complete:', result.data);
  return result.data;
}

extractWithRecaptchaV2().catch(console.error);

reCAPTCHA v3 with Maxun

typescript Copy
import { Extract } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const CAPSOLVER_API_KEY = process.env.CAPSOLVER_API_KEY!;
const MAXUN_API_KEY = process.env.MAXUN_API_KEY!;
const MAXUN_BASE_URL = process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk';

const capSolver = new CapSolverService({ apiKey: CAPSOLVER_API_KEY });
const extractor = new Extract({
  apiKey: MAXUN_API_KEY,
  baseUrl: MAXUN_BASE_URL,
});

async function extractWithRecaptchaV3() {
  const targetUrl = 'https://example.com/v3-protected';
  const recaptchaSiteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDEF';

  console.log('Solving reCAPTCHA v3 with high score...');

  // Solve with custom page action
  const token = await capSolver.solveReCaptchaV3(
    targetUrl,
    recaptchaSiteKey,
    'submit'  // pageAction
  );

  console.log('Token obtained with high score, creating robot...');

  // Create extraction robot using method chaining
  const robot = await extractor
    .create('V3 Protected Extractor')
    .navigate(targetUrl)
    .type('input[name="g-recaptcha-response"]', token)
    .click('#submit-btn')
    .wait(2000)
    .captureText({ resultData: '.result-data' });

  const result = await robot.run({ timeout: 30000 });

  console.log('Data extracted:', result.data);
  return result.data;
}

extractWithRecaptchaV3().catch(console.error);

Cloudflare Turnstile with Maxun

typescript Copy
import { Scrape } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const CAPSOLVER_API_KEY = process.env.CAPSOLVER_API_KEY!;
const MAXUN_API_KEY = process.env.MAXUN_API_KEY!;
const MAXUN_BASE_URL = process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk';

const capSolver = new CapSolverService({ apiKey: CAPSOLVER_API_KEY });
const scraper = new Scrape({
  apiKey: MAXUN_API_KEY,
  baseUrl: MAXUN_BASE_URL,
});

async function extractWithTurnstile() {
  const targetUrl = 'https://example.com/turnstile-protected';
  const turnstileSiteKey = '0x4xxxxxxxxxxxxxxxxxxxxxxxxxxxxGHI';

  console.log('Solving Cloudflare Turnstile...');

  // Solve with optional metadata (action and cdata)
  const token = await capSolver.solveTurnstile(
    targetUrl,
    turnstileSiteKey,
    'login',                              // optional action
    '0000-1111-2222-3333-example-cdata'  // optional cdata
  );

  console.log('Turnstile solved, creating scrape robot...');

  // Create a scrape robot - for Turnstile, we typically need to
  // submit the token via a POST request first, then scrape
  const robot = await scraper.create('turnstile-scraper', targetUrl, {
    formats: ['markdown', 'html'],
  });

  const result = await robot.run({ timeout: 30000 });

  console.log('Extraction complete');
  console.log('Markdown:', result.data.markdown?.substring(0, 500));
  return result.data;
}

extractWithTurnstile().catch(console.error);

Integration with Maxun Workflows

Using with Extract Class

The Extract class is used for pulling structured data from specific page elements. It supports both LLM-powered extraction (using natural language prompts) and non-LLM extraction (using CSS selectors):

typescript Copy
import { Extract } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const extractor = new Extract({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface ProductData {
  name: string;
  price: string;
  rating: string;
}

async function extractProductsWithCaptcha(): Promise<ProductData[]> {
  const targetUrl = 'https://example.com/products';
  const siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC';

  // Pre-solve CAPTCHA
  const captchaToken = await capSolver.solveReCaptchaV2(targetUrl, siteKey);

  console.log('CAPTCHA solved, creating extraction robot...');

  // Create extraction robot using method chaining
  const robot = await extractor
    .create('Product Extractor')
    .navigate(targetUrl)
    .type('#g-recaptcha-response', captchaToken)
    .click('button[type="submit"]')
    .wait(3000)
    .captureList({
      selector: '.product-card',
      pagination: { type: 'clickNext', selector: '.next-page' },
      maxItems: 50,
    });

  // Run the extraction
  const result = await robot.run({ timeout: 60000 });

  return result.data.listData as ProductData[];
}

extractProductsWithCaptcha()
  .then((products) => {
    products.forEach((product) => {
      console.log(`${product.name}: ${product.price}`);
    });
  })
  .catch(console.error);

โ˜… Insight โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
The captureList method in Maxun's Extract class automatically detects fields within list items and handles pagination. When you specify a pagination type (scrollDown, clickNext, or clickLoadMore), the robot will continue extracting until it reaches your limit or runs out of pages.
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

Using with Scrape Class

The Scrape class converts webpages into clean HTML, LLM-ready Markdown, or screenshots:

typescript Copy
import { Scrape } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';
import axios from 'axios';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const scraper = new Scrape({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface ScrapeResult {
  url: string;
  markdown?: string;
  html?: string;
  captchaSolved: boolean;
}

async function scrapeWithCaptchaHandling(): Promise<ScrapeResult[]> {
  const urls = [
    'https://example.com/page1',
    'https://example.com/page2',
    'https://example.com/page3',
  ];

  const results: ScrapeResult[] = [];

  for (const url of urls) {
    try {
      // For CAPTCHA-protected pages, solve first and establish session
      const siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC'; // Get dynamically if needed

      console.log(`Solving CAPTCHA for ${url}...`);
      const captchaToken = await capSolver.solveReCaptchaV2(url, siteKey);

      // Submit CAPTCHA to get session cookies
      const verifyResponse = await axios.post(`${url}/verify`, {
        'g-recaptcha-response': captchaToken,
      });

      // Create scrape robot for the authenticated page
      const robot = await scraper.create(`scraper-${Date.now()}`, url, {
        formats: ['markdown', 'html'],
      });

      const result = await robot.run({ timeout: 30000 });

      results.push({
        url,
        markdown: result.data.markdown,
        html: result.data.html,
        captchaSolved: true,
      });

      // Clean up - delete robot after use
      await robot.delete();

    } catch (error) {
      console.error(`Failed to scrape ${url}:`, error);
      results.push({ url, captchaSolved: false });
    }
  }

  return results;
}

scrapeWithCaptchaHandling().then(console.log).catch(console.error);

Using with Crawl Class

The Crawl class automatically discovers and scrapes multiple pages using sitemaps and link following:

typescript Copy
import { Crawl } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';
import axios from 'axios';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const crawler = new Crawl({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface PageResult {
  url: string;
  title: string;
  text: string;
  wordCount: number;
}

async function crawlWithCaptchaProtection(): Promise<PageResult[]> {
  const startUrl = 'https://example.com';
  const siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC';

  // Pre-solve CAPTCHA for the domain
  console.log('Solving CAPTCHA for domain access...');
  const captchaToken = await capSolver.solveReCaptchaV2(startUrl, siteKey);

  // Submit CAPTCHA to establish session (site-specific)
  await axios.post(`${startUrl}/verify`, {
    'g-recaptcha-response': captchaToken,
  });

  // Create crawl robot with domain-scoped configuration
  const robot = await crawler.create('site-crawler', startUrl, {
    mode: 'domain',           // Crawl scope: 'domain', 'subdomain', or 'path'
    limit: 50,                // Maximum pages to crawl
    maxDepth: 3,              // How deep to follow links
    useSitemap: true,         // Parse sitemap.xml for URLs
    followLinks: true,        // Extract and follow page links
    includePaths: ['/blog/', '/docs/'],  // Regex patterns to include
    excludePaths: ['/admin/', '/login/'], // Regex patterns to exclude
    respectRobots: true,      // Honor robots.txt
  });

  // Execute the crawl
  const result = await robot.run({ timeout: 120000 });

  // Each page in result contains: metadata, html, text, wordCount, links
  return result.data.crawlData.map((page: any) => ({
    url: page.metadata.url,
    title: page.metadata.title,
    text: page.text,
    wordCount: page.wordCount,
  }));
}

crawlWithCaptchaProtection()
  .then((pages) => {
    console.log(`Crawled ${pages.length} pages`);
    pages.forEach((page) => {
      console.log(`- ${page.title}: ${page.url} (${page.wordCount} words)`);
    });
  })
  .catch(console.error);

Pre-Authentication Pattern

For sites that require CAPTCHA before accessing content, use a pre-authentication workflow:

typescript Copy
import axios from 'axios';
import { Extract } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const extractor = new Extract({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface SessionCookies {
  name: string;
  value: string;
  domain: string;
}

async function preAuthenticateWithCaptcha(
  loginUrl: string,
  siteKey: string
): Promise<SessionCookies[]> {
  // Step 1: Solve the CAPTCHA
  const captchaToken = await capSolver.solveReCaptchaV2(loginUrl, siteKey);

  // Step 2: Submit the CAPTCHA token to get session cookies
  const response = await axios.post(
    loginUrl,
    {
      'g-recaptcha-response': captchaToken,
    },
    {
      withCredentials: true,
      maxRedirects: 0,
      validateStatus: (status) => status < 400,
    }
  );

  // Step 3: Extract cookies from response
  const setCookies = response.headers['set-cookie'] || [];
  const cookies: SessionCookies[] = setCookies.map((cookie: string) => {
    const [nameValue] = cookie.split(';');
    const [name, value] = nameValue.split('=');
    return {
      name: name.trim(),
      value: value.trim(),
      domain: new URL(loginUrl).hostname,
    };
  });

  return cookies;
}

async function extractWithPreAuth() {
  const loginUrl = 'https://example.com/verify';
  const targetUrl = 'https://example.com/protected-data';
  const siteKey = '6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC';

  // Pre-authenticate to get session cookies
  const sessionCookies = await preAuthenticateWithCaptcha(loginUrl, siteKey);

  console.log('Session established, creating extraction robot...');

  // Create extraction robot using method chaining
  // Note: Use setCookies() to pass authenticated session cookies
  const robot = await extractor
    .create('Authenticated Extractor')
    .setCookies(sessionCookies)
    .navigate(targetUrl)
    .wait(2000)
    .captureText({ content: '.protected-content' });

  // Run the extraction
  const result = await robot.run({ timeout: 30000 });

  return result.data;
}

extractWithPreAuth().then(console.log).catch(console.error);

โ˜… Insight โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
The pre-authentication pattern separates CAPTCHA solving from data extraction. This is particularly useful for Maxun because it operates at a higher abstraction levelโ€”instead of injecting tokens into the DOM, you establish an authenticated session first, then let Maxun's robots work within that session.
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€


Parallel Robot Execution with CAPTCHA Handling

Handle CAPTCHAs across multiple concurrent robot executions:

typescript Copy
import { Scrape } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

const capSolver = new CapSolverService({ apiKey: process.env.CAPSOLVER_API_KEY! });
const scraper = new Scrape({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: process.env.MAXUN_BASE_URL || 'https://app.maxun.dev/api/sdk',
});

interface ExtractionJob {
  url: string;
  siteKey?: string;
}

interface ExtractionResult {
  url: string;
  data: { markdown?: string; html?: string };
  captchaSolved: boolean;
  duration: number;
}

async function processJob(job: ExtractionJob): Promise<ExtractionResult> {
  const startTime = Date.now();

  let captchaSolved = false;

  // Solve CAPTCHA if site key is provided
  if (job.siteKey) {
    console.log(`Solving CAPTCHA for ${job.url}...`);
    const token = await capSolver.solveReCaptchaV2(job.url, job.siteKey);
    captchaSolved = true;
    // Token would be submitted to establish session before scraping
  }

  // Create and run a scrape robot
  const robot = await scraper.create(`scraper-${Date.now()}`, job.url, {
    formats: ['markdown', 'html'],
  });

  const result = await robot.run({ timeout: 30000 });

  // Clean up robot after use
  await robot.delete();

  return {
    url: job.url,
    data: {
      markdown: result.data.markdown,
      html: result.data.html,
    },
    captchaSolved,
    duration: Date.now() - startTime,
  };
}

async function runParallelExtractions(
  jobs: ExtractionJob[],
  concurrency: number = 5
): Promise<ExtractionResult[]> {
  const results: ExtractionResult[] = [];
  const chunks: ExtractionJob[][] = [];

  // Split jobs into chunks for controlled concurrency
  for (let i = 0; i < jobs.length; i += concurrency) {
    chunks.push(jobs.slice(i, i + concurrency));
  }

  for (const chunk of chunks) {
    const chunkResults = await Promise.all(chunk.map(processJob));
    results.push(...chunkResults);
  }

  return results;
}

// Example usage
const jobs: ExtractionJob[] = [
  { url: 'https://site1.com/data', siteKey: '6Lc...' },
  { url: 'https://site2.com/data' },
  { url: 'https://site3.com/data', siteKey: '6Lc...' },
  // ... more jobs
];

runParallelExtractions(jobs, 5)
  .then((results) => {
    const solved = results.filter((r) => r.captchaSolved).length;
    console.log(`Completed ${results.length} extractions, solved ${solved} CAPTCHAs`);

    results.forEach((r) => {
      console.log(`${r.url}: ${r.duration}ms`);
    });
  })
  .catch(console.error);

Best Practices

1. Error Handling with Retries

typescript Copy
async function solveWithRetry<T>(
  solverFn: () => Promise<T>,
  maxRetries: number = 3
): Promise<T> {
  let lastError: Error | undefined;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await solverFn();
    } catch (error) {
      lastError = error as Error;
      console.warn(`Attempt ${attempt + 1} failed: ${lastError.message}`);

      // Exponential backoff
      await new Promise((resolve) =>
        setTimeout(resolve, Math.pow(2, attempt) * 1000)
      );
    }
  }

  throw new Error(`Max retries exceeded: ${lastError?.message}`);
}

// Usage
const token = await solveWithRetry(() =>
  capSolver.solveReCaptchaV2(url, siteKey)
);

2. Balance Management

typescript Copy
async function ensureSufficientBalance(minBalance: number = 1.0): Promise<void> {
  const balance = await capSolver.checkBalance();

  if (balance < minBalance) {
    throw new Error(
      `Insufficient CapSolver balance: $${balance.toFixed(2)}. Please recharge.`
    );
  }

  console.log(`CapSolver balance: $${balance.toFixed(2)}`);
}

// Check balance before starting extraction jobs
await ensureSufficientBalance(5.0);

3. Token Caching

typescript Copy
interface CachedToken {
  token: string;
  timestamp: number;
}

class TokenCache {
  private cache = new Map<string, CachedToken>();
  private ttlMs: number;

  constructor(ttlSeconds: number = 90) {
    this.ttlMs = ttlSeconds * 1000;
  }

  private getKey(domain: string, siteKey: string): string {
    return `${domain}:${siteKey}`;
  }

  get(domain: string, siteKey: string): string | null {
    const key = this.getKey(domain, siteKey);
    const cached = this.cache.get(key);

    if (!cached) return null;

    if (Date.now() - cached.timestamp > this.ttlMs) {
      this.cache.delete(key);
      return null;
    }

    return cached.token;
  }

  set(domain: string, siteKey: string, token: string): void {
    const key = this.getKey(domain, siteKey);
    this.cache.set(key, { token, timestamp: Date.now() });
  }
}

const tokenCache = new TokenCache(90);

async function getCachedOrSolve(
  url: string,
  siteKey: string
): Promise<string> {
  const domain = new URL(url).hostname;

  const cached = tokenCache.get(domain, siteKey);
  if (cached) {
    console.log('Using cached token');
    return cached;
  }

  const token = await capSolver.solveReCaptchaV2(url, siteKey);
  tokenCache.set(domain, siteKey, token);

  return token;
}

Configuration Options

Maxun supports configuration through environment variables and SDK options:

Setting Description Default
MAXUN_API_KEY Your Maxun API key -
MAXUN_BASE_URL Maxun API base URL http://localhost:8080/api/sdk (self-hosted) or https://app.maxun.dev/api/sdk (cloud)
CAPSOLVER_API_KEY Your CapSolver API key -
CAPSOLVER_TIMEOUT Request timeout in ms 30000
CAPSOLVER_MAX_ATTEMPTS Max polling attempts 60

SDK Configuration

typescript Copy
import { Extract, Scrape, Crawl, Search } from 'maxun-sdk';
import { CapSolverService } from './capsolver-service';

// For Maxun Cloud (app.maxun.dev)
const MAXUN_BASE_URL = 'https://app.maxun.dev/api/sdk';

// For self-hosted Maxun (default)
// const MAXUN_BASE_URL = 'http://localhost:8080/api/sdk';

// Configure Maxun SDK modules
const extractor = new Extract({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: MAXUN_BASE_URL,
});
const scraper = new Scrape({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: MAXUN_BASE_URL,
});
const crawler = new Crawl({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: MAXUN_BASE_URL,
});
const searcher = new Search({
  apiKey: process.env.MAXUN_API_KEY!,
  baseUrl: MAXUN_BASE_URL,
});

// Configure CapSolver
const capSolver = new CapSolverService({
  apiKey: process.env.CAPSOLVER_API_KEY!,
  timeout: 30000,
  maxAttempts: 60,
});

Conclusion

Integrating CapSolver with Maxun creates a powerful combination for web data extraction at scale. While Maxun's robot-based architecture abstracts away low-level browser automation, CapSolver provides the essential capability to bypass CAPTCHA challenges that would otherwise block your extraction workflows.

The key to successful integration is understanding that Maxun operates at a higher abstraction level than traditional browser automation tools. Instead of direct DOM manipulation for CAPTCHA token injection, the integration focuses on:

  1. Pre-authentication: Solve CAPTCHAs before robot execution to establish sessions
  2. Cookie-based bypass: Pass solved tokens and cookies to Maxun robots
  3. Parallel processing: Handle CAPTCHAs across concurrent extractions efficiently

Whether you're building price monitoring systems, market research pipelines, or data aggregation platforms, the Maxun + CapSolver combination provides the reliability and scalability needed for production environments.


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


FAQ

What is Maxun?

Maxun is an open-source, no-code web data extraction platform that enables users to train robots to scrape websites without writing code. It features a visual robot builder, a powerful TypeScript/Node.js SDK, and supports both cloud and self-hosted deployments.

How does CapSolver integrate with Maxun?

CapSolver integrates with Maxun through a pre-authentication pattern. You solve CAPTCHAs via CapSolver's API before running Maxun robots, then pass the resulting tokens or session cookies to your extraction workflows. This approach works well with Maxun's higher-level abstraction.

What types of CAPTCHAs can CapSolver solve?

CapSolver supports a wide range of CAPTCHA types including reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile, Cloudflare Challenge (5s), AWS WAF, GeeTest v3/v4, and many more.

How much does CapSolver cost?

CapSolver offers competitive pricing based on the type and volume of CAPTCHAs solved. Visit capsolver.com for current pricing details. Use code MAXUN for a 6% bonus on your first recharge.

What programming languages does Maxun support?

Maxun's SDK is built in TypeScript and runs on Node.js 18+. It provides a modern, type-safe API for programmatic robot control and can be integrated into any Node.js application.

Is Maxun free to use?

Maxun is open-source and free to self-host. Maxun also offers a cloud service with additional features and managed infrastructure. Check their pricing page for details.

How do I find the CAPTCHA site key?

The site key is typically found in the page's HTML source. Look for:

  • reCAPTCHA: data-sitekey attribute on .g-recaptcha element
  • Turnstile: data-sitekey attribute on .cf-turnstile element
  • Or check network requests for the key in API calls

Can Maxun handle authenticated sessions?

Yes, Maxun supports cookies and custom headers in robot configurations. You can pass session cookies obtained from CAPTCHA solving to authenticate your extraction robots.

What's the difference between Maxun and Playwright/Puppeteer?

Maxun operates at a higher abstraction level. While Playwright and Puppeteer provide low-level browser control, Maxun focuses on reusable robot-based workflows that can be created visually or programmatically. This makes it easier to build and maintain extraction pipelines at scale.

More Integration Guide to read:
Playwright & Puppeteer

How do I handle CAPTCHAs that appear mid-extraction?

For CAPTCHAs that appear during extraction (not on initial page load), you may need to implement a detection mechanism in your robot workflow and trigger CAPTCHA solving when detected. Consider using Maxun's webhook or callback features to pause and resume extraction.

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

Top 10 No-Code Scrapers to Use in 2026
Top 10 No-Code Scrapers to Use in 2026

A curated list of the best no-code web scraping tools to use in 2026. Compare AI-powered scrapers, visual point-and-click platforms, pricing, pros and cons, and real-world use cases.

web scraping
Logo of CapSolver

Lucas Mitchell

21-Jan-2026

Maxun with CapSolver Integration
How to Solve Captcha in Maxun with CapSolver Integration

A practical guide to integrating CapSolver with Maxun for real-world web scraping. Learn how to handle reCAPTCHA, Cloudflare Turnstile, and CAPTCHA-protected sites using pre-auth and robot workflows.

web scraping
Logo of CapSolver

Ethan Collins

21-Jan-2026

Browser4 with CapSolver Integration
How to Solve Captcha in Browser4 with CapSolver Integration

High-throughput Browser4 automation combined with CapSolver for handling CAPTCHA challenges in large-scale web data extraction.

web scraping
Logo of CapSolver

Lucas Mitchell

21-Jan-2026

What Is A Scraping Bot and How to Build One
What Is A Scraping Bot and How to Build One

Learn what is a scraping bot and how to build one for automated data extraction. Discover top tools, security navigation techniques, and ethical scraping practices.

web scraping
Logo of CapSolver

Emma Foster

15-Jan-2026

Agno with CapSolver Integration
How to Solve Captcha in Agno with CapSolver Integration

Learn how to integrate CapSolver with Agno to solve reCAPTCHA v2/v3, Cloudflare Turnstile, and WAF challenges in autonomous AI agents. Includes real Python examples for web scraping and automation.

web scraping
Logo of CapSolver

Lucas Mitchell

13-Jan-2026

How to Solve Captcha with Katana Using CapSolver
Integrating Katana with CapSolver: Automated CAPTCHA Solving for Web Crawling

Learn how to integrate Katana with Capsolver to automatically solve reCAPTCHA v2 and Cloudflare Turnstile in headless crawling.

web scraping
Logo of CapSolver

Lucas Mitchell

09-Jan-2026