npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@axeptio/behavior-detection

v1.0.0

Published

Lightweight behavior detection library to assess human likelihood of user sessions

Downloads

95

Readme

@axeptio/behavior-detection

Lightweight, privacy-first behavior detection library to distinguish human users from automated bots

TypeScript Tree-shakeable

A sophisticated JavaScript library that analyzes user behavior patterns to determine if interactions are human-like or bot-like. Unlike traditional CAPTCHA systems, this library works silently in the background, providing a seamless user experience while offering robust bot detection capabilities.

✨ Features

  • 🎯 High Accuracy: Multi-strategy detection approach with configurable weights
  • 🌲 Tree-shakeable: Import only the strategies you need
  • 🚀 Zero Dependencies: Lightweight and fast (< 15KB minified)
  • 📱 Cross-platform: Works on desktop and mobile browsers
  • 🔒 Privacy-first: All processing happens client-side, no data sent to servers
  • ⚡ Real-time: Continuously monitors and scores user behavior
  • 🎨 Framework Agnostic: Works with vanilla JS, React, Vue, Angular, etc.
  • 📦 Multiple Build Formats: ESM, CommonJS, and IIFE (browser CDN)
  • 🧪 Battle-tested: Comprehensive adversarial testing against Playwright, Puppeteer, and Selenium

🎬 Demo

Test Harness Screenshot

Try the interactive test harness locally:

npm run tryme

This will build the library and open the comprehensive test harness in your browser, showing real-time detection scores and visualizations as you interact with the page.

Demo Files:

  • demos/test-harness.html - Full-featured interactive test harness with real-time graphs
  • demos/browser-demo.html - Simple CDN usage example with auto-initialization
  • demos/example.html - Strategy-based usage example with detailed visualizations

📦 Installation

NPM/Yarn

npm install @axeptio/behavior-detection
# or
yarn add @axeptio/behavior-detection

CDN (Browser)

<script src="https://static.axept.io/behavior-detector.latest.js"></script>

🚀 Quick Start

Strategy-based Usage (Recommended)

Import only the strategies you need for optimal bundle size:

import { BehaviorDetector, Mouse, Click, Keyboard } from '@axeptio/behavior-detection';

const detector = new BehaviorDetector()
  .addStrategy(new Mouse())
  .addStrategy(new Click())
  .addStrategy(new Keyboard());

// Start tracking
detector.start();

// Get score (0 = bot-like, 1 = human-like)
const result = await detector.score({ breakdown: true });
console.log('Human likelihood:', result.score);
console.log('Breakdown:', result.breakdown);

// Stop tracking when done
detector.stop();

Browser CDN Usage

<!DOCTYPE html>
<html>
<head>
  <title>Bot Detection Demo</title>
</head>
<body>
  <h1>Interact with this page</h1>
  <button>Click me</button>
  <input type="text" placeholder="Type something...">

  <script src="https://static.axept.io/behavior-detector.latest.js"></script>
  <script>
    // Configure before the script loads (or call init after)
    window.bdSettings = {
      autoStart: true,
      checkMs: 2000, // Check every 2 seconds
      onScore: (result) => {
        console.log('Score:', result.score);
      },
      ifBot: (result) => {
        console.warn('Bot detected!', result.score);
        // Take action: show CAPTCHA, limit features, etc.
      },
      ifHuman: (result) => {
        console.log('Human confirmed!', result.score);
      },
      botThreshold: 0.3,  // Below this = bot
      humanThreshold: 0.7 // Above this = human
    };
  </script>
</body>
</html>

Framework Examples

React

import { useEffect, useRef } from 'react';
import { BehaviorDetector, Mouse, Click, Scroll } from '@axeptio/behavior-detection';

