Switching to CDPCaptcha takes two steps: replace the script, then point your server-side verification at our endpoint.
A compatibility mode mounts the widget on the element classes of the old service, so the HTML can stay as it is.
1. Create a sitekey and an API key
Sign up, create a sitekey for the website and an API key for the server.
Both are in your account.
2. Replace the script
Remove the old script tag(s) and add ours with data-compat set to the service you are leaving.
The widget then also mounts on the old element class and names the hidden field like the old service did, so form handlers that read that field keep working until you rename it.
From Friendly Captcha
<!-- remove -->\n<script type="module" src="…/site.min.js" async defer></script>\n<script nomodule src="…/site.compat.min.js" async defer></script>\n\n<!-- add -->\n<link rel="stylesheet" href="https://cdpcaptcha.com/core/assets/css/cdp-captcha.css">\n<script src="https://cdpcaptcha.com/core/assets/js/cdp-captcha.js" data-compat="frc" defer></script>\n\n<!-- keep or rename; both work -->\n<div class="frc-captcha" data-sitekey="YOUR_CDPCAPTCHA_SITEKEY"></div>\n<div class="cdp-captcha" data-sitekey="YOUR_CDPCAPTCHA_SITEKEY"></div>Attribute mapping: data-sitekey, data-start (auto / focus / none), data-theme, lang and data-form-field-name have the same names and values.
Events: frc:widget.complete becomes cdpcaptcha:widget.complete (same for error, expire, reset, statechange);
event.detail.response is the token in both.
Server side: the siteverify request shape is the same (response, optional sitekey, X-API-Key header);
read success and, on failure, error.code.
From reCAPTCHA v2
<!-- remove -->\n<script src="https://www.google.com/recaptcha/api.js" async defer></script>\n\n<!-- add -->\n<link rel="stylesheet" href="https://cdpcaptcha.com/core/assets/css/cdp-captcha.css">\n<script src="https://cdpcaptcha.com/core/assets/js/cdp-captcha.js" data-compat="recaptcha" defer></script>\n\n<!-- the element can stay; the hidden field is named g-recaptcha-response -->\n<div class="g-recaptcha" data-sitekey="YOUR_CDPCAPTCHA_SITEKEY"></div>On the server replace the call to siteverify at google.com with ours: send the field as response and your API key in the X-API-Key header instead of the secret parameter.
Read success.
data-size, data-callback and the grecaptcha JavaScript object have no equivalent;
use our events instead.
Invisible reCAPTCHA corresponds to data-start="auto".
From hCaptcha
<!-- remove -->\n<script src="https://js.hcaptcha.com/1/api.js" async defer></script>\n\n<!-- add -->\n<link rel="stylesheet" href="https://cdpcaptcha.com/core/assets/css/cdp-captcha.css">\n<script src="https://cdpcaptcha.com/core/assets/js/cdp-captcha.js" data-compat="hcaptcha" defer></script>\n\n<div class="h-captcha" data-sitekey="YOUR_CDPCAPTCHA_SITEKEY"></div>The hidden field is named h-captcha-response in compatibility mode.
Replace the server call to hcaptcha.com/siteverify with ours as described above.
3. Switch the server-side check
# before (any of the three services)
POST https://<old-service>/siteverify secret=… response=…
# after
POST https://cdpcaptcha.com/api/v1/siteverify
X-API-Key: ck_YOUR_API_KEY
response=… sitekey=YOUR_CDPCAPTCHA_SITEKEY4. Clean up
Once everything works, rename the element class to cdp-captcha, drop data-compat, and read the field cdp-captcha-solution.
Remove the old service from your CSP and privacy notice.
Comparison
| Topic | CDPCaptcha | Friendly Captcha v2 | reCAPTCHA v2 | hCaptcha |
|---|---|---|---|---|
| Visitor task | none (proof of work) | none (proof of work) | picture puzzles | picture puzzles |
| Cookies / tracking | none | none | Google cookies | yes |
| Hosting | self-hosted or CTPF | SaaS (EU option) | SaaS | |
| Element class | cdp-captcha | frc-captcha | g-recaptcha | h-captcha |
| Hidden field | cdp-captcha-solution | frc-captcha-response | g-recaptcha-response | h-captcha-response |
| Server auth | X-API-Key | X-API-Key | secret | secret |
