Skip to content

Detection Scripts

A detection script is a JavaScript-based detection system that runs in visitors’ browsers. It analyzes browser characteristics and behavior to identify automated tools, headless browsers, and bots.

The detection script uses a two-phase approach to maximize detection:

Page Load (0ms)
├── Phase 1: Immediate Detection
│ ├── Basic bot signals (webdriver, headless)
│ ├── CDP artifact detection
│ ├── Canvas fingerprint hash
│ ├── WebGL deep parameters
│ ├── Audio context fingerprint
│ └── Send detection if score > 20
User Interaction (5 seconds)
├── Phase 2: Behavioral Analysis
│ ├── Mouse movement patterns
│ ├── Click timing analysis
│ ├── Scroll velocity patterns
│ ├── Keystroke dynamics
│ └── Send behavioral update
Final Score Calculated

Why two phases?

  • Phase 1 catches bots that leave immediately
  • Phase 2 provides deep analysis for bots that stay
  • Combined data gives the most accurate detection
Detection TypeWhat It Catches
Everything here requires the client to execute JavaScript. That is the defining constraint of this install method.
Detection TypeWhat It Catches
WebDriverSelenium, Puppeteer, Playwright automation
Headless BrowsersChrome Headless, PhantomJS, Firefox Headless
AI Browser AgentsClaude Computer Use, Stagehand, Browser Use — agents driving a real browser
AI Browser ExtensionsClaude, ChatGPT, Perplexity sidebars
Browser AnomaliesInconsistent navigator properties
Behavioral PatternsNon-human mouse movements, instant form fills
Fingerprint MismatchesCanvas, WebGL, font rendering inconsistencies
CDP ArtifactsChromeDriver, Selenium, Puppeteer markers
Environment IntegrityMessageChannel, API mocking detection
LLM ReferralsHumans arriving from ChatGPT, Perplexity, Claude
Not DetectedWhy
Googlebot, BingbotThe crawl pass is a plain HTTP fetch. Rendering is a separate, deferred, sampled pass — most crawls never execute your page’s JavaScript.
GPTBot, ClaudeBot, CCBot, PerplexityBotThese fetch HTML directly and do not execute JavaScript at all.
curl, Python requests, Go http, ScrapyNo JavaScript engine.
UA impersonatorsA client spoofing Googlebot never runs the script, so the script never sees it to check.

The script does contain user-agent patterns for these crawlers, which is why older versions of this page listed them. Those patterns only ever match if the crawler executes the script — which these crawlers do not. To detect them you need a server-side sensor.

Detection Script vs. Server-Side Detection

Section titled “Detection Script vs. Server-Side Detection”

These are complements, not alternatives. Most sites should run both.

AspectDetection Script (Client)Server-Side Detection
Where it runsVisitor’s browserYour server or edge
Requires JavaScriptYes — no JS, no detectionNo
What it seesBrowser internals, behaviorRaw HTTP request, real IP
Sees non-JS crawlersNoYes
Detection depthDeep browser analysisHeaders, IP, UA, path
Bypass difficultyHarder to evadeEasier to spoof, but verifiable via rDNS
Best forHeadless browsers, AI agents, extensionsCrawlers, scrapers, scanners, impersonators
AI Browser TypeDetection Rate
Stagehand + Browserbase~60-70%
Playwright + Stealth~75%
Basic Puppeteer~90%
Commercial anti-detect~40%

  1. Navigate to Detection Scripts

    • Click Detection Scripts in the sidebar
  2. Click “New Detection Script”

    • The create scanner dialog opens
  3. Configure the Scanner

    FieldDescriptionExample
    NameInternal identifier”Main Website Scanner”
    Endpoint DomainThe domain the script reports forwww.example.com
  4. Click “Create”

    • Detection script is created with a unique ID
  5. Install the Snippet

Detection scripts have no per-scanner tuning — every script runs the full detection suite: automation and headless-browser detection, AI-crawler identification, behavioral analysis, and browser fingerprinting. The only per-script controls are the name, the endpoint domain, and the enable/disable toggle.


Detects browser automation frameworks:

FrameworkDetection Method
Selenium WebDrivernavigator.webdriver property
PuppeteerChrome DevTools Protocol traces
PlaywrightBrowser-specific markers
CypressTest runner indicators

Enable when: You want to catch automated testing tools and bots.

Identifies browsers running without a visible UI:

SignalDescription
Missing pluginsHeadless browsers often have no plugins
Canvas fingerprintRendering differences
WebGL anomaliesGraphics processing inconsistencies
User agent hintsClient hints mismatches