function App() {
  const detectorRef = useRef<BehaviorDetector>();

  useEffect(() => {
    const detector = new BehaviorDetector()
      .addStrategy(new Mouse())
      .addStrategy(new Click())
      .addStrategy(new Scroll());

    detector.start();
    detectorRef.current = detector;

    // Check score periodically
    const interval = setInterval(async () => {
      const result = await detector.score();
      if (result.score < 0.3) {
        console.warn('Bot detected!');
        // Show CAPTCHA or take other action
      }
    }, 3000);

    return () => {
      clearInterval(interval);
      detector.stop();
    };
  }, []);

  return <div>Your app content</div>;
}

Vue

<template>
  <div>Your app content</div>
</template>

<script setup>
import { onMounted, onUnmounted } from 'vue';
import { BehaviorDetector, Mouse, Click, Scroll } from '@axeptio/behavior-detection';

let detector;
let checkInterval;

onMounted(() => {
  detector = new BehaviorDetector()
    .addStrategy(new Mouse())
    .addStrategy(new Click())
    .addStrategy(new Scroll());

  detector.start();

  checkInterval = setInterval(async () => {
    const result = await detector.score();
    if (result.score < 0.3) {
      console.warn('Bot detected!');
    }
  }, 3000);
});

onUnmounted(() => {
  clearInterval(checkInterval);
  detector?.stop();
});
</script>

🎯 Detection Strategies

The library uses multiple autonomous detection strategies, each analyzing different aspects of user behavior:

🖱️ Mouse Strategy

Weight: 0.30 (default)

Analyzes mouse movement patterns for human-like characteristics:

  • Velocity Variation: Humans have natural acceleration/deceleration (CV ~0.8-1.2)
  • Direction Changes: Organic curves vs. linear interpolation
  • Movement Smoothness: Natural micro-corrections vs. perfect paths
import { MouseStrategy } from '@axeptio/behavior-detection';

const mouse = new MouseStrategy({
  rollingWindow: 5000 // Keep last 5 seconds of data
});

detector.addStrategy(mouse, 0.30); // Custom weight

Bot Indicators:

  • Constant velocity movements
  • Perfect straight lines or curves
  • Instant position jumps
  • No micro-corrections

👆 Click Strategy

Weight: 0.30 (default)

Monitors click positioning accuracy on interactive elements:

import { ClickStrategy } from '@axeptio/behavior-detection';

const click = new ClickStrategy({
  targetSelectors: ['button', 'a', '[role="button"]']
});

detector.addStrategy(click);

// Add custom targets dynamically
click.addTarget('.custom-clickable');

Detection Patterns:

  • Human: Mouse positioned over element before click
  • ⚠️ Suspicious: Click at exact center (pixel-perfect)
  • Bot: Click without mouse movement or mouse outside element

📜 Scroll Strategy

Weight: 0.15 (default)

Analyzes scrolling behavior patterns:

import { ScrollStrategy } from '@axeptio/behavior-detection';

const scroll = new ScrollStrategy({
  rollingWindow: 5000
});

Bot Indicators:

  • Identical scroll distances (smoking gun)
  • Instant jumps (programmatic scrollTo)
  • Too consistent velocity
  • No natural acceleration/deceleration

⌨️ Keyboard Strategy

Weight: 0.10 (default)

Examines typing patterns and timing:

import { KeyboardStrategy } from '@axeptio/behavior-detection';

const keyboard = new KeyboardStrategy({
  targetSelectors: ['input[type="text"]', 'textarea']
});

// Add custom input targets
keyboard.addTarget('#custom-input');

Detection Factors:

  • Keystroke interval variation (natural human timing has CV ~0.4-0.6)
  • Key press duration variance
  • Backspace usage (error correction = human)
  • Too fast/instant key releases (<5ms = bot)

📱 Tap Strategy (Mobile)

Weight: 0.35 (mobile default)

Mobile-specific touch interaction detection:

import { TapStrategy } from '@axeptio/behavior-detection';

const tap = new TapStrategy({
  targetSelectors: ['button', 'a']
});

Analyzes:

  • Touch pressure patterns
  • Tap duration and timing
  • Multi-touch gestures

🌐 Environment Strategy

Weight: 0.08 (default)

Fingerprints browser environment for automation indicators:

