3. Verify the CAPTCHA Solution
β A full working backend example can be found at the bottom of this page.
- Server Side Verification
- Curl Example
- API Response
- Summary Of The POST Request Response
- Full Backend Examples (PHP, Python, Node...)
Verification of the solution (token) works in the same way as with Google reCAPTCHA & hCaptcha. Only the API response is slightly different with more information. And you can also verify email addresses in the same API call.
Server Side Verificationβ
Remember the secret key
that was automatically generated together with the sitekey
. This secret key
is needed to verify the CAPTCHA solution with the API endpoint to ensure that it is indeed real and valid.
To verify the CAPTCHA solution, make a POST request to
https://www.zencaptcha.com/captcha/siteverify
with the following parameters:
Post Parameter | Description |
---|---|
response | The solution (zenc-captcha-solution ) of the CAPTCHA |
secret | Your secret key (that matches the sitekey of the widget) |
Optional: Users email address (disposable/invalid check) - Alternatively, you can simply provide the domain name of the email (for maximum privacy: example.com). |
Do not use a GET request to call /siteverify (or it will fail)
curl exampleβ
Change CAPTCHA-SOLUTION and YOUR-SECRET-KEY with your values:
curl https://www.zencaptcha.com/captcha/siteverify
-X POST
-H "Content-Type: application/x-www-form-urlencoded"
-d 'response=CAPTCHA-SOLUTION&secret=YOUR-SECRET-KEY'
To verify the zenc-captcha-solution
token sent from your frontend HTML to your backend, the endpoint requires a POST request with two parameters - your secret key
and the zenc-captcha-solution
token. You can optionally include the users email adress &email=xxx@example.com
to check wheter the user uses a disposable or invalid email address. (This option is only available on all paid plans.)
API Responseβ
The verification responseβ
The response to the POST request indicates whether the CAPTCHA solution (token) is valid.
- The response body is a JSON object.
The response will also give you the user's country code (ISO 3166-1 alpha-2 codes)
, the validity of the user's email address and a fraud score for each user from 0 to 99. Scores between 0 and 55 are acceptable, while scores between 55 and 99 indicate that the user may be fraudulent. Do not rely on the score, it should only help you identify potentially fraudulent users based on their activity on your site.
{
"success":true|false, //true if validation is successful
"message":"XXX", //"valid" or another error message
"fraudscore":XXX, //number between 0-99
"countrycode":"XXX", //two letter country code ex. "DE", "FR"
"emailvalid":"XXX" //`none`, `valid_email`, `invalid_email`, `disposable_email` or `upgrade_plan`
}
//"success":true and "message":"valid" This means that the solution is correct. => accept user
Solutions can only be validated once and will then be marked as invalid or duplicated. Solutions are also only valid for up to 5 minutes, after which they will be marked as invalid. If you need a new solution, you should reset the captcha (zencap.reset()) and start it again (zencap.start()).
Summary Of The POST Request Responseβ
Response Key | Description |
---|---|
success | If true , then the solution was correct, no need to check the message field. If false , the solution was invalid, duplicate or has timed out more info in "message" . |
message | If "valid" , then the solution was correct. If "timeout_or_duplicate" , then then the solution has already been validated or has timed out. If "invalid_solution" , then the solution is not valid. Other error codes are possible. |
fraudscore | 0-55 is acceptable, 55-99 means that the user could be a spammer based on potential fraudulent activity. However a value of 0-55 does not mean that the user is not a spammer. Use at your own risk. |
countrycode | Two-letter country codes of the users defined in ISO 3166-1 - (ISO 3166-1 alpha-2 codes) . For example: Germany "DE", France "FR" |
emailvalid | "valid_email" is perfect, "invalid_email" or "disposable_email" is not good. "disposable_email" means that the user tried to use a disposable email address (100% sure). "none" means that you may not have submitted an email address. "upgrade_plan" means that you need to update your plan |
Full (Simple) Backend Examplesβ
- PHP
- Node
- Python
- Ruby
$email = $_POST['email'];
$password = $_POST['password'];
$captcharesponse = $_POST['zenc-captcha-solution'];
$secret = "YOUR-SECRET-KEY"; //never share your key
$data = array(
"response" => $captcharesponse,
"secret" => $secret,
"email" => $email,
);
$options = array(
"http" => array(
"header" => "Content-type: application/x-www-form-urlencoded",
"method" => "POST",
"content" => http_build_query($data),
),
);
$context = stream_context_create($options);
$verify = file_get_contents("https://www.zencaptcha.com/captcha/siteverify", false, $context);
$captcha_success = json_decode($verify);
if ($captcha_success->success==false) {
//wrong solution - do not continue
exit();
}
else{
//correct solution - continue with your code
//$captcha_success->fraudscore (get the score)
//$captcha_success->countrycode (get users' country code)
//$captcha_success->emailvalid (check users' email address)
}
const https = require('https');
const querystring = require('querystring');
const postData = querystring.stringify({
'response': 'zenc-captcha-solution', //response of the captcha - the solution
'secret': 'YOUR-SECRET',
'email': 'USER-EMAIL-ADDRESS' //email address of the user
});
const options = {
hostname: 'www.zencaptcha.com',
path: '/captcha/siteverify',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
const req = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
const result = JSON.parse(data);
if (result.success) {
console.log('Verification successful! '+ result.message);
//correct solution - continue with your code
//result.fraudscore (get the score)
//result.countrycode (get users' country code)
//result.emailvalid (check users' email address)
} else {
console.log('Verification failed. '+ result.message);
return;
//do not continue
}
});
});
req.on('error', (error) => {
console.error(error);
});
req.write(postData);
req.end();
import requests
import json
email = request.getParameter("email")
password = request.getParameter("password")
captcharesponse = request.getParameter("zenc-captcha-solution")
secret = "YOUR-SECRET-KEY" #never share your key
data = {
"response": captcharesponse,
"secret": secret,
"email": email
}
url = "https://www.zencaptcha.com/captcha/siteverify"
response = requests.post(url, data=data)
verify = response.text
captcha_success = json.loads(verify)
if not captcha_success["success"]:
#wrong solution - do not continue
return
else:
#correct solution - continue with your code
#captcha_success["fraudscore"] #get the score
#captcha_success["countrycode"] #get users' country code
#captcha_success["emailvalid"] #check users' email address
require 'net/http'
require 'json'
email = get_parameter("email")
password = get_parameter("password")
captcharesponse = get_parameter("zenc-captcha-solution")
secret = "YOUR-SECRET-KEY" #never share your key
data = {
"response" => captcharesponse,
"secret" => secret,
"email" => email
}
url = URI("https://www.zencaptcha.com/captcha/siteverify")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Content-Type"] = "application/x-www-form-urlencoded"
request.body = URI.encode_www_form(data)
response = http.request(request)
verify = response.read_body
captcha_success = JSON.parse(verify)
if not captcha_success["success"]
#wrong solution - do not continue
return
else
#correct solution - continue with your code
#captcha_success["fraudscore"] #get the score
#captcha_success["countrycode"] #get users' country code
#captcha_success["emailvalid"] #check users' email address
end