Overview
CaptchaShield is a modern CAPTCHA solution designed to protect your web applications from bots and automated attacks while providing a seamless experience for legitimate users. This documentation covers everything you need to integrate CaptchaShield into your application.
Integration involves two key steps:
- Frontend Integration: Embed the CaptchaShield widget in your forms
- Backend Verification: Validate the CAPTCHA token on your server
Quick Start
Get started with CaptchaShield in under 5 minutes. This guide shows you the minimal setup required.
Step 1: Get Your API Keys
Sign up at captchashield.com to obtain:
- Site Key (public key for frontend)
- Secret Key (private key for backend)
Step 2: Add Widget to Your Form
Insert this HTML in your form:
<form action="/submit" method="POST">
<!-- Your form fields -->
<input type="text" name="email" placeholder="Email">
<!-- CaptchaShield Widget -->
<div class="captchashield"
data-sitekey="YOUR_SITE_KEY"
data-api="https://captchashield.com"
data-theme="auto"
data-lang="auto"></div>
<button type="submit">Submit</button>
</form>
<!-- Load CaptchaShield Script -->
<script src="https://captchashield.com/widget.js" async defer></script>
Step 3: Verify on Server
When your form is submitted, verify the CAPTCHA token:
// PHP Example $captchaToken = $_POST['captchaToken']; $secretKey = 'YOUR_SECRET_KEY'; $response = file_get_contents('https://captchashield.com/v1/siteverify', false, stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => 'Content-Type: application/x-www-form-urlencoded', 'content' => http_build_query([ 'secret' => $secretKey, 'response' => $captchaToken, 'remoteip' => $_SERVER['REMOTE_ADDR'] ]) ] ])); $result = json_decode($response); if ($result->success) { // CAPTCHA verified - process form } else { // CAPTCHA failed - show error }
That's it! You're now protected by CaptchaShield.
Frontend Widget
The CaptchaShield widget is a customizable component that handles user verification on the client side.
Basic Usage
<div class="captchashield"
data-sitekey="YOUR_SITE_KEY"
data-api="https://captchashield.com"></div>
<script src="https://captchashield.com/widget.js" async defer></script>
Widget Attributes
Customize the widget behavior with these data attributes:
data-sitekey (required)
Your public site key obtained from the CaptchaShield dashboard.
data-sitekey="YOUR_SITE_KEY"
data-api (optional)
API endpoint URL. Default: https://captchashield.com
data-api="https://captchashield.com"
data-theme (optional)
Visual theme for the widget. Options: auto, light, dark. Default: auto
<div class="captchashield" data-sitekey="YOUR_SITE_KEY" data-theme="dark"></div>
data-lang (optional)
Language for widget text. Options: auto, en, tr. Default: auto
<div class="captchashield" data-sitekey="YOUR_SITE_KEY" data-lang="en"></div>
data-callback (optional)
Global function name to call when CAPTCHA is successfully completed.
<script>
function onCaptchaSuccess(token) {
console.log('CAPTCHA token:', token);
// Auto-submit form or enable submit button
document.getElementById('myForm').submit();
}
</script>
<div class="captchashield"
data-sitekey="YOUR_SITE_KEY"
data-callback="onCaptchaSuccess"></div>
Privacy & Terms Links (optional)
Add links to your privacy policy, terms of service, and GDPR information.
<div class="captchashield"
data-sitekey="YOUR_SITE_KEY"
data-privacy="https://yoursite.com/privacy"
data-terms="https://yoursite.com/terms"
data-gdpr="https://yoursite.com/gdpr"></div>
Multiple Widgets on One Page
You can render multiple CaptchaShield widgets on the same page. Each will generate its own token.
<form id="loginForm">
<div class="captchashield" data-sitekey="YOUR_SITE_KEY"></div>
</form>
<form id="registerForm">
<div class="captchashield" data-sitekey="YOUR_SITE_KEY"></div>
</form>
captchaToken to the form.
Server Verification
Always verify the CAPTCHA token on your server before processing protected actions. Client-side validation alone is insufficient for security.
Verification Endpoint
POST https://captchashield.com/v1/siteverify
Request Parameters
Send these parameters as form data or JSON:
| Parameter | Required | Description |
|---|---|---|
secret |
Yes | Your secret key from CaptchaShield dashboard |
response |
Yes | The CAPTCHA token from the widget |
remoteip |
No | User's IP address (recommended) |
Response Format
The API returns a JSON response:
{
"success": true,
"challenge_ts": "2024-01-27T12:34:56Z",
"hostname": "yoursite.com",
"error_codes": []
}
| Field | Type | Description |
|---|---|---|
success |
boolean | true if verification passed |
challenge_ts |
string | Timestamp of CAPTCHA completion |
hostname |
string | Hostname where CAPTCHA was solved |
error_codes |
array | Error codes if verification failed |
Verification Flow
- User completes CAPTCHA on frontend
- Widget generates
captchaToken(one-time use) - Form submits to your server with token
- Your server sends token to CaptchaShield API for verification
- If
success: true, process the request - If
success: false, reject the request and show error
Security Best Practices
- Never expose your secret key in frontend code, version control, or logs
- Verify every token server-side before processing protected actions
- Tokens are one-time use - verify immediately and don't cache
- Use HTTPS for all communications
- Pass user IP via
remoteipparameter for enhanced security - Implement rate limiting on your endpoints to prevent abuse
- Handle errors gracefully and provide user-friendly messages
- Monitor for suspicious patterns like repeated failures
Code Examples
Complete integration examples for popular languages and frameworks.
PHP with cURL
<?php function verifyCaptcha($token, $secretKey, $remoteIp = null) { $url = 'https://captchashield.com/v1/siteverify'; $data = [ 'secret' => $secretKey, 'response' => $token ]; if ($remoteIp) { $data['remoteip'] = $remoteIp; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); return json_decode($response, true); } // Usage in form handler if ($_SERVER['REQUEST_METHOD'] === 'POST') { $captchaToken = $_POST['captchaToken'] ?? ''; $secretKey = 'YOUR_SECRET_KEY'; $result = verifyCaptcha( $captchaToken, $secretKey, $_SERVER['REMOTE_ADDR'] ); if ($result['success']) { // CAPTCHA verified - process form echo "Form submitted successfully!"; } else { // CAPTCHA failed $errors = $result['error_codes'] ?? []; echo "CAPTCHA verification failed: " . implode(', ', $errors); } } ?>
Laravel Controller
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Http; class ContactController extends Controller { public function submit(Request $request) { // Validate form fields $validated = $request->validate([ 'email' => 'required|email', 'message' => 'required|string', 'captchaToken' => 'required|string', ]); // Verify CAPTCHA $response = Http::asForm()->post('https://captchashield.com/v1/siteverify', [ 'secret' => config('services.captchashield.secret'), 'response' => $validated['captchaToken'], 'remoteip' => $request->ip(), ]); $result = $response->json(); if (!$result['success']) { return back()->withErrors([ 'captcha' => 'CAPTCHA verification failed. Please try again.' ]); } // Process form (save to DB, send email, etc.) // ... return redirect()->route('contact.success') ->with('message', 'Your message has been sent!'); } } ?>
Add to config/services.php:
'captchashield' => [ 'sitekey' => env('CAPTCHASHIELD_SITE_KEY'), 'secret' => env('CAPTCHASHIELD_SECRET_KEY'), ],
Node.js with Express
const express = require('express'); const axios = require('axios'); const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); async function verifyCaptcha(token, remoteIp) { try { const response = await axios.post( 'https://captchashield.com/v1/siteverify', new URLSearchParams({ secret: process.env.CAPTCHASHIELD_SECRET_KEY, response: token, remoteip: remoteIp }) ); return response.data; } catch (error) { console.error('CAPTCHA verification error:', error); return { success: false, error_codes: ['network-error'] }; } } app.post('/submit', async (req, res) => { const { email, message, captchaToken } = req.body; // Verify CAPTCHA const result = await verifyCaptcha( captchaToken, req.ip || req.connection.remoteAddress ); if (!result.success) { return res.status(400).json({ error: 'CAPTCHA verification failed', details: result.error_codes }); } // Process form // ... res.json({ success: true, message: 'Form submitted successfully' }); }); app.listen(3000, () => console.log('Server running on port 3000'));
Ruby on Rails
require 'net/http' require 'json' class ContactsController < ApplicationController def create captcha_token = params[:captchaToken] if verify_captcha(captcha_token, request.remote_ip) # Process form flash[:success] = 'Form submitted successfully!' redirect_to root_path else flash[:error] = 'CAPTCHA verification failed' render :new end end private def verify_captcha(token, remote_ip) uri = URI('https://captchashield.com/v1/siteverify') params = { secret: ENV['CAPTCHASHIELD_SECRET_KEY'], response: token, remoteip: remote_ip } response = Net::HTTP.post_form(uri, params) result = JSON.parse(response.body) result['success'] == true rescue => e Rails.logger.error "CAPTCHA verification error: #{e.message}" false end end
Python with Flask
from flask import Flask, request, jsonify import requests import os app = Flask(__name__) def verify_captcha(token, remote_ip): """Verify CAPTCHA token with CaptchaShield""" url = 'https://captchashield.com/v1/siteverify' payload = { 'secret': os.environ.get('CAPTCHASHIELD_SECRET_KEY'), 'response': token, 'remoteip': remote_ip } try: response = requests.post(url, data=payload, timeout=5) result = response.json() return result.get('success', False) except Exception as e: print(f'CAPTCHA verification error: {e}') return False @app.route('/submit', methods=['POST']) def submit_form(): data = request.get_json() or request.form captcha_token = data.get('captchaToken') if not captcha_token: return jsonify({'error': 'CAPTCHA token missing'}), 400 # Verify CAPTCHA if not verify_captcha(captcha_token, request.remote_addr): return jsonify({'error': 'CAPTCHA verification failed'}), 400 # Process form # ... return jsonify({'success': True, 'message': 'Form submitted'}) if __name__ == '__main__': app.run(debug=True)
Go with net/http
package main import ( "encoding/json" "fmt" "net/http" "net/url" "os" ) type CaptchaResponse struct { Success bool `json:"success"` ChallengeTS string `json:"challenge_ts"` Hostname string `json:"hostname"` ErrorCodes []string `json:"error_codes"` } func verifyCaptcha(token, remoteIP string) (bool, error) { secretKey := os.Getenv("CAPTCHASHIELD_SECRET_KEY") resp, err := http.PostForm("https://captchashield.com/v1/siteverify", url.Values{ "secret": {secretKey}, "response": {token}, "remoteip": {remoteIP}, }) if err != nil { return false, err } defer resp.Body.Close() var result CaptchaResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return false, err } return result.Success, nil } func submitHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } captchaToken := r.FormValue("captchaToken") remoteIP := r.RemoteAddr success, err := verifyCaptcha(captchaToken, remoteIP) if err != nil || !success { http.Error(w, "CAPTCHA verification failed", http.StatusBadRequest) return } // Process form fmt.Fprintf(w, "Form submitted successfully") } func main() { http.HandleFunc("/submit", submitHandler) http.ListenAndServe(":8080", nil) }
Java with Spring Boot
package com.example.demo; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import java.util.Map; @Service class CaptchaService { @Value("${captchashield.secret}") private String secretKey; private final RestTemplate restTemplate = new RestTemplate(); public boolean verify(String token, String remoteIp) { String url = "https://captchashield.com/v1/siteverify"; MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("secret", secretKey); params.add("response", token); params.add("remoteip", remoteIp); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); try { ResponseEntity<Map> response = restTemplate.postForEntity( url, request, Map.class); Map<String, Object> body = response.getBody(); return body != null && Boolean.TRUE.equals(body.get("success")); } catch (Exception e) { return false; } } } @RestController class ContactController { private final CaptchaService captchaService; public ContactController(CaptchaService captchaService) { this.captchaService = captchaService; } @PostMapping("/submit") public ResponseEntity<String> submit( @RequestParam String captchaToken, @RequestHeader("X-Forwarded-For") String remoteIp) { if (!captchaService.verify(captchaToken, remoteIp)) { return ResponseEntity .badRequest() .body("CAPTCHA verification failed"); } // Process form return ResponseEntity.ok("Form submitted successfully"); } }
.NET with ASP.NET Core
using Microsoft.AspNetCore.Mvc; using System.Text.Json; public class CaptchaService { private readonly IConfiguration _configuration; private readonly IHttpClientFactory _httpClientFactory; public CaptchaService( IConfiguration configuration, IHttpClientFactory httpClientFactory) { _configuration = configuration; _httpClientFactory = httpClientFactory; } public async Task<bool> VerifyAsync(string token, string remoteIp) { var client = _httpClientFactory.CreateClient(); var secretKey = _configuration["CaptchaShield:SecretKey"]; var parameters = new Dictionary<string, string> { { "secret", secretKey }, { "response", token }, { "remoteip", remoteIp } }; var content = new FormUrlEncodedContent(parameters); try { var response = await client.PostAsync( "https://captchashield.com/v1/siteverify", content); var json = await response.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize<CaptchaResponse>(json); return result?.Success ?? false; } catch { return false; } } } public class CaptchaResponse { public bool Success { get; set; } public string? ChallengeTs { get; set; } public string? Hostname { get; set; } public string[]? ErrorCodes { get; set; } } [ApiController] [Route("[controller]")] public class ContactController : ControllerBase { private readonly CaptchaService _captchaService; public ContactController(CaptchaService captchaService) { _captchaService = captchaService; } [HttpPost("submit")] public async Task<IActionResult> Submit([FromForm] string captchaToken) { var remoteIp = HttpContext.Connection.RemoteIpAddress?.ToString(); if (!await _captchaService.VerifyAsync(captchaToken, remoteIp)) { return BadRequest("CAPTCHA verification failed"); } // Process form return Ok("Form submitted successfully"); } }
WordPress Plugin
<?php /** * Plugin Name: CaptchaShield Integration * Description: Adds CaptchaShield protection to forms */ function captchashield_verify_token($token) { $secret_key = get_option('captchashield_secret_key'); $response = wp_remote_post('https://captchashield.com/v1/siteverify', [ 'body' => [ 'secret' => $secret_key, 'response' => $token, 'remoteip' => $_SERVER['REMOTE_ADDR'] ] ]); if (is_wp_error($response)) { return false; } $body = json_decode(wp_remote_retrieve_body($response), true); return !empty($body['success']); } // Add widget to comment form function captchashield_comment_form() { $site_key = get_option('captchashield_site_key'); echo '<div class="captchashield" data-sitekey="' . esc_attr($site_key) . '" data-api="https://captchashield.com"></div>'; } add_action('comment_form_after_fields', 'captchashield_comment_form'); // Add widget script to footer function captchashield_enqueue_script() { wp_enqueue_script( 'captchashield', 'https://captchashield.com/widget.js', [], null, true ); } add_action('wp_enqueue_scripts', 'captchashield_enqueue_script'); // Verify on comment submission function captchashield_verify_comment($commentdata) { if (is_user_logged_in()) { return $commentdata; // Skip for logged-in users } $token = $_POST['captchaToken'] ?? ''; if (!captchashield_verify_token($token)) { wp_die('CAPTCHA verification failed. Please go back and try again.'); } return $commentdata; } add_filter('preprocess_comment', 'captchashield_verify_comment'); ?>
Rules
What are Rules?
Rules let you control how CaptchaShield reacts to visitors. For each request we check basic signals like IP, IP range (CIDR), Country, ASN (ISP / hosting network), and User-Agent. If a rule matches, we apply the action you chose: Allow, Challenge, or Block.
Actions
- Allow — Let the request pass normally. Easy captcha.
- Challenge — Show a Hard CAPTCHA. The visitor must solve the challenge to continue.
- Block — Completely denied. The request is rejected immediately and is not bypassable (no CAPTCHA is shown).
Common rule types
Allowlist by IP (single IP)
Use this when you want to skip captcha for your own office/VPN/admin access.
If IP equals 203.0.113.10 → Allow
Allowlist by IP range (CIDR)
Allow a whole subnet (e.g., your server network or trusted provider range).
If IP is in 203.0.113.0/24 → Allow
Challenge by ASN
ASN represents the network/ISP (often used to detect hosting/datacenter traffic). You can force captcha for suspicious ASNs.
If ASN is in [13335, 16509, 8075] → Challenge
Block by country
If you don’t serve certain regions or you’re under attack from a region, block it.
If Country is in ["RU", "KP"] → Block
Challenge “everything else”
Example policy: allow your trusted traffic, block obvious bad traffic, and challenge the rest.
Default action → Challenge
Best practices
- Start with Challenge rules before using Block (reduce false positives).
- Keep allowlists strict (only your known IPs/ranges).
- Use ASN rules to challenge datacenter traffic without blocking real users.
- Review Logs to confirm your rules are doing what you expect.
Logs
CaptchaShield logs important events so you can monitor attack patterns, measure conversions, and debug false positives. Logs are organized per Site and contain request context such as country, ASN, user agent signals, latency, and verification outcomes.
Events
Common event types you may see:
| Event | Meaning | Notes |
|---|---|---|
challenge |
A captcha challenge was issued | Includes risk tier + rule result |
solve |
User attempted to solve a challenge | Records solve time & heuristics |
siteverify |
Backend token verification | One-time token usage is enforced |
blocked |
Request blocked by rule or security checks | Typically includes an error_code |
site → filter by time range → inspect challenge and siteverify events,
then check whether a rule or heuristic forced an unexpected action.
Fields
Logs typically include the following fields:
| Field | Description |
|---|---|
site_id |
Site that produced the event |
event |
Event type (challenge, solve, siteverify, blocked) |
success |
Whether the event succeeded (1/0) |
error_code |
Failure reason (e.g., invalid token, duplicate, cooldown) |
latency_ms |
API response latency (challenge/siteverify) |
solve_ms |
Solve duration reported by widget |
country |
Detected country (ISO 3166-1 alpha-2) |
asn |
Autonomous System Number (ISP/hosting network) |
ip_hash |
Hashed IP (privacy-safe correlation) |
ua_hash |
Hashed user agent fingerprint |
ip_hash) so you can
correlate abuse without storing raw IPs long-term.
Filters
Use filters to isolate problems quickly. Recommended filters:
- Site (always start here)
- Event (challenge / solve / siteverify / blocked)
- Success (failed only is great for debugging)
- Country / ASN (spot datacenter/bot clusters)
- Time range (last 15m / 1h / 24h)
Common investigations
- Users stuck: filter
solvefailures and checkerror_code - Too many challenges: compare
challengevolume vssolvesuccess rate - Bot wave: group by ASN/country and check failure clustering
Analytics
Use Analytics to track performance and security effectiveness:
- Challenge → Solve conversion rate (higher is better for UX)
- Fail rate per ASN (high fail from datacenters is normal)
- Latency (should remain low; spikes can indicate network issues)
- Top referrers (detect abuse sources / leaked forms)
Troubleshooting
Common issues and their solutions.
Widget Not Appearing
- Verify the widget script is loaded:
<script src="https://captchashield.com/widget.js"> - Check browser console for JavaScript errors
- Ensure
data-sitekeyattribute is set correctly - Verify your domain is authorized in CaptchaShield dashboard
Verification Always Fails
- Invalid Secret Key: Double-check your secret key matches the dashboard
- Token Already Used: Tokens are single-use only. Don't verify the same token twice
- Token Expired: Tokens have a short validity period. Verify immediately after form submission
- Wrong Site Key: Ensure frontend site key matches the secret key's site
- Network Issues: Check firewall rules allow outbound HTTPS to captchashield.com
Common Error Codes
| Error Code | Description | Solution |
|---|---|---|
missing-input-secret |
Secret key not provided | Add secret key to request |
invalid-input-secret |
Secret key is invalid | Verify secret key in dashboard |
missing-input-response |
CAPTCHA token not provided | Ensure token is sent in request |
invalid-input-response |
Token is invalid or expired | Request new CAPTCHA from user |
timeout-or-duplicate |
Token expired or already used | Don't reuse tokens, verify immediately |
Testing & Debugging
// Add console logging to debug widget <script> function onCaptchaSuccess(token) { console.log('CAPTCHA completed:', token); } </script> <div class="captchashield" data-sitekey="YOUR_SITE_KEY" data-callback="onCaptchaSuccess"></div>
FAQ
What is a CAPTCHA token?
A CAPTCHA token (also called captchaToken) is a unique, encrypted string generated by the CaptchaShield widget when a user successfully completes the CAPTCHA challenge. This token is sent to your server and verified through the CaptchaShield API to confirm the user is legitimate.
How long is a CAPTCHA token valid?
Tokens are valid for a short period (typically 2 minutes) and are single-use only. After verification, the token cannot be reused. Always verify tokens immediately upon receipt.
Can I use the same token for multiple verifications?
No. Tokens are single-use only. Each form submission requires a new CAPTCHA completion and generates a new token.
Do I need to verify on both frontend and backend?
No. The widget handles the user interaction on the frontend, but you must only verify server-side. Client-side validation can be bypassed, making server-side verification essential for security.
What themes are available?
CaptchaShield supports three themes:
auto- Matches user's system preferencelight- Light background themedark- Dark background theme
What languages are supported?
Currently supported languages:
auto- Detect from browser languageen- Englishtr- Turkish
More languages are being added regularly.
Can I customize the widget appearance?
The widget uses the theme specified via data-theme. For advanced customization, you can apply CSS to the container, but internal widget styling is managed by CaptchaShield to ensure consistent security and functionality.
How do I add privacy policy links?
Use the optional data attributes:
<div class="captchashield"
data-sitekey="YOUR_SITE_KEY"
data-privacy="https://yoursite.com/privacy"
data-terms="https://yoursite.com/terms"
data-gdpr="https://yoursite.com/gdpr"></div>
Is CaptchaShield GDPR compliant?
Yes. CaptchaShield is designed with privacy in mind and provides options to link to your privacy policy and GDPR information. No personal data is stored without consent, and all processing complies with GDPR requirements.
What happens if the verification API is down?
If the verification endpoint is unreachable, your server should handle it gracefully by rejecting the request and showing a user-friendly error message. Consider implementing retry logic with exponential backoff for transient network issues.
Can I test integration without affecting production?
Yes. Create separate site keys for development and production environments in your CaptchaShield dashboard. Use environment-specific keys in your application configuration.
Support
Need help integrating CaptchaShield or experiencing issues? We're here to assist.
Resources
- Official Documentation
- Dashboard - Manage your sites and keys
- Live Examples - Working code samples
Contact
- Email: [email protected]
- Status Page: status.captchashield.com