Testing
What to check before going live, how to see every outcome on a staging page, and how to test the server check with curl.
No test keys yet
Dedicated test keys that always pass, always hold or always show the puzzle are planned and not available yet. Until they are, test with your real site key on a page that is not your production form. The checks below cover every outcome your code must handle, and each can be produced without special keys.
Drive the widget from the console
Load your staging page, open the console and run the widget by hand. Every event is logged, so you can see the order described on the Browser API page.
// In the browser console on your staging page
otcaptcha.version
// "1.2.1"
otcaptcha.init({ captchaId: '[SITE KEY]' }, (w) => {
window.w = w;
w.onReady(() => console.log('ready')).onSuccess(() => console.log('pass', w.getValidate()))
.onFail((f) => console.log('fail', f)).onClose(() => console.log('close')).onError((e) => console.log('error', e));
});
// then
w.showBox();To see the offline path, block api.otcaptcha.com in the browser's developer tools before calling init: ready still fires after about five seconds and showBox() produces a pass whose lot_number starts with offline. Post that pass to your server: the verify endpoint answers -50306, which is the proof that blocking our domain is not a bypass.
To see a hold on your own page, raise the attempt's score: by default, more than 30 verifications from one address inside a minute cross the rate check, so a short loop of init and showBox() brings the box up. The demo page shows the hold and the puzzle as the visitor sees them, in the browser, without calling the service.
Before going live
Browser
[ ] otcaptcha.version prints the version you expect
[ ] ready fires within 6 seconds of init, on a normal connection and with the API host blocked
[ ] showBox() ends in success with no box, and getValidate() has five non-empty strings
[ ] with the API host blocked, success still fires and lot_number starts with "offline"
[ ] the page's console shows no policy violation from the loader
Server
[ ] a fresh pass answers {"result":"success"}
[ ] the same pass sent again, more than 20 seconds later, answers code -50003
[ ] a pass with one character changed answers -50306
[ ] a pass signed with the wrong secret answers -50002
[ ] an offline pass answers -50306
[ ] a pass confirmed six minutes after success answers -50308
[ ] the verify host blocked at your server: your outage policy does what you chose, and your counter risesThe server rows need a real pass. Take one from the console above with w.getValidate(), and post it with the curl sample or your own code. Change one character of pass_token for the tampered case, and wait six minutes for the expired case.
Browsers
The loader is built for browsers from 2018 onwards: Chrome 70, Safari 12 and their contemporaries. It uses Web Workers and WebAssembly when it can and falls back when it cannot, so an old or locked-down browser is slower, not broken. The current loader has been exercised in headless Chrome by automated tests on every build; real phones, Safari, Firefox and screen readers have not been tested on it yet, and the Arabic and Hindi strings await a native review. Mobile apps that show your page in a web view run the same loader; they have not been tested either.
Testing against a local service
If you are evaluating self-hosting, the service runs on a laptop with the in-memory store and no credentials file: an any-key secret lets it accept every well-formed site key, deriving a secret for each. Point the loader at it with apiServers, and post server checks to the internal listener; the sign_token is skipped for keys that are not in a credentials file. See Self-hosting for the settings.
# Run the service on a laptop against the in-memory store, with any well-formed site key accepted.
OTCAPTCHA_STORE=memory OTCAPTCHA_ANY_ID_SECRET='a-local-only-secret-of-at-least-32-characters' \
OTCAPTCHA_ALLOWED_ORIGINS='*' ./otcaptcha
# Public listener on :8080, server check on :8081, metrics on :9800.