Official PHP client for the CapSkip local captcha solver.
CapSkip runs on your machine and exposes a standard captcha-solver HTTP API (the familiar in.php / res.php endpoints). This SDK wraps that API with clean, familiar method names, so you can solve captchas locally — no per-solve API fees beyond your CapSkip license.
Download and run the CapSkip desktop app from capskip.com. Leave it running in the background.
In CapSkip settings, note:
- API port (default:
8080) - API key (optional — if validation is disabled, any string works)
composer require capskip/capskipOr from source:
git clone https://github.com/capskip/capskip-php.git
cd capskip-php
composer install<?php
require 'vendor/autoload.php';
use CapSkip\CapSkip;
$solver = new CapSkip(['host' => '127.0.0.1', 'port' => 8080]);
$result = $solver->recaptcha(
'YOUR_SITEKEY',
'https://example.com/page-with-recaptcha'
);
echo $result['code']; // g-recaptcha-response tokenPrerequisite: CapSkip must be running before you call the SDK. If you see a connection error, see Troubleshooting.
| Type | SDK method |
|---|---|
| Image CAPTCHA (distorted text) | $solver->normal($file) |
| reCAPTCHA v2 (checkbox) | $solver->recaptcha($sitekey, $url) |
| reCAPTCHA v2 Invisible | $solver->recaptcha($sitekey, $url, ['invisible' => 1]) |
| reCAPTCHA v2 Enterprise | $solver->recaptcha($sitekey, $url, ['enterprise' => 1]) |
| reCAPTCHA v3 | $solver->recaptcha($sitekey, $url, ['version' => 'v3']) |
| reCAPTCHA v3 Enterprise | $solver->recaptcha($sitekey, $url, ['version' => 'v3', 'enterprise' => 1]) |
| Cloudflare Turnstile (widget) | $solver->turnstile($sitekey, $url) |
| Cloudflare Turnstile (challenge page) | $solver->turnstile($sitekey, $url, ['data' => ..., 'pagedata' => ...]) |
| GeeTest v3 (slide) | $solver->geetest($gt, $challenge, $url) |
| Guide | Description |
|---|---|
| Tutorial | Complete walkthrough of every captcha type |
| Getting Started | Full setup: CapSkip app, SDK install, first script |
| API Reference | All classes, methods, parameters, and return values |
| Examples | Ready-to-run scripts for every captcha type |
| Troubleshooting | Connection errors, timeouts, proxy issues |
| Contributing | Development setup, tests, pull requests |
| Changelog | Release history |
use CapSkip\CapSkip;
$solver = new CapSkip([
'apiKey' => 'capskip', // your CapSkip API key (or any string if validation is off)
'host' => '127.0.0.1', // CapSkip host
'port' => 8080, // CapSkip port from app settings
'defaultTimeout' => 120, // seconds — image captcha polling timeout
'recaptchaTimeout' => 300, // seconds — reCAPTCHA / Turnstile / GeeTest polling timeout
'pollingInterval' => 5, // max seconds between res.php polls (starts at 0.25s, backs off to this)
]);Use environment variables in production:
# Linux / macOS
export CAPSKIP_API_KEY="your-key"
export CAPSKIP_HOST="127.0.0.1"
export CAPSKIP_PORT="8080"# Windows PowerShell
$env:CAPSKIP_API_KEY = "your-key"
$env:CAPSKIP_HOST = "127.0.0.1"
$env:CAPSKIP_PORT = "8080"use CapSkip\CapSkip;
$solver = new CapSkip([
'apiKey' => getenv('CAPSKIP_API_KEY') ?: 'capskip',
'host' => getenv('CAPSKIP_HOST') ?: '127.0.0.1',
'port' => (int) (getenv('CAPSKIP_PORT') ?: 8080),
]);$result = $solver->normal('captcha.png');
$result = $solver->normal('https://example.com/captcha.jpg');
$result = $solver->normal('data:image/png;base64,iVBORw0KGgo...');
echo $result['code'];// reCAPTCHA v2
$v2 = $solver->recaptcha('...', 'https://example.com');
// reCAPTCHA v3
$v3 = $solver->recaptcha('...', 'https://example.com', [
'version' => 'v3',
'action' => 'submit',
'score' => 0.7,
]);$result = $solver->turnstile('0x4AAAAAAA...', 'https://example.com');$gt is static per site, but $challenge is single-use and expires in about a
minute — fetch a fresh pair right before solving.
$result = $solver->geetest(
'81388ea1fc187e0c335c0a8907ff2625',
'7cf6a8b1a2c34d5e6f7089abcdef0123',
'https://example.com/login'
);
// Post these back exactly as the site's own front-end would
$result['challenge']; $result['validate']; $result['seccode'];// Proxy is not supported for image captcha
$result = $solver->recaptcha('...', 'https://example.com', [
'proxy' => ['type' => 'HTTPS', 'uri' => 'user:pass@1.2.3.4:3128'],
]);
$result = $solver->turnstile('...', 'https://example.com', [
'proxy' => ['type' => 'HTTP', 'uri' => '1.2.3.4:3128'],
]);use CapSkip\CapSkip;
$solver = new CapSkip();
$r1 = $solver->recaptcha('...', 'https://a.com');
$r2 = $solver->turnstile('...', 'https://b.com');
echo $r1['code'], $r2['code'];PHP executes synchronously, so each solve blocks until it finishes.
AsyncCapSkipis exported as an alias ofCapSkipfor parity with the other CapSkip SDKs — code ported from them keeps working unchanged.
More examples: examples/
Every solve method returns an associative array:
[
'captchaId' => '12345', // internal ID from CapSkip
'code' => 'TOKEN_OR_TEXT', // solution — text for image, token for reCAPTCHA/Turnstile
'userAgent' => '...', // Turnstile only — use when submitting challenge-page tokens
]GeeTest additionally expands its answer into challenge, validate, and
seccode, while code keeps the raw JSON string.
use CapSkip\CapSkip;
use CapSkip\Exceptions\ValidationException;
use CapSkip\Exceptions\NetworkException;
use CapSkip\Exceptions\ApiException;
use CapSkip\Exceptions\TimeoutException;
try {
$result = $solver->recaptcha('...', '...');
} catch (ValidationException $e) {
// invalid parameters
} catch (NetworkException $e) {
// CapSkip not running, or captcha not ready (manual polling)
} catch (ApiException $e) {
// API returned an error code
} catch (TimeoutException $e) {
// polling timeout exceeded
}All four extend CapSkip\Exceptions\CapSkipError, so you can catch them all at once with the base class.
- PHP 8.0 or newer
- The
curlandjsonextensions (bundled with most PHP installs) - No other runtime dependencies
git clone https://github.com/capskip/capskip-php.git
cd capskip-php
composer install
composer testSee CONTRIBUTING.md for the full development workflow.
MIT — see LICENSE.