API Tutorials

Multi-Character Image CAPTCHA Solving Strategies

Complex image CAPTCHAs use connected letters, overlapping characters, varied fonts, and noise to prevent OCR. Here's how to approach them with CaptchaAI.


Common Complexity Types

Type Description Difficulty
Clean text No distortion, uniform font Easy
Warped text Letters individually rotated/scaled Medium
Connected letters Characters overlap or touch Hard
Multi-font Different fonts per character Hard
Noise + lines Background noise, strikethrough lines Medium
Color variation Different colors per character Medium
Math expression Numbers + operators, result expected Medium

Submitting Complex CAPTCHAs

For standard multi-character CAPTCHAs, submit via base64 with appropriate hints:

import requests
import base64
import time
import os

API_KEY = os.environ["CAPTCHAAI_API_KEY"]


def solve_complex_image(image_b64, hints=None):
    """Solve a complex multi-character image CAPTCHA."""
    payload = {
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "json": 1,
    }

    if hints:
        payload.update(hints)

    resp = requests.post(
        "https://ocr.captchaai.com/in.php",
        data=payload,
        timeout=30,
    )
    result = resp.json()

    if result.get("status") != 1:
        raise RuntimeError(f"Submit failed: {result.get('request')}")

    task_id = result["request"]

    time.sleep(8)
    for _ in range(24):
        resp = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        }, timeout=15)
        data = resp.json()
        if data.get("status") == 1:
            return data["request"]
        if data["request"] != "CAPCHA_NOT_READY":
            raise RuntimeError(data["request"])
        time.sleep(5)

    raise TimeoutError("Solve timeout")

Strategy: Connected Letters

Connected letters are the hardest for basic OCR but not for CaptchaAI:

def solve_connected_letters(image_path):
    """Solve CAPTCHA with connected/overlapping characters."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "textinstructions": "Characters may be connected or overlapping",
        "minLen": 4,
        "maxLen": 8,
    })

Strategy: Mixed Case with Noise

def solve_noisy_mixed(image_path):
    """Solve CAPTCHA with background noise and mixed case."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "regsense": 1,         # Case-sensitive
        "language": 2,         # Latin characters
        "textinstructions": "Ignore background lines and noise",
    })

Strategy: Multi-Font Text

def solve_multi_font(image_path):
    """Solve CAPTCHA using multiple fonts per character."""
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("ascii")

    return solve_complex_image(b64, hints={
        "textinstructions": "Each character may use a different font or style",
        "minLen": 5,
        "maxLen": 7,
    })

Image Preprocessing for Better Results

Preprocessing before submission can improve accuracy:

# preprocess.py
from PIL import Image, ImageFilter, ImageEnhance
import io
import base64


def preprocess_for_ocr(image_path):
    """Preprocess image to improve OCR accuracy."""
    img = Image.open(image_path)

    # Convert to grayscale
    img = img.convert("L")

    # Increase contrast
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(2.0)

    # Sharpen
    img = img.filter(ImageFilter.SHARPEN)

    # Binarize (threshold)
    threshold = 128
    img = img.point(lambda p: 255 if p > threshold else 0)

    # Encode back to base64
    buffer = io.BytesIO()
    img.save(buffer, format="PNG")
    return base64.b64encode(buffer.getvalue()).decode("ascii")

Retry Strategy with Reporting

# retry_strategy.py


def solve_with_retry(image_b64, hints, max_retries=3):
    """Retry solving with fallback strategies."""
    strategies = [
        hints,                                          # Original hints
        {**hints, "textinstructions": ""},              # Without instructions
        {**hints, "numeric": 0, "regsense": 0},        # Relaxed constraints
    ]

    for i, strategy in enumerate(strategies[:max_retries]):
        try:
            result = solve_complex_image(image_b64, strategy)
            return {"text": result, "strategy": i, "success": True}
        except RuntimeError:
            continue

    return {"text": None, "strategy": -1, "success": False}


def report_bad_answer(task_id):
    """Report incorrect answer for quality feedback."""
    requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY,
        "action": "reportbad",
        "id": task_id,
    }, timeout=10)

Troubleshooting

Issue Cause Fix
Missing characters Connected letters misread Add textinstructions about connected text
Extra characters Noise interpreted as text Preprocess: remove noise before submission
Wrong case Case not preserved Set regsense=1
Math result returned as expression Missing calc=1 Enable calc mode for math CAPTCHAs
Consistently wrong on specific site Site-specific font Report bad answers to improve model

FAQ

Should I preprocess images before submitting?

Only if you're getting poor results. CaptchaAI handles most distortions natively. Preprocessing helps for very noisy or low-contrast images.

What if the same image type keeps failing?

Report bad answers with reportbad to help improve accuracy. Also try adding specific textinstructions describing the CAPTCHA characteristics.

Is there a character limit for image CAPTCHAs?

CaptchaAI can handle CAPTCHAs up to about 20 characters. Most are 4-8 characters.



Solve complex image CAPTCHAs — start with CaptchaAI.

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.