import { EnvironmentStrategy } from '@axeptio/behavior-detection';

const env = new EnvironmentStrategy();

Checks:

  • Suspicious dimensions (800x600, 1024x768)
  • Missing browser features (WebGL, localStorage)
  • Plugin/MIME type inconsistencies
  • Headless browser indicators
  • Navigator property anomalies

📐 Resize Strategy

Weight: 0.02 (default)

Monitors window resize behavior:

import { ResizeStrategy } from '@axeptio/behavior-detection';

const resize = new ResizeStrategy();

Detects:

  • Programmatic resizing patterns
  • Suspicious resize timing
  • Mouse position during resize

📊 API Reference

BehaviorDetector

Main class for managing detection strategies.

Constructor

constructor(options?: TickOptions)

Options:

  • interval?: number - Tick interval in milliseconds (default: 1000)
  • pauseOnHidden?: boolean - Automatically pause detection when tab is hidden (default: true)

Methods

addStrategy(strategy: DetectionStrategy, weight?: number): this

Add a detection strategy with optional custom weight.

detector.addStrategy(new Mouse(), 0.35);
removeStrategy(name: string): this

Remove a strategy by name.

detector.removeStrategy('mouse');
setStrategyEnabled(name: string, enabled: boolean): this

Enable or disable a strategy without removing it.

detector.setStrategyEnabled('mouse', false);
start(): void

Start all enabled strategies.

detector.start();
stop(): void

Stop all strategies and cleanup listeners.

detector.stop();
reset(): void

Clear all collected data without stopping.

detector.reset();
score(options?: ScoreOptions): Promise<ScoreResult>

Calculate the human likelihood score.

const result = await detector.score({
  breakdown: true, // Include per-strategy scores
});

ScoreOptions:

  • breakdown?: boolean - Include detailed breakdown of each strategy

ScoreResult:

{
  score: number;        // 0-1 (0=bot, 1=human)
  breakdown?: {
    overall: number;
    factors: {
      mouse?: number;
      click?: number;
      scroll?: number;
      keyboard?: number;
      environment?: number;
      // ...
    };
    weights: {
      mouse: number;
      click: number;
      // ...
    };
  };
}
isActive(): boolean

Check if detector is currently tracking.

if (detector.isActive()) {
  console.log('Detector is running');
}
isPaused(): boolean

Check if detector is currently paused due to tab visibility.

if (detector.isPaused()) {
  console.log('Detector is paused (tab hidden)');
}

Note: A detector can be both active and paused. When the tab is hidden with pauseOnHidden: true, the detector remains active but is temporarily paused.

getEventCount(): Record<string, number>

Get event counts from all strategies.

getStrategyDebugInfo(): Record<string, any>

Get debug information from all strategies.

destroy(): void

Complete cleanup and remove all strategies.

detector.destroy();

⚙️ Configuration

Strategy Weights

Customize how much each strategy contributes to the final score:

const detector = new BehaviorDetector()
  .addStrategy(new Mouse(), 0.40)      // 40% weight
  .addStrategy(new Click(), 0.35)      // 35% weight
  .addStrategy(new Scroll(), 0.15)     // 15% weight
  .addStrategy(new Keyboard(), 0.10);  // 10% weight

Desktop vs Mobile

The library automatically adjusts strategies based on device type:

Desktop (default):

  • Mouse: 0.30
  • Click: 0.30
  • Scroll: 0.15
  • Keyboard: 0.10
  • Environment: 0.08
  • Resize: 0.02

Mobile (automatic):

  • Tap: 0.35 (replaces click)
  • Scroll: 0.35 (increased)
  • Keyboard: 0.15
  • Environment: 0.10
  • Resize: 0.05

Tick Interval

Control how often strategies receive tick updates:

const detector = new BehaviorDetector({
  interval: 500 // Check every 500ms
});

Automatic Pause on Hidden Tab

