Detection Methodology
How a session score is built and what each signal means
Every ClickLens verdict is the weighted sum of named signals, and it is exactly recomputable from the data stored against the session. No opaque model decides whether a visitor was a person. This page is the model: the categories, the thresholds, and the specific signals each category subtracts on. The Technology overview is the same material written for a general reader; this is the reference.
The deduction model
A session scores from 0 to 100. Each of five categories starts at full marks and loses points only when a specific check fires. A clean session keeps its score, which is the honest default. Because the score is a sum of named deductions, each session on your dashboard shows the flags that produced its verdict, and you can read why a click was judged the way it was.
One consequence is worth stating plainly: a category that only subtracts on detection treats a beacon with nothing to detect as clean. That hole is closed by the cross-layer trust checks below, which require a human verdict to be corroborated by evidence the client cannot forge.
Category weights
The weights are fixed and published here. They are not tuned per customer.
| Category | Weight |
|---|---|
| Automation detection | 25% |
| Behavioural signals | 25% |
| Fingerprint consistency | 20% |
| Network reputation | 15% |
| Contextual signals | 15% |
Verdict thresholds
The score maps to one of three verdicts:
| Score | Verdict | Meaning |
|---|---|---|
| 71–100 | Human | No corroborated evidence of automation. |
| 40–70 | Suspect | Some signal, not enough to condemn. Also the cap applied when a human verdict lacks corroboration. |
| 0–39 | Bot | Enough corroborated signal to classify the session as automated. |
Signal glossary
These are the named signals that move each category, grouped by the category that emits them. They are the flag identifiers recorded against a session. The point value of each signal is deliberately not published: a precise penalty table is an evasion-tuning target, so weights and thresholds are public but per-signal penalties are not. Most signals are soft on their own, and the behavioural geometry checks in particular require an independent corroborating flag before they pull a score toward bot.
Automation detection
Markers a real browser does not carry.
| Signal | What it detects |
|---|---|
webdriver_detected | navigator.webdriver was true, the standard automation marker. |
headless_ua_detected | The user agent matched a headless-browser pattern. |
selenium_indicators_detected | Selenium, Playwright or Cypress signatures were present. |
cdp_indicators_detected | Chrome DevTools Protocol indicators appeared in the environment. |
automation_globals_detected | Global variables that automation frameworks inject were present. |
native_functions_shimmed | Native browser functions had been overridden, a common spoofing tell. |
chrome_runtime_missing | A Chromium user agent was missing chrome.runtime. |
permissions_query_anomaly | The Permissions API disagreed with the reported notification state. |
Behavioural signals
Pointer, timing and interaction shape. Soft signals need corroboration before they condemn.
| Signal | What it detects |
|---|---|
no_mouse_movements | No mouse movement was sampled during the session. |
no_scroll_events | The visitor never scrolled. |
time_on_page_under_1s | The session lasted under one second. |
page_never_visible | The page visibility state was hidden for the whole session. |
machine_click_timing | Click intervals were too regular to be human. |
machine_keystroke_timing | Keystroke intervals had near-zero variance. |
mouse_entropy_too_low | Mouse movement was too uniform to be a person. |
path_too_straight | The pointer travelled in lines too straight to be hand-driven. |
smooth_trajectory_bot | The path changed direction too rarely, the signature of a generated trajectory. |
Fingerprint consistency
A device surface that contradicts itself.
| Signal | What it detects |
|---|---|
timezone_geo_mismatch | The reported timezone did not match the IP geolocation. |
language_geo_mismatch | The browser language did not match the IP country. |
accept_language_mismatch | The HTTP Accept-Language header disagreed with the JS language. |
canvas_webgl_absent | Both the Canvas and WebGL fingerprint surfaces were missing. |
virtual_gpu_detected | The WebGL renderer was a known virtual or datacentre GPU. |
ua_platform_mismatch | The user agent platform disagreed with navigator.platform. |
js_engine_ua_mismatch | The JavaScript engine behaviour disagreed with the claimed browser. |
ja4_ua_mismatch | The JA4 TLS class did not match the claimed browser (with the mismatching class as a suffix). |
Network reputation
Where the request actually originates.
| Signal | What it detects |
|---|---|
cloud_provider_ip | The IP belongs to a public cloud, verified by ASN. |
datacenter_ip | The IP is datacentre or hosting, not a consumer ISP. |
vpn_ip | The IP is a known VPN provider. |
high_abuse_confidence | IP threat-intelligence returned a high abuse score. |
missing_accept_language | The request sent no Accept-Language header at all. |
Contextual signals
The session context around the visit.
| Signal | What it detects |
|---|---|
empty_referrer_with_utm | UTM parameters were present but the referrer was empty. |
referrer_utm_mismatch | The referrer hostname did not match the UTM source. |
impossible_travel_detected | The same fingerprint appeared in two countries within minutes. |
rapid_geo_shift_detected | The same IP appeared in two cities within half an hour. |
residential_proxy_suspected | An IP carried far more distinct fingerprints than a household would. |
bot_ring_detected | One IP carried fingerprints at a rate consistent with a bot ring. |
previously_verified_bot_fingerprint | This fingerprint was confirmed a bot before. |
This glossary covers the signals you are most likely to see. It is a representative set, not the complete rule list.
Keeping the browser honest
The browser is the thing under test, so its self-report cannot be the final word. A human verdict has to be corroborated by evidence the client cannot fabricate. Four checks do that, and when corroboration is missing the verdict is capped to suspect.
Signed beacons
Each beacon is signed with HMAC-SHA256 and carries a nonce and timestamp. An unsigned beacon, a forged signature, a stale timestamp or a replayed nonce all fail verification, so a captured payload cannot be replayed to mint a fake human.
Cross-layer consistency
The user agent in the beacon body is checked against the trusted HTTP-header user agent, the JA4 TLS class and the Accept-Language header. A residential proxy that sends a clean browser user agent still has to make the wire layers agree, and they rarely do.
Client-hint agreement
Sec-CH-UA request headers are scored against the browser family parsed from the trusted user agent. Because client hints are a Chromium feature, their absence is never held against Safari or Firefox, near a fifth of real traffic; only their unexpected presence counts.
Server-timing checks
Timing the client reports is corroborated against what the server independently observed. A client timeline that grew faster than wall-clock could only be fabricated, so it is flagged rather than trusted.
A forged or empty beacon can no longer score human. A human verdict must be backed by a real fingerprint surface and server-attested evidence, and must not be contradicted by a user-agent mismatch, a failed signature or a replayed nonce.
Conversion provenance signals
When a conversion is reported, the engine scores the conversion event as well as the click. It captures seven submit-provenance signals grouped into three families: gesture authenticity (was the submit browser-trusted, did a pointer path precede it, was a field pasted without focus), fill pattern (how many fields took keystrokes, the entropy of the fill order, the interaction count) and timing (load to conversion). None of them reads a field value, a field name, or any user-entered text. It is provenance, not content.
The conversion tracking guide lists all seven with the exact field names, and conversion protection covers how they combine into a graded verdict.
How the model is kept honest
Accuracy is measured, not asserted. Precision, recall and F1 are computed against verified ground truth, and every scoring change is replayed against a bank of verified sessions before it ships, so a tweak that would reclassify a known human is caught before release. The disputes and efficacy guide covers the confusion matrix, the metrics, and how a label earns precedence.