Behavioral Scoring
Cerno’s behavioral scoring uses deterministic math — no ML on the hot path. Pure statistical thresholds against known human distributions.
Public features
The client SDK extracts 7 behavioral features from raw pointer events:
| Feature | What it measures |
|---|---|
velocity_std | Speed variance across the trace |
path_efficiency | Euclidean vs. actual path distance |
pause_count | Hesitations over 100ms |
movement_onset_ms | Reaction time before first move |
jerk_std | Third derivative of position |
angular_velocity_entropy | Randomness in direction changes |
timing_cv | Coefficient of variation of inter-event timing |
All features are re-extracted server-side from raw events. The client cannot lie about them.
Scoring
Each feature is scored against baselines. Features are combined via weighted average with penalties for suspicious patterns. The server also computes additional secret features not present in client code — see Secret Features.
Maze-relative baselines
Published mouse-movement baselines assume free-form movement. A maze constrains the path. A human solving an easy 4x4 maze behaves differently than one solving a complex 12x12.
Cerno computes a MazeProfile for each generated maze and derives expected feature ranges from the maze structure. This prevents false rejections on easy mazes and missed bots on hard ones.
Penalties
- Low sample count — not enough pointer data is suspicious
- Fast completion — humans don’t solve mazes instantly
Threshold
Default: 0.6 (configurable via ScoringConfig). Adjust based on your use case.
Runtime configuration
Use ScoringConfig to override baselines and scoring parameters at runtime:
const config: ServerConfig = { secret: process.env.CERNO_SECRET!, store: new MemoryStore(), scoring: { gaussianK: 3, publicScoreWeight: 0.7, secretScoreWeight: 0.3, },}See the Server SDK guide for full configuration options.