Enable when: Attackers use headless Chrome, PhantomJS, etc.

Identifies AI/LLM training crawlers:

BotUser Agent Pattern
GPTBotGPTBot
ClaudeBotClaudeBot
Google-ExtendedGoogle-Extended
PerplexityBotPerplexityBot
CCBotCCBot

Enable when: You want to detect AI training data collection.

The detection script tracks mouse movements, clicks, scrolls, and keystrokes to detect non-human patterns:

SignalPointsWhat It Detects
Low mousemove count+25Fewer than 10 mouse events (bots often skip mouse simulation)
Linear paths+20Mouse moves in perfectly straight lines (humans curve)
Constant velocity+15No speed variation (humans accelerate/decelerate)
Grid-aligned moves+15Positions on exact coordinates (automation artifacts)
SignalPointsWhat It Detects
Instant clicks+30No delay between mouse stop and click (humans have reaction time)
No pre-movement+25Clicks without preceding mouse movement (teleporting cursor)
SignalPointsWhat It Detects
Constant scroll velocity+10Same speed throughout (humans vary)
Perfect scroll intervals+10Exact timing between scroll events
SignalPointsWhat It Detects
Constant typing rhythm+15No variation in keystroke timing
Superhuman typing speed+20Less than 30ms between keystrokes

Builds a fingerprint from browser characteristics:

  • Canvas rendering
  • WebGL renderer
  • Audio context
  • Font enumeration
  • Screen properties
  • Timezone/language

Enable when: You want to track returning visitors and detect fingerprint anomalies.

SignalPointsWhat It Detects
SwiftShader renderer+30Software rendering (common in headless Chrome)
Mesa LLVMpipe renderer+25Software rendering on Linux
No unmasked renderer+15GPU info hidden (real browsers expose this)
Low extension count+10Fewer than 10 WebGL extensions
SignalPointsWhat It Detects
AudioContext unavailable+15API missing or blocked
Zero audio fingerprint+25Mocked AudioContext returns zero
Missing baseLatency+10Chrome 74+ should have this property
Unusual sample rate+10Not 44100 or 48000 Hz
Zero channel count+15Invalid audio configuration

The detection script generates a unique hash from canvas rendering:

  1. Draws specific shapes and text
  2. Uses specific fonts and colors
  3. Generates hash from the rendered output
  4. Compares against known patterns

Headless browsers often have distinct canvas fingerprints due to software rendering.

Chrome DevTools Protocol (CDP) is the automation protocol used by ChromeDriver, Puppeteer, Playwright, and other browser automation tools. These tools inject identifiable artifacts that are extremely difficult to hide.

SignalPointsWhat It Detects
cdc_ properties+40ChromeDriver injects cdc_* prefixed global variables
$cdc_ properties+40Older ChromeDriver variants with $cdc_* prefix
__webdriver_evaluate+30Selenium WebDriver evaluation artifacts
__selenium_evaluate+30Direct Selenium markers
__puppeteer_evaluation_script__+35Puppeteer script injection markers
__fxdriver_evaluate+25Firefox WebDriver (Geckodriver) artifacts
__cdp_binding__+40CDP runtime binding artifacts
__chromium_protocol__+40Chromium protocol handler markers
Modified webdriver getter+35Attempts to hide navigator.webdriver leave traces
CDP script injection+30Scripts injected via Runtime.evaluate protocol

Why CDP detection is highly reliable:

  1. Protocol-level injection - These artifacts are injected by the automation framework itself, not the browser
  2. Hard to remove - Removing them requires patching the automation tool’s source code
  3. Near-zero false positives - Normal browsers never have these properties
  4. Catches stealth attempts - Tools that try to hide navigator.webdriver often leave other CDP traces

Example detection:

// ChromeDriver leaves these artifacts:
window.cdc_adoQpoasnfa76pfcZLmcfl_Array // Random but always cdc_ prefixed
window.cdc_adoQpoasnfa76pfcZLmcfl_Promise // Multiple cdc_ properties
// Selenium WebDriver leaves:
window.__webdriver_evaluate // Evaluation function
window.__driver_unwrapped // Unwrapped driver reference
// Puppeteer leaves:
window.__puppeteer_evaluation_script__ // Script injection marker

The detection script performs additional environment integrity checks that verify browser APIs behave correctly. Automation tools sometimes incorrectly mock or break these APIs.

The MessageChannel API enables communication between different browsing contexts. Some automation frameworks incorrectly implement or break this API.

