Agentcha is split into a browser widget and a server verifier. The browser renders challenges and records interaction telemetry. The server owns trust decisions.
flowchart TB
subgraph Client
Page["Protected page"]
Widget["@agentcha/widget"]
Badge["Protected by Agentcha badge"]
end
subgraph Server
Verify["Verifier endpoint"]
Store["Challenge store"]
Signer["Token signer"]
Content["Protected content endpoint"]
end
Page --> Widget
Widget --> Badge
Widget --> Verify
Verify --> Store
Verify --> Signer
Page --> Content
Content --> Signer
sequenceDiagram
participant B as Browser or agent
participant W as Widget
participant V as Verifier
participant S as Challenge store
participant C as Content endpoint
B->>W: Page interaction
W->>V: Challenge request with site key and action
V->>S: Store expected answer and timing
V-->>W: Public challenge
B->>W: Typed answer
W->>V: Submit answer and telemetry
V->>S: Consume challenge
alt First correct answer
V-->>W: Next challenge in chain
else Second correct answer
V-->>W: Signed token
W->>C: Request content with token
C->>V: Verify token scope
C-->>W: Protected content
else Wrong or replayed answer
V-->>W: Fresh challenge and reset chain
end
flowchart LR
DOM["DOM state"]:::weak -->|not trusted| Server["Server decision"]
LocalStorage["localStorage"]:::weak -->|not trusted| Server
Event["verified event"]:::weak -->|notification only| Server
Token["Signed token"]:::strong -->|verified server-side| Server
Store["One-time challenge state"]:::strong --> Server
classDef weak fill:#fff7ed,stroke:#c2410c,color:#111827
classDef strong fill:#ecfdf5,stroke:#047857,color:#111827
The widget can improve UX and raise the cost of casual bypass, but it cannot make browser-side data private. Protected content must be fetched from a server endpoint after token verification.
- The verifier creates a challenge with a server-held expected answer.
- The public challenge omits the expected answer and any hidden answer field.
- The client waits until the answer readiness window.
- The verifier consumes the challenge on answer submission.
- A wrong answer, replay, expired challenge, or spray attempt resets the chain.
- Two consecutive correct challenges issue a signed token.
- The content endpoint verifies the token and consumes the token ID where practical.
packages/widget
src/agentcha-widget.ts Web Component, modal, badge, telemetry
src/telemetry.ts Browser interaction signal collection
packages/verify
src/handler.ts Request handler, chain state, token flow
src/challenge.ts Challenge generation
src/token.ts Signed token creation and verification
src/webBotAuth.ts Web Bot Auth helper logic
templates/ Edge and serverless examples
apps/demo
src/pages/agentcha.astro Demo protected route
src/pages/api/agentcha Verify and content endpoints
- Use a durable challenge store when traffic can hit more than one server instance.
- Keep
AGENTCHA_SECRETserver-only. - Rate-limit challenge issuance and answer submission per session and IP.
- Log challenge type, result, timing, and reset reason.
- Treat Web Bot Auth as additive identity signal, not a replacement for challenge verification.