The Three-Actor Model

Most bot detection systems classify sessions as either human or bot. That model is outdated. Nyasa introduces a third actor: AuthorizedAgent. This is an AI agent acting legitimately on behalf of a real user—like a shopping assistant or fintech integration. Blocking these agents means turning away real business.

Nyasa classifies every session as exactly one of:

  • Human: no detection rules fired
  • AuthorizedAgent: holds a valid cryptographic identity claim, automatically bypasses bot rules
  • UnauthorizedBot: one or more detection rules fired

The AuthorizedAgent category is the real addition. An AI shopping assistant should not have to pass a CAPTCHA. It presents a signed identity claim, and Nyasa recognizes it.

The Signal Stack: 24 Signals Across Three Layers

Behavioral Signals (13)

SignalWhat it measures
Keystroke dwell and flight timeHow long keys are held, time between keystrokes
Mouse path curvatureDeviation from straight-line movement
Paste vs typed ratioWhether text was typed character by character or bulk-pasted
Click precision (center offset)Distance from click point to element center
Session burst-pause rhythmAlternation between fast activity and idle gaps
Backspace correctionsCorrection frequency during text input
Scroll depthHow far down the page a session goes
Touch mechanicsMulti-touch patterns and pressure distribution
Field-level timingTime spent on each form field before moving on
Input originTyped vs pasted vs dropped vs programmatic fill
Tab visibilityWhether the session loses and regains focus
File upload mechanicsHow files are attached (drag, click, or programmatic)
Session rhythmOverall pace and structure of the session

Fingerprint Signals (8)

  • Webdriver and CDP markers
  • Iframe vs parent plugin consistency
  • Canvas fingerprint hash
  • WebGL renderer string (SwiftShader and LLVMpipe detection)
  • Audio fingerprint via OfflineAudioContext
  • Incognito detection via storage quota probe
  • Timezone vs navigator.language consistency
  • Persistent device UUID with isNew flag

Network Signals (3)

  • Page reaction time (time from page load to first interaction)
  • Connection type (from Navigator API)
  • Page load timing (Performance timing breakdown)

Detection Rules: Six Rules That Fire Independently

  1. isHeadless: Reads fingerprint layer for automation markers: webdriver properties, CDP exposure, WebGL renderer strings like SwiftShader or LLVMpipe, iframe/parent inconsistencies.
  2. isScripted: Reads behavioral signals for bot-like input patterns: fields filled in milliseconds, no backspace, perfect field sequence.
  3. isLLMAgent: The hardest rule. Seven signals evaluated together (see below).
  4. isAuthorizedAgent: Reads window.__nyasaAgentSignature or a meta tag. If valid, session is AuthorizedAgent and no other rules run.
  5. isUploadAutomation: Checks file upload mechanics. Human uploads use file picker or drag; programmatic uploads bypass both.
  6. isMultimodalBot: Looks for cross-signal contradictions. Reads sibling DetectionResults to catch near-miss compositions.

isLLMAgent Deep Dive

LLM agents are genuinely hard to distinguish from fast, focused humans. Seven signals are evaluated together:

  • Machine-speed keystroke bursts under 20ms: Human dwell times cluster around 80-200ms.
  • Mouse stillness above 70%: Humans move the mouse constantly; LLM-driven sessions often keep the cursor parked.
  • Uniform keystroke variance near zero: Human typing has natural rhythm variation; LLM agent keystrokes have suspiciously consistent intervals.
  • Zero backspace rate: Humans make corrections. An agent filling a form it computed upfront doesn't backspace.
  • Pixel-perfect click precision: Humans click near the center but not exactly on it; agents click at the computed center coordinate.
  • Missing field exploration: Humans often click into a field, leave, return, re-read the label. LLM agents visit each field once in sequence and move on.
  • No idle micro-pauses: Humans have sub-second pauses between thoughts. Agent sessions show continuous forward progress.

No single signal is definitive. isLLMAgent requires several of these signals to align before it fires.

Feature Extraction Layer

Early versions had each detection rule computing its own derived metrics, causing duplicated math and divergence. The feature extraction layer runs once per session and computes 8 shared derived metrics before any detection rule evaluates. Every rule reads from the same computed values, ensuring consistency.

Verdict System

Every session gets a verdict object:

interface NyasaVerdict {
  type: 'Human' | 'AuthorizedAgent' | 'UnauthorizedBot';
  confidence: number;           // 0.0 to 1.0
  badges: DetectionBadge[];     // which rules fired or nearly fired
}

Confidence is a noisy-OR score across all active rules. If one rule fires with 0.8 confidence and a second fires with 0.6, the combined score is 1 - (1 - 0.8) * (1 - 0.6) = 0.92. Badge labels tell you which rules contributed.

The verdict payload ships via navigator.sendBeacon. Non-blocking, fires after the page interaction completes, survives page unload.

Architecture and Installation

The SDK runs entirely in the browser. Signals are collected passively as the session progresses. Feature extraction runs on a timer and on key events. Detection rules evaluate when a verdict is requested or automatically at session end.

Nyasa ships as both ESM and IIFE from a single tsup build config.

ESM for bundlers:

import { createNyasa } from '@devanshhq/nyasa';
const nyasa = createNyasa({
  endpoint: 'https://your-backend.com/nyasa',
  agentBypass: true,
});
nyasa.start();

IIFE for script tags:



Installation:

npm install @devanshhq/nyasa

Minimal setup:

import { createNyasa } from '@devanshhq/nyasa';
const nyasa = createNyasa({
  endpoint: '/api/session-verdict',
});
nyasa.start();
const verdict = await nyasa.getVerdict();
console.log(verdict.type);       // 'Human' | 'AuthorizedAgent' | 'UnauthorizedBot'
console.log(verdict.confidence); // 0.0 - 1.0
console.log(verdict.badges);     // ['isHeadless', 'isLLMAgent', ...]

Agent Bypass

If you're building an AI agent that needs to interact with Nyasa-protected pages, set the signature before the SDK initializes:

window.__nyasaAgentSignature = {
  token: 'signed-jwt-from-your-auth-server',
  agentId: 'shopping-assistant-v2',
  issuedAt: Date.now(),
};

Or via meta tag:

The isAuthorizedAgent rule reads this claim, validates the signature, and short-circuits to AuthorizedAgent.

What It Catches That Others Miss

Traditional fingerprinting misses LLM agents because they run in real browsers with patched automation markers. Traditional behavioral analytics miss them because modern LLM agents have realistic typing cadence. Nyasa catches them through the combination: machine-speed micro-bursts that no human produces, combined with zero backspace rate and pixel-perfect clicks. Any one signal has false positives. All three together don't.

Try It