SignalPointsWhat It Detects
MessageChannel timeout+10*Message not received within 100ms
MessageChannel error+10*API throws error or is unavailable
MessageChannel exception+10*Cannot create MessageChannel

*Weak signal: Only counted when combined with other strong bot indicators. This prevents false positives from legitimate environments that restrict MessageChannel (some sandboxed iframes, older browsers).

Why this detection works:

  • Real browsers have full MessageChannel support
  • Automation frameworks sometimes mock MessageChannel incorrectly
  • The test is fast (100ms timeout) and non-blocking
  • Very low performance impact

These advanced detection techniques are inspired by CreepJS and target sophisticated evasion tools.

Detects when browsers attempt to spoof their fingerprint using stealth plugins like puppeteer-extra-stealth or playwright-stealth:

SignalPointsWhat It Detects
lie_modified_*+15 each (max 45)Native function toString() doesn’t return [native code]
lie_webdriver_getter_tampered+15WebDriver property descriptor has extra properties
lie_webdriver_getter_modified+15WebDriver getter’s toString is not native
lie_toString_tampered+15Function.prototype.toString itself is modified
lie_bind_tampered+15Function.prototype.bind is modified
lie_plugins_spoofed+15navigator.plugins object type mismatch
lie_getOwnPropertyDescriptor_tampered+15Core Object method modified
lie_defineProperty_tampered+15Core Object method modified
lie_chrome_runtime_spoofed+15Fake chrome.runtime in non-Chrome

Why this detection is highly effective:

  • Stealth plugins MUST modify native functions to hide automation
  • These modifications leave detectable traces
  • Catches the most sophisticated evasion tools

Compares browser properties between the main thread and a Web Worker:

SignalPointsWhat It Detects
worker_mismatch+20 per field (max 40)Any navigator property mismatch
worker_mismatch_platform+20Platform differs between main/worker
worker_mismatch_userAgent+20User agent differs
worker_mismatch_hardwareConcurrency+20CPU cores differ
worker_mismatch_language+20Language differs

Why this detection works:

  • Many stealth tools only patch the main window object
  • Web Workers have separate navigator objects
  • Inconsistencies reveal automation that forgot to patch workers

Detects canvas fingerprint manipulation used by anti-fingerprinting tools:

SignalPointsWhat It Detects
canvas_pixel_noise+30Pixel values differ after write/read cycle
canvas_text_metrics_anomaly+15Text measurements inconsistent across fonts

Why this detection works:

  • Anti-fingerprinting tools add random noise to canvas output
  • Normal browsers return exact pixel values that were written
  • Brave browser, Firefox resist fingerprinting, and privacy extensions trigger this

Detection scripts can automatically inject honeypot elements into your pages.

Adds hidden form fields that humans can’t see or fill:

<!-- Injected automatically by detection script -->
<input type="text"
name="website_url"
style="position:absolute;left:-9999px"
tabindex="-1"
autocomplete="off">
BehaviorResult
Field is emptyLikely human
Field has valueDefinitely a bot

Best for: Contact forms, signup forms, comment sections.

Adds hidden links that only bots follow:

<!-- Injected automatically by detection script -->
<a href="/trap-path-abc123"
style="display:none;visibility:hidden">
Secret Link
</a>
BehaviorResult
Link not clickedNormal user
Link is followedBot or crawler

Best for: Any page where you want crawler detection.

Honeypot injection is automatic — there are no per-scanner injection settings.


  1. Go to Detection Scripts
  2. Find your scanner in the list
  3. Click Copy Snippet (or the copy icon)
