Tutorials

Solve CAPTCHAs with Java Using CaptchaAI

This tutorial shows how to integrate CaptchaAI into Java applications using java.net.http.HttpClient (Java 11+). No third-party dependencies required.

Requirements

Requirement Details
Java 11+ (HttpClient API)
Dependencies None (standard library)
CaptchaAI API key Get one here

CaptchaAI Client Class

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Map;
import java.util.stream.Collectors;

public class CaptchaAI {

    private final String apiKey;
    private final String baseUrl = "https://ocr.captchaai.com";
    private final HttpClient httpClient;

    public CaptchaAI(String apiKey) {
        this.apiKey = apiKey;
        this.httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(30))
                .build();
    }

    /**

     * Submit a CAPTCHA task and return the task ID.
     */
    public String submit(Map<String, String> params) throws Exception {
        params.put("key", apiKey);
        String query = buildQuery(params);
        String url = baseUrl + "/in.php?" + query;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        HttpResponse<String> response = httpClient.send(
                request, HttpResponse.BodyHandlers.ofString());
        String body = response.body();

        if (!body.startsWith("OK|")) {
            throw new RuntimeException("Submit failed: " + body);
        }

        return body.split("\\|", 2)[1];
    }

    /**

     * Poll for the result with a timeout in seconds.
     */
    public String poll(String taskId, int timeoutSeconds) throws Exception {
        long deadline = System.currentTimeMillis() + (timeoutSeconds * 1000L);
        String query = buildQuery(Map.of(
                "key", apiKey,
                "action", "get",
                "id", taskId
        ));
        String url = baseUrl + "/res.php?" + query;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        while (System.currentTimeMillis() < deadline) {
            Thread.sleep(5000);

            HttpResponse<String> response = httpClient.send(
                    request, HttpResponse.BodyHandlers.ofString());
            String body = response.body();

            if ("CAPCHA_NOT_READY".equals(body)) {
                continue;
            }

            if (body.startsWith("OK|")) {
                return body.split("\\|", 2)[1];
            }

            throw new RuntimeException("Solve failed: " + body);
        }

        throw new RuntimeException("Timeout after " + timeoutSeconds
                + "s for task " + taskId);
    }

    /**

     * Submit and poll in one call.
     */
    public String solve(Map<String, String> params) throws Exception {
        String taskId = submit(params);
        return poll(taskId, 300);
    }

    /**

     * Check account balance.
     */
    public double getBalance() throws Exception {
        String query = buildQuery(Map.of(
                "key", apiKey,
                "action", "getbalance"
        ));
        String url = baseUrl + "/res.php?" + query;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        HttpResponse<String> response = httpClient.send(
                request, HttpResponse.BodyHandlers.ofString());

        return Double.parseDouble(response.body());
    }

    private String buildQuery(Map<String, String> params) {
        return params.entrySet().stream()
                .map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8)
                        + "="
                        + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));
    }
}

Solve reCAPTCHA v2

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws Exception {
        CaptchaAI solver = new CaptchaAI(System.getenv("CAPTCHAAI_API_KEY"));

        Map<String, String> params = new HashMap<>();
        params.put("method", "userrecaptcha");
        params.put("googlekey", "6Le-wvkS...");
        params.put("pageurl", "https://example.com");

        String token = solver.solve(params);
        System.out.println("Token: " + token);
    }
}

Solve reCAPTCHA v3

Map<String, String> params = new HashMap<>();
params.put("method", "userrecaptcha");
params.put("googlekey", "6Le-wvkS...");
params.put("pageurl", "https://example.com");
params.put("version", "v3");
params.put("action", "login");

String token = solver.solve(params);

Solve Cloudflare Turnstile

Map<String, String> params = new HashMap<>();
params.put("method", "turnstile");
params.put("sitekey", "0x4AAAAA...");
params.put("pageurl", "https://example.com");

String token = solver.solve(params);

Solve Image CAPTCHAs

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

byte[] imageBytes = Files.readAllBytes(Path.of("captcha.png"));
String imageB64 = Base64.getEncoder().encodeToString(imageBytes);

Map<String, String> params = new HashMap<>();
params.put("method", "base64");
params.put("body", imageB64);

String text = solver.solve(params);
System.out.println("Text: " + text);

Concurrent Solving with CompletableFuture

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ParallelSolver {
    public static void main(String[] args) throws Exception {
        CaptchaAI solver = new CaptchaAI(System.getenv("CAPTCHAAI_API_KEY"));
        ExecutorService executor = Executors.newFixedThreadPool(10);

        List<String> pages = List.of(
                "https://example.com/page1",
                "https://example.com/page2",
                "https://example.com/page3"
        );

        List<CompletableFuture<String>> futures = new ArrayList<>();
        for (String page : pages) {
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                try {
                    Map<String, String> params = new HashMap<>();
                    params.put("method", "userrecaptcha");
                    params.put("googlekey", "6Le-wvkS...");
                    params.put("pageurl", page);
                    return solver.solve(params);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }, executor);
            futures.add(future);
        }

        for (int i = 0; i < futures.size(); i++) {
            try {
                String token = futures.get(i).get();
                System.out.printf("Page %d: solved (%d chars)%n", i, token.length());
            } catch (Exception e) {
                System.err.printf("Page %d: %s%n", i, e.getMessage());
            }
        }

        executor.shutdown();
    }
}

Spring Boot Integration

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CaptchaConfig {

    @Bean
    public CaptchaAI captchaAI(@Value("${captchaai.api-key}") String apiKey) {
        return new CaptchaAI(apiKey);
    }
}
# application.yml
captchaai:
  api-key: ${CAPTCHAAI_API_KEY}
import org.springframework.web.bind.annotation.*;

@RestController
public class FormController {

    private final CaptchaAI solver;

    public FormController(CaptchaAI solver) {
        this.solver = solver;
    }

    @PostMapping("/submit")
    public Map<String, Object> submit(@RequestBody Map<String, String> body)
            throws Exception {
        Map<String, String> params = new HashMap<>();
        params.put("method", "userrecaptcha");
        params.put("googlekey", body.get("siteKey"));
        params.put("pageurl", body.get("pageUrl"));

        String token = solver.solve(params);
        return Map.of("success", true, "tokenLength", token.length());
    }
}

Troubleshooting

Error Cause Fix
java.net.ConnectException Network issue Check firewall and DNS
Submit failed: ERROR_WRONG_USER_KEY Bad API key Copy key from dashboard
NumberFormatException on balance Unexpected response Check key validity
Timeout after 300s Slow solve or network Increase timeout; retry

FAQ

Does this work with Java 8?

The HttpClient API requires Java 11+. For Java 8, use HttpURLConnection or Apache HttpClient with the same API parameters.

Can I use this with Maven/Gradle?

Yes. The code has no external dependencies. Add it as a source file or package it in a local module.

Is the CaptchaAI class thread-safe?

Yes. HttpClient is thread-safe. Use a single CaptchaAI instance across threads.

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.