By default, the detector automatically pauses when the browser tab becomes hidden (using the Page Visibility API) and resumes when the tab becomes visible again. This provides several benefits:

  • Better Performance: Saves CPU cycles when the tab isn't visible
  • Battery Life: Reduces power consumption on mobile devices
  • Accuracy: Avoids collecting misleading data from background tabs
// Default: pause on hidden (recommended)
const detector = new BehaviorDetector({
  pauseOnHidden: true  // Default
});

// Disable if you need to track background behavior
const detector = new BehaviorDetector({
  pauseOnHidden: false
});

// Check if currently paused
if (detector.isPaused()) {
  console.log('Detection is paused (tab hidden)');
}

Browser CDN Usage:

window.bdSettings = {
  autoStart: true,
  pauseOnHidden: true,  // Default: true
  // ... other settings
};

The detector remains "active" (via isActive()) while paused, but strategies and tick updates are temporarily stopped until the tab becomes visible again. All collected data is preserved during the pause.

🎨 Browser Support

  • ✅ Chrome/Edge 90+
  • ✅ Firefox 88+
  • ✅ Safari 14+
  • ✅ Mobile Safari (iOS 14+)
  • ✅ Chrome Mobile (Android 90+)

🧪 Testing & Validation

The library includes comprehensive adversarial testing against popular automation frameworks:

Run All Tests

npm run test:adversarial

Individual Framework Tests

# Test against Playwright
npm run test:playwright

# Test against Puppeteer
npm run test:puppeteer

# Test against Selenium
npm run test:selenium

# Stress test (extensive scenarios)
npm run test:stress

Test Scenarios

Each framework is tested with:

  1. Bot-like behavior - Rapid actions, no delays (expected: score < 0.4)
  2. Human-like behavior - Natural delays and movements (expected: score > 0.6)
  3. Stealth mode - Automation with evasion techniques
  4. Headless vs Headed - Different browser modes

See tests/adversarial/README.md for detailed testing documentation.

🏗️ Architecture

Strategy Pattern

Each detection strategy is a fully autonomous module:

interface DetectionStrategy {
  readonly name: string;
  readonly defaultWeight: number;
  
  start(): void;      // Register listeners
  stop(): void;       // Cleanup
  reset(): void;      // Clear data
  score(): number | undefined;  // Calculate score
  
  onTick?(timestamp: number): void;  // Optional polling
  getDebugInfo?(): any;              // Optional debug data
}

Benefits:

  • 🌲 Tree-shakeable (import only what you need)
  • 🔌 Fully autonomous (manages own listeners and state)
  • 🎯 Single responsibility
  • 🧩 Easy to extend with custom strategies

Mathematical Scoring

Uses smooth mathematical functions instead of magic numbers:

import { gaussian, sigmoid, inverseSigmoid } from './math-utils';

// Gaussian: ideal value with symmetric falloff
score = gaussian(actualCV, idealCV, width);

// Sigmoid: smooth 0-1 mapping
score = sigmoid(value, midpoint, steepness);

// Inverse sigmoid: penalize high values
score = inverseSigmoid(value, midpoint, steepness);

📈 Performance

  • Minimal CPU Impact: Sampling and rolling windows prevent data buildup
  • Memory Efficient: ~1-2MB typical memory usage
  • No Network Calls: Everything runs client-side
  • Async Scoring: Non-blocking score calculations

🔐 Privacy & Security

  • Client-side only: No data transmitted to servers
  • No PII collected: Only behavioral patterns (no keystrokes content)
  • GDPR friendly: No cookies, no tracking, no storage
  • Transparent: Open source and auditable

🛠️ Development

Build

# Build all formats (ESM, CJS, IIFE)
npm run build:all

# Build only ESM/CJS
npm run build

# Build browser bundle
npm run build:browser

Project Structure

