reCAPTCHA & image captchas in PHP — updated August 2026
TL;DR: Everything runs over plain HTTPS — the cURL extension is all you need, so this works on any shared host. Image captchas solve synchronously; reCAPTCHA is create-task + poll. 50 free solves on signup, no credit card.
No Composer, no dependencies — just the cURL extension that ships with PHP. CURLFile handles the multipart upload:
<?php
$apiKey = getenv('CAPTCHAKINGS_KEY');
$ch = curl_init('https://captchakings.com/api/process.php');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $apiKey"],
CURLOPT_POSTFIELDS => ['captcha' => new CURLFile('captcha.jpg')],
CURLOPT_TIMEOUT => 30
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($data['success']) {
echo $data['data']['prediction']; // solved text
echo $data['data']['confidence']; // 0-100
echo $data['billing']['balance_remaining'];
} else {
echo 'Error: ' . $data['error']['message'];
}
reCAPTCHA, hCaptcha and AWS WAF are token tasks — submit the job, then poll until it's ready. This reusable function covers the full flow (payload details on the reCAPTCHA solver page):
<?php
function ckPost(string $url, array $payload): array {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 30
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
return $data;
}
function solveRecaptchaV2(string $pageUrl, string $siteKey): string {
$apiKey = getenv('CAPTCHAKINGS_KEY');
$created = ckPost('https://api.captchakings.com/createTask', [
'clientKey' => $apiKey,
'task' => [
'type' => 'RecaptchaV2TaskProxyless',
'websiteURL' => $pageUrl,
'websiteKey' => $siteKey
]
]);
if (empty($created['taskId'])) {
throw new RuntimeException('createTask failed: ' . json_encode($created));
}
$deadline = time() + 120;
while (time() < $deadline) {
sleep(3);
$result = ckPost('https://api.captchakings.com/getTaskResult', [
'clientKey' => $apiKey,
'taskId' => $created['taskId']
]);
if (($result['status'] ?? '') === 'ready') {
return $result['solution']['gRecaptchaResponse'];
}
}
throw new RuntimeException('Solve timed out');
}
If your project already uses Guzzle (Laravel, Symfony, Slim...), the same calls get shorter:
<?php
use GuzzleHttp\Client;
$http = new Client(['base_uri' => 'https://api.captchakings.com']);
// Create task
$created = json_decode($http->post('createTask', [
'json' => [
'clientKey' => getenv('CAPTCHAKINGS_KEY'),
'task' => [
'type' => 'RecaptchaV2TaskProxyless',
'websiteURL' => $pageUrl,
'websiteKey' => $siteKey
]
]
])->getBody(), true);
// Image captcha via multipart
$img = json_decode((new Client())->post('https://captchakings.com/api/process.php', [
'headers' => ['Authorization' => 'Bearer ' . getenv('CAPTCHAKINGS_KEY')],
'multipart' => [[
'name' => 'captcha',
'contents' => fopen('captcha.jpg', 'r')
]]
])->getBody(), true);
echo $img['data']['prediction'];
Inside a plugin or theme, use WordPress's HTTP API — it picks the right transport automatically:
<?php
function myplugin_solve_recaptcha($page_url, $site_key) {
$api_key = get_option('captchakings_api_key');
$response = wp_remote_post('https://api.captchakings.com/createTask', [
'headers' => ['Content-Type' => 'application/json'],
'body' => wp_json_encode([
'clientKey' => $api_key,
'task' => [
'type' => 'RecaptchaV2TaskProxyless',
'websiteURL' => $page_url,
'websiteKey' => $site_key
]
]),
'timeout' => 30
]);
$created = json_decode(wp_remote_retrieve_body($response), true);
if (empty($created['taskId'])) return false;
// Poll (same pattern with wp_remote_post on getTaskResult)
for ($i = 0; $i < 40; $i++) {
sleep(3);
$poll = wp_remote_post('https://api.captchakings.com/getTaskResult', [
'headers' => ['Content-Type' => 'application/json'],
'body' => wp_json_encode(['clientKey' => $api_key, 'taskId' => $created['taskId']])
]);
$result = json_decode(wp_remote_retrieve_body($poll), true);
if (($result['status'] ?? '') === 'ready') {
return $result['solution']['gRecaptchaResponse'];
}
}
return false;
}
| Captcha Type | Endpoint | Result |
|---|---|---|
| Image captcha | captchakings.com/api/process.php | Solved text (synchronous) |
| reCAPTCHA / hCaptcha / AWS WAF | api.captchakings.com/createTask | Token (async, poll getTaskResult) |
| 2Captcha-compatible | captchakings.com/in.php / res.php | Drop-in migration format |
Yes. The API only needs outbound HTTPS through the cURL extension, which every shared host enables by default. No Composer, root access, or custom ports required.
POST a RecaptchaV2TaskProxyless task to createTask, poll getTaskResult every 3 seconds until status is ready, and use the returned gRecaptchaResponse token. Full function above.
Yes — wp_remote_post handles both task creation and polling, and the image API accepts a multipart body the same way. Example above.
Both work. Native cURL = zero dependencies and runs everywhere; Guzzle is nicer in Composer-based projects like Laravel. Both styles shown above.
50 free solves on signup — test with your own captchas.
Get Your API Key