Skip to content

Browser Bot Detection Script

The browser script is the fastest install that works on any website. It catches headless browsers, automation, browser agents, and LLM referrals from clients that execute JavaScript.

Create a free account → · Compare all install methods

  1. In the WebDecoy dashboard setup checklist, open Install the detection script and choose Copy. If the checklist is closed, open Detection Scripts, create a script for the selected site, and choose Copy snippet.
  2. Paste the generated line into the shared layout for your site, just before </head>.
  3. Deploy and load one page that contains the tag. The checklist waits for the first sensor event and confirms when it arrives.

The generated line looks like this, but your data-aid and data-sid values are unique:

<script
async
src="https://cdn.webdecoy.com/bot-detection/v1/bot-detection.min.js"
data-aid="your-property-uuid"
data-sid="your-scanner-uuid">
</script>

To confirm the install, open Sensors and look for the Detection Script row, or follow the installation verification checklist.

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.

For capabilities, coverage, and deployment options, see the Bot Scanner product overview.

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

Everything here requires the client to execute JavaScript. That is the defining constraint of this install method.

Detection Type What It Catches
WebDriver Selenium, Puppeteer, Playwright automation
Headless Browsers Chrome Headless, PhantomJS, Firefox Headless
AI Browser Agents Claude Computer Use, Stagehand, Browser Use (agents driving a real browser)
AI Browser Extensions Claude, ChatGPT, Perplexity sidebars
Browser Anomalies Inconsistent navigator properties
Behavioral Patterns Non-human mouse movements, instant form fills
Fingerprint Mismatches Canvas, WebGL, font rendering inconsistencies
CDP Artifacts ChromeDriver, Selenium, Puppeteer markers
Environment Integrity MessageChannel, API mocking detection
LLM Referrals Humans arriving from ChatGPT, Perplexity, Claude
Not Detected Why
Googlebot, Bingbot The crawl pass is a plain HTTP fetch. Rendering is a separate, deferred, sampled pass, and most crawls never execute your page’s JavaScript.
GPTBot, ClaudeBot, CCBot, PerplexityBot These fetch HTML directly and do not execute JavaScript at all.
curl, Python requests, Go http, Scrapy No JavaScript engine.
UA impersonators A 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.

Aspect Detection Script (Client) Server-Side Detection
Where it runs Visitor’s browser Your server or edge
Requires JavaScript Yes (no JS, no detection) No
What it sees Browser internals, behavior Raw HTTP request, real IP
Sees non-JS crawlers No Yes
Detection depth Deep browser analysis Headers, IP, UA, path
Bypass difficulty Harder to evade Easier to spoof, but verifiable via rDNS
Best for Headless browsers, AI agents, extensions Crawlers, scrapers, scanners, impersonators
AI Browser Type Detection 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, under Countermeasures
  2. Click “New Detection Script”

    • The create scanner dialog opens
  3. Configure the Scanner

    Field Description Example
    Name Internal identifier “Main Website Scanner”
    Endpoint Domain The domain the script reports for “www.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:

Framework Detection Method
Selenium WebDriver navigator.webdriver property
Puppeteer Chrome DevTools Protocol traces
Playwright Browser-specific markers
Cypress Test runner indicators

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

Identifies browsers running without a visible UI:

Signal Description
Missing plugins Headless browsers often have no plugins
Canvas fingerprint Rendering differences
WebGL anomalies Graphics processing inconsistencies
User agent hints Client hints mismatches

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

Identifies AI/LLM training crawlers:

Bot User Agent Pattern
GPTBot GPTBot
ClaudeBot ClaudeBot
Google-Extended Google-Extended
PerplexityBot PerplexityBot
CCBot CCBot

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:

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

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

Signal Points What It Detects
cdc_ properties +40 ChromeDriver injects cdc_* prefixed global variables
$cdc_ properties +40 Older ChromeDriver variants with $cdc_* prefix
__webdriver_evaluate +30 Selenium WebDriver evaluation artifacts
__selenium_evaluate +30 Direct Selenium markers
__puppeteer_evaluation_script__ +35 Puppeteer script injection markers
__fxdriver_evaluate +25 Firefox WebDriver (Geckodriver) artifacts
__cdp_binding__ +40 CDP runtime binding artifacts
__chromium_protocol__ +40 Chromium protocol handler markers
Modified webdriver getter +35 Attempts to hide navigator.webdriver leave traces
CDP script injection +30 Scripts 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.

Signal Points What 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:

Signal Points What It Detects
lie_modified_* +15 each (max 45) Native function toString() doesn’t return [native code]
lie_webdriver_getter_tampered +15 WebDriver property descriptor has extra properties
lie_webdriver_getter_modified +15 WebDriver getter’s toString is not native
lie_toString_tampered +15 Function.prototype.toString itself is modified
lie_bind_tampered +15 Function.prototype.bind is modified
lie_plugins_spoofed +15 navigator.plugins object type mismatch
lie_getOwnPropertyDescriptor_tampered +15 Core Object method modified
lie_defineProperty_tampered +15 Core Object method modified
lie_chrome_runtime_spoofed +15 Fake 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:

Signal Points What It Detects
worker_mismatch +20 per field (max 40) Any navigator property mismatch
worker_mismatch_platform +20 Platform differs between main/worker
worker_mismatch_userAgent +20 User agent differs
worker_mismatch_hardwareConcurrency +20 CPU cores differ
worker_mismatch_language +20 Language 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:

Signal Points What It Detects
canvas_pixel_noise +30 Pixel values differ after write/read cycle
canvas_text_metrics_anomaly +15 Text 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">
Behavior Result
Field is empty Likely human
Field has value Definitely 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>
Behavior Result
Link not clicked Normal user
Link is followed Bot 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/bot-detection/v1/bot-detection.min.js"
data-aid="your-property-uuid"
data-sid="your-scanner-uuid">
</script>
Attribute Required Description
src Yes CDN URL for the script
data-aid Yes Your property UUID (the site this snippet is installed on)
data-sid Yes Your detection script UUID
data-endpoint No Custom ingest endpoint (default: https://ingest.webdecoy.com/api/v1/detect/public)

There is one script. The lite/pro tier split is gone, and so is the separate “pro” bundle.

Version URL
Minified https://cdn.webdecoy.com/bot-detection/v1/bot-detection.min.js
Source https://cdn.webdecoy.com/bot-detection/v1/bot-detection.js

The older /v1/pro/bot-detection-pro.min.js paths still serve the same bytes, so existing installs are not broken, but new snippets use the URLs above. If you have the old path hard-coded somewhere, it is safe to leave and better to update.

Add the snippet before the closing </head> tag in your shared layout:

<!DOCTYPE html>
<html>
<head>
<title>Your Site</title>
<!-- WebDecoy Detection Script -->
<script async src="https://cdn.webdecoy.com/bot-detection/v1/bot-detection.min.js"
data-aid="your-property-uuid"
data-sid="your-scanner-uuid">
</script>
</head>
<body>
<!-- Your content -->
</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/bot-detection/v1/bot-detection.min.js"
data-aid="your-property-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/bot-detection/v1/bot-detection.min.js"
data-aid="your-property-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/bot-detection/v1/bot-detection.min.js';
script.setAttribute('data-aid', 'your-property-uuid');
script.setAttribute('data-sid', 'your-scanner-uuid');
script.async = true;
document.body.appendChild(script);
}
};
</script>

In the browser:

  1. Load your website in a browser
  2. Open Developer Tools (F12)
  3. Go to the Network tab
  4. Look for the bot-detection.min.js request
  5. Check Console for [WebDecoy] messages

In the app, the Sensors page (sidebar, under Countermeasures) answers the question the browser cannot: whether detections are actually arriving. Your site’s card lists a Detection Script sensor with when it was last seen and its counts over 24h and 7d, and it distinguishes the states that look alike from the outside:

Row says Means
Reporting Detections are arriving
Nothing reported yet Installed, nothing has come in
Quiet It has reported before, but not recently

A Nothing reported yet on a busy site usually means the script is loading but every visitor is scoring under the reporting threshold, which is the normal state for a site with only human traffic. Remember that a detection script sees only clients that run JavaScript, so silence here is not silence overall. See the caution at the top of this page.


Go to Detection Scripts to see all scripts:

Column Description
Name Scanner identifier
Enabled Active status toggle
Detections Detection count attributed to the script
Created Creation date
Actions Edit, 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 Type Collected Purpose
Browser properties ✅ Basic detection
Mouse coordinates ✅ Movement pattern analysis
Click positions ✅ Click behavior analysis
Scroll positions ✅ Scroll pattern analysis
Keystroke timing ✅ Typing rhythm analysis
Canvas fingerprint ✅ Rendering consistency
WebGL parameters ✅ Hardware fingerprinting
Audio fingerprint ✅ Audio 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 the Sensors page first: it tells you whether anything has ever arrived from this script, which separates “not installed” from “installed and quiet”
  2. Check browser console for [WebDecoy] messages
  3. Verify the script loads (a 404 on the src is silent, because the tag is async)
  4. Verify data-aid is your property UUID and data-sid your scanner UUID
  5. Ensure score threshold (20) is exceeded
  6. 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