behavior-detection/
├── src/
│   ├── behavior-detector.ts    # Main detector class
│   ├── strategy.ts              # Strategy interface
│   ├── types.ts                 # TypeScript types
│   ├── math-utils.ts            # Mathematical functions
│   ├── browser.ts               # Browser CDN wrapper
│   └── strategies/
│       ├── mouse.ts             # Mouse movement detection
│       ├── click.ts             # Click accuracy detection
│       ├── scroll.ts            # Scroll behavior detection
│       ├── keyboard.ts          # Keyboard timing detection
│       ├── tap.ts               # Mobile tap detection
│       ├── environment.ts       # Environment fingerprinting
│       └── resize.ts            # Window resize detection
├── dist/                        # Build output
├── demos/
│   ├── test-harness.html        # Interactive testing UI with graphs
│   ├── browser-demo.html        # CDN usage example
│   └── example.html             # Strategy-based usage example
├── tests/
│   └── adversarial/             # Automation framework tests
└── docs/                        # Documentation assets

Scripts

npm run build           # Build library (ESM + CJS)
npm run build:all       # Build all formats
npm run build:browser   # Build browser IIFE bundle
npm run clean           # Clean dist directory
npm run tryme           # Build and start demo server
npm run deploy          # Deploy to CDN (AWS S3/CloudFront)
npm run test            # Run basic tests
npm run test:adversarial # Run all adversarial tests
npm run test:stress     # Stress test with extensive scenarios

🤝 Contributing

Contributions are welcome! This library can be extended with:

  • New strategies: Add detection for new behavioral patterns
  • Improved algorithms: Enhance existing detection logic
  • Mobile optimizations: Better touch/gesture detection
  • Performance improvements: Reduce overhead
  • Test coverage: Add more adversarial test scenarios

Creating Custom Strategies

import { DetectionStrategy } from '@axeptio/behavior-detection';

export class CustomStrategy implements DetectionStrategy {
  readonly name = 'custom';
  readonly defaultWeight = 0.10;
  
  private data: any[] = [];
  private listener: any;
  
  start(): void {
    this.listener = (e: Event) => {
      // Collect data
      this.data.push(/* ... */);
    };
    document.addEventListener('someevent', this.listener);
  }
  
  stop(): void {
    if (this.listener) {
      document.removeEventListener('someevent', this.listener);
    }
  }
  
  reset(): void {
    this.data = [];
  }
  
  score(): number | undefined {
    if (this.data.length < 5) return undefined;
    
    // Calculate and return score (0-1)
    return 0.85;
  }
  
  getDebugInfo() {
    return {
      eventCount: this.data.length,
      data: this.data
    };
  }
}

📝 Use Cases

  • Form Protection: Detect automated form submissions
  • Account Security: Identify credential stuffing attacks
  • E-commerce: Prevent inventory hoarding bots
  • Analytics: Filter bot traffic from user metrics
  • Rate Limiting: Adaptive limits based on behavior
  • A/B Testing: Exclude bots from experiments
  • Progressive CAPTCHAs: Only show CAPTCHA to suspicious users

🎯 Detection Thresholds

Recommended score interpretation:

| Score Range | Interpretation | Action | |-------------|---------------|--------| | 0.8 - 1.0 | Very likely human | Full access | | 0.6 - 0.8 | Probably human | Monitor | | 0.3 - 0.6 | Suspicious | Add friction (CAPTCHA) | | 0.0 - 0.3 | Very likely bot | Block or severely limit |

Note: Thresholds should be tuned based on your specific use case and acceptable false positive rate.

⚠️ Limitations

  • Not foolproof: Sophisticated bots with human-like behavior can evade detection
  • Initial period: Requires user interaction to build confidence
  • False positives: Accessibility tools, keyboard-only navigation may score lower
  • Context matters: Some legitimate use cases (automation testing, scripts) will be flagged

Best Practice: Use as one layer in a defense-in-depth strategy, not as the sole security measure.

📄 License

Proprietary © Axeptio

🙏 Acknowledgments

  • Inspired by research in behavioral biometrics and bot detection
  • Built with TypeScript for type safety
  • Tested against real-world automation frameworks
  • Mathematical approach based on statistical pattern recognition

Made with ❤️ by Axeptio