<script async src="https://cdn.webdecoy.com/v1/pro/bot-detection-pro.min.js"
data-aid="your-organization-uuid"
data-sid="your-scanner-uuid">
</script>
AttributeRequiredDescription
srcYesCDN URL for scanner
data-aidYesYour organization UUID
data-sidYesYour detection script UUID
data-endpointNoCustom ingest endpoint (default: https://ingest.webdecoy.com/api/v1/detect/public)
VersionURL
Minifiedhttps://cdn.webdecoy.com/v1/pro/bot-detection-pro.min.js
Sourcehttps://cdn.webdecoy.com/v1/pro/bot-detection-pro.js

Add the snippet before the closing </body> tag:

<!DOCTYPE html>
<html>
<head>
<title>Your Site</title>
</head>
<body>
<!-- Your content -->
<!-- WebDecoy Detection Script -->
<script async src="https://cdn.webdecoy.com/v1/pro/bot-detection-pro.min.js"
data-aid="your-organization-uuid"
data-sid="your-scanner-uuid">
</script>
</body>
</html>
  1. Create a new Custom HTML tag
  2. Paste the snippet
  3. Set trigger to All Pages
  4. Publish the container

Add to your theme’s footer.php:

<?php if (!is_admin()) : ?>
<script async src="https://cdn.webdecoy.com/v1/pro/bot-detection-pro.min.js"
data-aid="your-organization-uuid"
data-sid="your-scanner-uuid">
</script>
<?php endif; ?>
// _app.js or layout.js
import Script from 'next/script';
export default function App({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<Script
src="https://cdn.webdecoy.com/v1/pro/bot-detection-pro.min.js"
data-aid="your-organization-uuid"
data-sid="your-scanner-uuid"
strategy="afterInteractive"
/>
</>
);
}
App.vue
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
mounted() {
const script = document.createElement('script');
script.src = 'https://cdn.webdecoy.com/v1/pro/bot-detection-pro.min.js';
script.setAttribute('data-aid', 'your-organization-uuid');
script.setAttribute('data-sid', 'your-scanner-uuid');
script.async = true;
document.body.appendChild(script);
}
};
</script>
  1. Load your website in a browser
  2. Open Developer Tools (F12)
  3. Go to the Network tab
  4. Look for bot-detection-pro.min.js request
  5. Check Console for [WebDecoy] messages

Go to Detection Scripts to see all scripts:

ColumnDescription
NameScanner identifier
EnabledActive status toggle
DetectionsDetection count attributed to the script
CreatedCreation date
ActionsEdit, delete, copy snippet
  1. Find the scanner in the list
  2. Toggle the Enabled switch
  3. Scanner is immediately active/inactive
  1. Click the menu (three dots)
  2. Select Edit
  3. Modify settings
  4. Click Save
  1. Click the menu (three dots)
  2. Select Delete
  3. Confirm deletion
  4. Scanner and snippet stop working immediately

  • ✅ Start with Medium sensitivity
  • ✅ Enable honeypot injection
  • ✅ Test on staging before production
  • ✅ Monitor false positive rates
  • ✅ Combine with server-side detection
  • ❌ Use High sensitivity without testing
  • ❌ Block users based solely on scanner results
  • ❌ Install multiple scanners on the same page
  • ❌ Forget to update snippet when changing scanners
Detection Options:
✓ Detect automation - Essential
✓ Detect headless - Essential
✓ Detect AI crawlers - Recommended
✓ Behavioral analysis - Recommended
✓ Fingerprinting - Optional (privacy considerations)
Honeypot Options:
✓ Form honeypot - Highly recommended
✓ Link honeypot - Recommended

In addition to bot detection, the detection script automatically tracks visitors arriving from AI platforms like ChatGPT, Perplexity, Claude, and others.

When a visitor clicks a link shared in an AI conversation, the detection script checks document.referrer against known AI platform domains and sends a lightweight beacon. This fires independently of bot detection since these are human visitors.

ChatGPT, Perplexity, Google Gemini, Claude, DeepSeek, Microsoft Copilot, You.com, Phind, Kagi, Meta AI, and Grok.

  • Score is always 0 — these are real human visitors, not bots
  • Fires once per page load — won’t create duplicate records
  • Independent of bot detection — does not interfere with threat scoring
  • Data appears in the AI Referrals dashboard

For full details, see AI Detections — LLM Referral Tracking.


The detection script collects data for detection purposes:

Data TypeCollectedPurpose
Browser propertiesBasic detection
Mouse coordinatesMovement pattern analysis
Click positionsClick behavior analysis
Scroll positionsScroll pattern analysis
Keystroke timingTyping rhythm analysis
Canvas fingerprintRendering consistency
WebGL parametersHardware fingerprinting
Audio fingerprintAudio context verification

Important:

  • Data is used solely for bot detection scoring
  • No actual keystrokes are captured (only timing intervals)
  • Data is not used for user tracking or advertising
  • Consider your privacy policy when deploying

  1. Check browser console for [WebDecoy] messages
  2. Verify data-aid and data-sid attributes are set correctly
  3. Ensure score threshold (20) is exceeded
  4. Check network tab for requests to ingest endpoint
  1. Ensure behavioral phase has time to collect data (users need 5+ seconds on page)
  2. Check that users interact with page (mouse movement, scrolling)
  3. Review detection metadata to see which signals are triggering
  4. Consider if bots are leaving before Phase 2 completes

Scripts are served with permissive CORS headers. If you see CORS errors:

  1. Ensure you’re loading from cdn.webdecoy.com
  2. Check if a proxy or CDN is stripping headers
  3. Verify no browser extensions are blocking requests