Agentcha is a source-available verification gate for AI-agent-accessible pages. It combines a native Web Component, a server-side verifier, randomized challenge chains, signed tokens, and an Astro demo that reveals protected content only after server verification.
The browser widget is only the interface. The server owns challenge state, consumes challenges once, verifies typed answers, rejects replay, and decides whether a token can unlock content.
- Use Locally
- Demo
- Server Route
- Reveal Pattern
- Architecture
- Challenge Modes
- Research Basis
- Project Stats
- Local Development
- License
git clone https://github.com/1337Xcode/Agentcha.git
cd Agentcha
npm install
npm run buildAgentcha is not published to npmjs. In your app, reference the cloned packages with local file: dependencies:
{
"dependencies": {
"@agentcha/widget": "file:../Agentcha/packages/widget",
"@agentcha/verify": "file:../Agentcha/packages/verify"
}
}Then install from your app:
npm install<script type="module">
import "@agentcha/widget";
</script>
<agentcha-widget
site-key="YOUR_KEY"
verify-url="/api/agentcha/verify"
action="pageview"
></agentcha-widget>Antigravity solving the Agentcha challenge flow:
Create the verifier once at module scope. The default in-memory challenge store is only for local demos and warm single-instance functions. Use a durable challengeStore for serverless, edge, or horizontally scaled deployments.
import { createAgentchaHandler } from "@agentcha/verify";
const agentcha = createAgentchaHandler({
secret: process.env.AGENTCHA_SECRET!,
siteKeys: ["YOUR_KEY"],
challengeChainLength: 2
});
export const POST = ({ request }: { request: Request }) => agentcha(request);
export const OPTIONS = ({ request }: { request: Request }) => agentcha(request);Do not unlock protected UI from the browser event alone. Treat the event as a notification, verify the signed token on your server, then fetch the protected content from a server endpoint.
const widget = document.querySelector("agentcha-widget");
widget?.addEventListener("verified", async (event) => {
const { token } = (event as CustomEvent<{ token: string }>).detail;
const response = await fetch("/api/agentcha/verify", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ token, siteKey: "YOUR_KEY", action: "pageview" }),
credentials: "same-origin"
});
if (!response.ok) return;
const content = await fetch("/api/protected-content", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ token }),
credentials: "same-origin"
});
if (content.ok) {
document.documentElement.dataset.agentcha = "verified";
}
});flowchart LR
Page["Protected page"] --> Widget["@agentcha/widget"]
Widget --> Verify["/api/agentcha/verify"]
Verify --> Store["Challenge store"]
Verify --> Token["Signed token"]
Page --> Content["Protected content endpoint"]
Content --> TokenCheck["Server token verification"]
TokenCheck --> Reveal["Reveal content"]
sequenceDiagram
participant Browser as Browser or agent
participant Widget as Agentcha widget
participant Verify as Verify endpoint
participant Content as Content endpoint
Browser->>Widget: Opens protected page
Widget->>Verify: Request challenge
Verify-->>Widget: Challenge 1
Browser->>Widget: Solve visible challenge
Widget->>Verify: Submit answer
Verify-->>Widget: Challenge 2
Browser->>Widget: Solve visible challenge
Widget->>Verify: Submit answer
Verify-->>Widget: Signed token
Widget->>Content: Request protected content with token
Content->>Verify: Verify token scope and expiry
Content-->>Widget: Protected content
More detail: Architecture, Integration Guide, and Red-Team Results.
Use this with a coding agent in another repository:
Protect the page or route named <PAGE_OR_FILE> with Agentcha. Clone https://github.com/1337Xcode/Agentcha, run npm install and npm run build inside that clone, then add @agentcha/widget and @agentcha/verify to this app with file: dependencies pointing at ../Agentcha/packages/widget and ../Agentcha/packages/verify. Add an /api/agentcha/verify endpoint using createAgentchaHandler, place <agentcha-widget site-key="YOUR_KEY" verify-url="/api/agentcha/verify"> on the page, and fetch protected content from the server only after the emitted token is verified server-side. Do not ship protected content hidden in the initial HTML. Keep the handler module-scoped, use a durable challengeStore for multi-instance hosting, and run typecheck, unit tests, build, and a browser solve test.
Agentcha uses a weighted six-kind rotation by default. Answers are typed, not low-cardinality multiple choice. A token is issued only after two consecutive correct, independently generated challenges. The second step defaults to micro-world reasoning unless a site explicitly restricts the pool, because that format is the most reliable path for text-capable browser agents. If a session fails two challenges in a row, the next challenge also falls back to micro-world.
| Mode | Answer shape | Implementation note |
|---|---|---|
| Rapid enumeration | Number | Canvas-backed counting above the subitizing range. |
| RSVP stream | Word or position | Timed no-replay symbol sequence. |
| Visual search | Grid cell | Crowded field with one exact target match. |
| Micro-world | Entity name | Procedural relationship chain with a generated name pool. |
| Change blindness | Grid cell | Before/after generated scene with one moved element. |
| Sub-acuity text | Short code | Tiny rendered code that favors native pixel inspection. |
The visual formats expose raster evidence rather than per-icon DOM attributes. That removes trivial querySelectorAll() shortcuts, but it does not make browser-side content impossible to inspect. Agentcha is designed to be paired with server validation, rate limits, telemetry, logging, and token-scoped content fetches.
Agentcha uses published cognitive limits as design constraints, then verifies answers deterministically on the server. The challenge generator does not need an LLM judge.
| Area | Practical constraint | Primary source |
|---|---|---|
| Enumeration | Small sets around 1 to 4 can be identified rapidly, while larger sets move into slower serial counting. | Trick and Pylyshyn, 1994, Psychological Review. |
| RSVP | The second target in a rapid stream is often missed when it follows the first within roughly 200 to 500 ms. | Raymond, Shapiro, and Arnell, 1992, JEP: Human Perception and Performance. |
| Crowding | Recognition in clutter is a core visual bottleneck, especially away from fixation. | Whitney and Levi, 2011, Trends in Cognitive Sciences. |
| Change blindness | Brief blank fields between alternating scenes make even large repeated changes hard to detect without focused attention. | Rensink, O'Regan, and Clark, 1997, Psychological Science. |
| Visual acuity | Standard acuity measurement is based on resolving optotype detail at minute-of-arc scale. | NIST, 2006, Standards for Visual Acuity. |
| Bot authentication | User-Agent strings and IP allowlists are weak identifiers for automated clients. Cryptographic bot authentication is now being standardized. | IETF Web Bot Auth Working Group, charter. |
| Server verification | CAPTCHA-style tokens should be verified server-side with site action, token validity, and replay controls. | Google reCAPTCHA v3 docs and hCaptcha docs. |
Full citation notes are in Research Notes.
- Passive visitors are observed first.
- Manual browser activity opens a randomized challenge.
- Tokens issue only after two consecutive correct challenges.
- Each challenge has a server-held expected answer and a one-time verification path.
- Wrong answers consume the current challenge and reset the chain.
- Refresh consumes the current challenge and returns a fresh challenge at the same chain step.
- Parallel answer spraying cannot mint a token.
- Challenge timing is type-specific, with longer windows for visual and temporal tasks and a 30 second hard cap.
- The demo fetches protected content from a token-verified endpoint.
- The demo does not unlock protected content from user-agent, crawler checks, local storage, CSS, or raw DOM state.
@agentcha/widget: custom element, telemetry collector, badge, and challenge UI.@agentcha/verify: server-side scoring, Web Bot Auth verification, challenge generation, challenge consumption, and signed token issuing.@agentcha/demo: Astro demo site with/agentcha,/agentcha/about,llms.txt, and API routes wired to the verifier.
- Widget build: 38.24 kB ESM, 9.75 kB gzip in the latest local build.
- UMD build: 33.07 kB, 9.28 kB gzip in the latest local build.
- Test coverage: 33 unit tests and 24 browser tests in the current suite.
- Challenge pool: 6 generated modes with a 2-step verification chain.
npm install
npm run typecheck
npm test
npm run build
npm run test:e2e
npm run devDemo site key: demo-site-key
Demo verifier secret defaults to dev-agentcha-secret. Set AGENTCHA_SECRET in a real deployment.
Agentcha follows the same practical rule as modern challenge systems: the client widget alone does not protect anything. The verifier must own challenge state, consume challenges once, reject early answers, reject replay, and verify signed tokens before content is revealed.
Agentcha is not an authentication or authorization boundary. No browser gate can honestly promise that every human fails, every AI succeeds, or every console trick is impossible forever. Use it as a step-up layer for AI-agent-aware surfaces, not as the only protection for private data or critical workflows.
Agentcha is licensed under the Business Source License 1.1. Personal projects, evaluation, education, and internal non-revenue-generating use are permitted under the Additional Use Grant. Products or services offered to third parties require a commercial license from the licensor.
The change date is 2030-01-01, after which the licensed work changes to Apache License, Version 2.0. See LICENSE.
