The short version

Gaitcha is a self-hosted behavioral captcha. The JavaScript client collects a small interaction log. The PHP server validates a signed token and scores that log. An optional proof-of-work challenge adds computation before the server issues a token.

No external captcha API makes the decision. The library is framework-independent; Gaitcha for WordPress supplies the CMS and form-builder integrations.

From interaction to decision

  1. A placeholder appears. It reserves the widget’s space without exposing a token or random field name.
  2. An interaction starts initialization. Mouse movement, touch, focus or keyboard activity triggers the same-origin init request.
  3. Proof of work runs, when enabled. A Web Worker solves a signed SHA-256 challenge. A chunked main-thread fallback exists if the worker cannot run.
  4. The server issues the widget payload. It includes a random field name and an HMAC-signed token with an expiry.
  5. The visitor checks the box. The client freezes and serializes the interaction log, including for AJAX form builders.
  6. The server validates the submission. Token checks and behavioral scoring determine acceptance. A visual checkmark alone is not a server verdict.

Three interaction profiles

Mouse: trajectory changes, speed variation, direction reversals, slowing near the checkbox and click offset contribute signals. Additional checks examine synthetic-looking event patterns.

Keyboard: tab navigation, time between focus and activation, key dwell times and timing variation contribute signals. Use the actual keyboard path when testing an integration.

Touch: movement, tap offset and, where the device exposes them, pressure and contact-radius variation contribute signals.

The primary profile follows the check event. If another profile has usable data, the scorer can consider it too. Certain implausible patterns trigger an immediate rejection.

Why add proof of work?

Proof of work requires the client to solve a signed challenge before obtaining a token. This adds a computational cost to repeated automated requests. The bundled JavaScript client handles the calculation in the background.

The default difficulty is 18 bits. Device speed and browser conditions affect completion time. Test slower devices before increasing the difficulty.

Pair proof of work with anti-replay and a token store. Otherwise, a solved challenge can be reused until it expires.

Defaults that matter

SettingPHP coreWordPress plugin
Behavioral scoringEnabledEnabled
Proof of workOff unless configuredOn by default
Anti-replayOff unless configuredOn by default
Replay storageBring a token storeWordPress options
Native WordPress protectionNot applicableOpt in per form

The default token lifetime is 120 seconds and the default score threshold is 0.5. Tokens can be refreshed by the client; cache rules must not serve a shared init response.

Limits and accessibility

Client-side interaction data can be fabricated, so targeted automation can still pass verification. Proof of work adds computational cost; it does not prove that a visitor is human. Use Gaitcha alongside rate limiting and your application’s usual validation.

Before launch, test your forms with keyboard navigation, mobile devices and assistive technology. Provide a useful retry and a way to contact you if verification fails.

JavaScript is required by default. no_js_fallback: 'allow' accepts submissions without a token, including automated submissions. Keep 'reject' if every submission must pass verification.

Read the PHP integration guide and the privacy explanation. The implementation is available in the core repository.

A question or an edge case?

Start a conversation on GitHub