Home  ›  Open source  ›  AOCaptcha

Prove you're human by the way you move.

AOCaptcha is a self hosted, drag and drop CAPTCHA for PHP. A visitor nudges a shape into place, and your server weighs the whole motion that got it there, not just where it landed. No third party, nothing phoning home.

Self hosted No third party calls Free under GPL-3.0
0
Built in shapes to draw a challenge from, extensible in config.
0
Parametric shape families, from polygons and stars to gears.
0
Third party calls. Every challenge and check stays on your server.
0
Checks on every solve: where it landed, and how it got there.

Four steps, and the answer never leaves your server.

The visitor only ever sees a shape to drag. Everything that decides human or bot happens in your own code, with the correct answer held server side the whole way through.

01

Challenge

The server picks a shape, a target and a starting spin, and keeps the answer to itself.

02

Drag

The visitor drags the piece into place while the widget records the whole path, roughly a point every 25 milliseconds.

03

Snap

Once the piece is close enough it snaps home, and the full motion trace is sent to your verify endpoint.

04

Verify

The server checks the drop against the stored target, then scores the motion. Only a solve that is right and human earns a one time token.

It judges the gesture, not just the destination.

A bot can drop a piece in the right place. What it struggles to fake is the messy, human way a real hand gets it there. AOCaptcha scores that motion before it trusts the solve.

Path curvature

Real hands rarely travel in a perfect line. A dead straight drag is a tell.

Speed variance

People speed up and slow down as they go, so a perfectly constant velocity reads as a script.

Direction corrections

Humans overshoot and nudge back. That self correction is hard to fake.

Acceleration noise

Organic micro jitter in the motion data that a clean synthetic drag lacks.

Drop position

The piece still has to land within tolerance of the target it was never shown.

No lockout on a miss

If a solve fails, a fresh challenge is issued, so a real person is never shut out.

Three small pieces, no framework required.

An endpoint to serve and verify challenges, a container in your form, and one check on submit. Plain PHP 8.1+ and vanilla JavaScript, installed with Composer and npm or just copied in.

One config file, and it wears your brand.

Colours, fonts, radii, the piece size and the whole shape pool live in a single JSON file, each mapped to a CSS custom property. Override the theme at runtime for per tenant styling, no rebuild needed.

What is in the box.

Run composer require weanteomnio/aocaptcha and here is what you actually get. No account, no API key, no database unless you want one.

Drop-in PHP core

CaptchaHandler, Challenge and BehaviorAnalyzer. Plain PHP 8.1+, and you can wire it without Composer.

Storage adapters

Session and Redis out of the box, or implement the interface and bring your own.

The widget

A vanilla JavaScript widget with no framework, shipped as both UMD and ESM builds.

One stylesheet

A single stylesheet driven entirely by CSS variables, so it wears your brand with no overrides.

A library of shapes

421 shapes across nine parametric families to draw challenges from, all listed in config.

A real test suite

21 PHPUnit tests and 653 assertions covering challenge generation, storage and the motion scoring.

One config file

Shapes, colours, fonts and sizing in a single JSON file, each mapped to a CSS variable.

Zero dependencies

Nothing to pull in from outside, and nothing that phones home once it is running.

The hard parts are decided where a bot cannot see.

The client is only ever handed a puzzle to draw. Every judgement, and the answer itself, stays in your process.

Answer stays server side

The correct drop position is stored on the server and never sent to the browser.

Behaviour is scored

A positionally correct but mechanically synthetic drag is rejected, not trusted.

One time tokens

A pass token is deleted the moment it is read and compared, so it cannot be replayed.

Short lived state

Challenges expire in minutes and tokens soon after, both tunable to your needs.

No stale caching

Explicit no store and CDN surrogate headers stop a proxy serving an old challenge.

No external calls

Nothing leaves your server, so there is no vendor outage and no data to share.

Open, honest, and still early.

AOCaptcha is young. The PHP core is tested and the security model is deliberate, but it has not yet been battle tested across thousands of sites, and a couple of things are honestly still missing.

It is free under GPL-3.0 with no lock in. Read it, run it, fork it, and if you find a gap, the issues are open.

Self hosted, no lock in

Runs entirely on your own server. No account, no metering, nothing to rent.

Tested PHP core

21 PHPUnit tests and 653 assertions cover challenge generation, storage and the motion scoring thresholds.

Keyboard fallback is not there yet

The challenge is drag only today, so it is not usable by keyboard alone. Until that lands, pair it with a honeypot or keep an accessible path open for forms that must reach everyone.

JavaScript tests still to come

The front end is not yet covered by automated tests. It is on the list, and contributions are welcome.

Want a form that keeps bots out, cleanly?

AOCaptcha is one of the tools we reach for. If you have a site or a form that needs protecting without handing visitors to a third party, the next step is a short call with the person who would build it.