CAPTCHA proves you're human. HATCHA proves you're not.
HATCHA (Hyperfast Agent Test for Computational Heuristic Assessment) is a reverse CAPTCHA that gates access behind challenges trivial for AI agents but painful for humans — large-number multiplication, string reversal, binary decoding, and more.
- Server-side verification — answers never reach the client. HMAC-signed tokens, stateless, no database required.
- 5 built-in challenge types — math, string reversal, character counting, sorting, binary decode.
- Extensible — register custom challenge generators at runtime.
- Themeable — dark, light, or auto mode via CSS custom properties.
- Framework adapters — Next.js App Router and Express middleware out of the box.
npm install @mondaycom/hatcha-react @mondaycom/hatcha-server// app/api/hatcha/[...hatcha]/route.tsimport{createHatchaHandler}from"@mondaycom/hatcha-server/nextjs";consthandler=createHatchaHandler({secret: process.env.HATCHA_SECRET!,});exportconstGET=handler;exportconstPOST=handler;// app/layout.tsximport{HatchaProvider}from"@mondaycom/hatcha-react";import"@mondaycom/hatcha-react/styles.css";exportdefaultfunctionRootLayout({ children }){return(<htmllang="en"><body><HatchaProvider>{children}</HatchaProvider></body></html>);}"use client";import{useHatcha}from"@mondaycom/hatcha-react";functionAgentModeButton(){const{ requestVerification }=useHatcha();return(<buttononClick={()=>requestVerification((token)=>{console.log("Agent verified!",token);})}>
Enter Agent Mode
</button>);}# .env.local
HATCHA_SECRET=your-random-secret-hereClient Server
│ │
│ GET /api/hatcha/challenge │
│────────────────────────────────►│
│ │ Generate challenge
│ │ Hash answer
│ │ HMAC-sign { hash, expiry }
│ { challenge (no answer), token }
│◄────────────────────────────────│
│ │
│ Agent solves the challenge │
│ │
│ POST /api/hatcha/verify │
│ { answer, token } │
│────────────────────────────────►│
│ │ Verify HMAC signature
│ │ Check expiry
│ │ Compare answer hash
│ { success, verificationToken } │
│◄────────────────────────────────│
The answer never reaches the client. The signed token is opaque and contains only a hashed answer + expiry. Verification is stateless — no database needed.
| Type | Icon | What it does | Time limit |
|---|---|---|---|
math | × | 5-digit × 5-digit multiplication | 30 s |
string | ↔ | Reverse a 60–80 character random string | 30 s |
count | # | Count a specific character in ~250 characters | 30 s |
sort | ⇅ | Sort 15 numbers, return the k-th smallest | 30 s |
binary | 01 | Decode binary octets to ASCII | 30 s |
import{registerChallenge}from"@mondaycom/hatcha-server";registerChallenge({type: "hex",generate(){constn=Math.floor(Math.random()*0xffffff);return{display: {type: "hex",icon: "0x",title: "Hex Decode",description: "Convert this hex number to decimal.",prompt: `0x${n.toString(16).toUpperCase()}`,timeLimit: 30,answer: String(n),},answer: String(n),};},});HATCHA uses CSS custom properties scoped under --hatcha-*. Override them on any parent element:
[data-hatcha-theme] {
--hatcha-accent:#3b82f6;
--hatcha-accent-light:#60a5fa;
--hatcha-bg:#060b18;
--hatcha-fg:#e4eaf6;
--hatcha-success:#22c55e;
--hatcha-danger:#ef4444;
}Pass theme="dark", theme="light", or theme="auto" to <HatchaProvider> or <Hatcha>.
importexpressfrom"express";import{hatchaRouter}from"@mondaycom/hatcha-server/express";constapp=express();app.use(express.json());app.use("/api/hatcha",hatchaRouter({secret: process.env.HATCHA_SECRET!}));app.listen(3000);| Package | Description |
|---|---|
@mondaycom/hatcha-core | Challenge generation and cryptographic verification |
@mondaycom/hatcha-react | React component, provider, and styles |
@mondaycom/hatcha-server | Next.js and Express server handlers |
git clone https://github.com/mondaycom/HATCHA.git
cd HATCHA
pnpm install
pnpm build
cd examples/nextjs-app
pnpm devContributions are welcome! See CONTRIBUTING.md for setup instructions and guidelines.
