API Tutorials

CaptchaAI Soft ID and Referral Tracking Integration

The soft_id parameter lets you track which application, client, or integration generated each CAPTCHA solve. This is essential for agencies managing multiple clients, software vendors embedding CaptchaAI, and affiliate partners.


What Is Soft ID?

Without soft_id:
  All solves tracked as one pool
  No way to know which project/client generated usage

With soft_id:
  Solve #1 ──▶ soft_id=PROJECT_A ──▶ Tracked separately
  Solve #2 ──▶ soft_id=PROJECT_B ──▶ Tracked separately
  Solve #3 ──▶ soft_id=CLIENT_123 ──▶ Tracked separately

Basic Usage

Add soft_id to any solve request:

import requests

API_KEY = "YOUR_API_KEY"
SOFT_ID = "1234"  # Your registered soft_id

resp = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": "SITE_KEY",
    "pageurl": "https://example.com",
    "soft_id": SOFT_ID,
    "json": 1,
})

Works with all CAPTCHA types:

# Turnstile with soft_id
resp = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "turnstile",
    "sitekey": "SITE_KEY",
    "pageurl": "https://example.com",
    "soft_id": SOFT_ID,
    "json": 1,
})

# Image CAPTCHA with soft_id
resp = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "base64",
    "body": base64_image,
    "soft_id": SOFT_ID,
    "json": 1,
})

Use Cases

1. Agency Client Tracking

class AgencySolver:
    """Track CAPTCHA usage per client."""

    def __init__(self, api_key, agency_soft_id):
        self.api_key = api_key
        self.soft_id = agency_soft_id
        self.base = "https://ocr.captchaai.com"

    def solve(self, method, client_tag=None, **params):
        data = {
            "key": self.api_key,
            "method": method,
            "soft_id": self.soft_id,
            "json": 1,
        }
        data.update(params)

        resp = requests.post(f"{self.base}/in.php", data=data)
        task_id = resp.json()["request"]

        # Log client attribution locally
        if client_tag:
            self._log_usage(client_tag, method, task_id)

        return self._poll(task_id)

    def _poll(self, task_id, timeout=120):
        import time
        start = time.time()
        while time.time() - start < timeout:
            time.sleep(5)
            resp = requests.get(f"{self.base}/res.php", params={
                "key": self.api_key, "action": "get",
                "id": task_id, "json": 1,
            })
            data = resp.json()
            if data["request"] != "CAPCHA_NOT_READY":
                return data["request"]
        raise TimeoutError("Solve timeout")

    def _log_usage(self, client_tag, method, task_id):
        import csv
        import datetime
        with open("client_usage.csv", "a", newline="") as f:
            writer = csv.writer(f)
            writer.writerow([
                datetime.datetime.utcnow().isoformat(),
                client_tag, method, task_id,
            ])


# Track usage per client
solver = AgencySolver("YOUR_API_KEY", agency_soft_id="1234")

# Client A's solves
solver.solve("userrecaptcha",
    client_tag="client_acme",
    googlekey="KEY", pageurl="https://acme.com",
)

# Client B's solves
solver.solve("turnstile",
    client_tag="client_beta",
    sitekey="KEY", pageurl="https://beta.com",
)

2. Software Vendor Integration

If you build a tool that uses CaptchaAI, include your soft_id so usage is attributed to your application:

class MyScraper:
    """Scraping tool with embedded CaptchaAI integration."""

    SOFT_ID = "5678"  # Registered when joining partner program

    def __init__(self, user_api_key):
        self.api_key = user_api_key

    def solve_captcha(self, method, **params):
        data = {
            "key": self.api_key,
            "method": method,
            "soft_id": self.SOFT_ID,  # Always include vendor ID
            "json": 1,
        }
        data.update(params)
        resp = requests.post(
            "https://ocr.captchaai.com/in.php", data=data,
        )
        return resp.json()

3. Multi-Project Attribution

# Different soft_ids per project
PROJECTS = {
    "price_monitor": "1001",
    "lead_gen": "1002",
    "qa_testing": "1003",
}

def solve_for_project(project_name, method, **params):
    soft_id = PROJECTS.get(project_name, "0000")
    data = {
        "key": API_KEY,
        "method": method,
        "soft_id": soft_id,
        "json": 1,
    }
    data.update(params)
    return requests.post("https://ocr.captchaai.com/in.php", data=data)

Local Usage Tracking

Track solver usage by soft_id locally for billing and analytics:

import csv
import datetime
from collections import defaultdict


class UsageTracker:
    """Track CAPTCHA solve usage for billing and analytics."""

    def __init__(self, log_file="captchaai_usage.csv"):
        self.log_file = log_file
        self._init_log()

    def _init_log(self):
        try:
            with open(self.log_file, "r"):
                pass
        except FileNotFoundError:
            with open(self.log_file, "w", newline="") as f:
                writer = csv.writer(f)
                writer.writerow([
                    "timestamp", "soft_id", "client",
                    "method", "task_id", "status",
                ])

    def record(self, soft_id, client, method, task_id, status="submitted"):
        with open(self.log_file, "a", newline="") as f:
            writer = csv.writer(f)
            writer.writerow([
                datetime.datetime.utcnow().isoformat(),
                soft_id, client, method, task_id, status,
            ])

    def get_summary(self, days=30):
        """Summarize usage by client over the last N days."""
        cutoff = datetime.datetime.utcnow() - datetime.timedelta(days=days)
        usage = defaultdict(lambda: defaultdict(int))

        with open(self.log_file, "r") as f:
            reader = csv.DictReader(f)
            for row in reader:
                ts = datetime.datetime.fromisoformat(row["timestamp"])
                if ts > cutoff:
                    usage[row["client"]][row["method"]] += 1

        return dict(usage)


# Usage
tracker = UsageTracker()
tracker.record("1234", "client_acme", "userrecaptcha", "TASK123")

summary = tracker.get_summary(days=30)
for client, methods in summary.items():
    print(f"{client}: {dict(methods)}")

Troubleshooting

Issue Cause Fix
soft_id not tracked Wrong parameter name Use soft_id (underscore, not hyphen)
No attribution in dashboard soft_id not registered Register your soft_id through the partner program
Multiple soft_ids needed One per application/integration Register each application separately
Usage not matching local logs Local tracking missed errors Log both success and failure

FAQ

How do I get a soft_id?

Register through CaptchaAI's partner or developer program. You'll receive a unique soft_id for your application.

Does soft_id affect solving behavior?

No. The soft_id is only for tracking and attribution. It doesn't change solve speed, accuracy, or pricing.

Can I use multiple soft_ids with one API key?

Yes. Each request can include a different soft_id. Use different IDs for different projects or clients.



Track your integration usage — join the CaptchaAI partner program.

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.