@noidme/am-i-bot
v0.1.0-beta.0
Published
am-i-bot — consent-native bot / fraud detection. Client signals for telling a human from automation: driver-injected automation tells + CDP stack markers, incognito/private-mode, a LOCAL behavioral anomaly score (raw events never leave the device), and a
Maintainers
Readme
@noidme/am-i-bot
Consent-native bot / fraud detection. The client-side signals for telling a human from automation — delivered as public facts and a raise-only score, never a verdict (the verdict happens server-side).
- Automation tells (
EnvProbe):navigator.webdriver+ headless UA + driver-injected globals (playwright/selenium/chromedriver$cdc_/phantom) + a CDP eval-stack marker that survives stealth plugins. - Incognito / private mode (
StorageProbe): a StorageManager-quota heuristic. - Local behavioral score (
behavior): pointer + timing patterns scored on-device — raw events never leave the device, only the[0,1]score does (and it's treated raise-only server-side). - Signed-challenge liveness (
DeviceKey): a non-extractable ECDSA device key — page JS can sign a server challenge but can never exfiltrate the key, so a bot can't relay/impersonate.
Zero-dependency. Consent comes from @noidme/consent
(the window.noidme bridge); the server engine turns these into a class (human / bot / declared-agent),
a suspectScore, and a livenessVerified — combined with un-fakeable server-side timing. For device identity
see @noidme/mac-print; the all-in-one agent is
@noidme/glassprint.
Install
npm i @noidme/am-i-botUse
import { ConsentGate, resolveEngine, BOT_SIGNAL_PROBES, createBehaviorCollector, DeviceKey, createMemoryKeyStore } from '@noidme/am-i-bot';
const gate = new ConsentGate(await resolveEngine(2000));
// 1. Collect the public automation/incognito facts (gated under security-fraud).
const signals = [];
for (const f of BOT_SIGNAL_PROBES) {
if (!gate.granted(f.purpose)) continue;
const s = await f.create(gate).read();
if (s) signals.push(s);
}
// 2. Score behavior locally (raw events stay on the device; only the score is sent).
const behavior = createBehaviorCollector(gate);
behavior.start();
// … later, at submit time:
const anomalyScore = behavior.flush(); // number in [0,1] or null
// 3. Answer a server liveness challenge with the non-extractable device key.
const key = new DeviceKey(createMemoryKeyStore()); // IndexedDB store in the browser
const proof = await key.sign(`${cid}|${nonce}|${anomalyScore}`);Honest limits
The behavioral scorer ships in the client, so a determined bot can read + evade it — it's a cheap pre-filter against naive automation, treated raise-only. The robust anti-bot signal is server-side (request-timing regularity the client can't fake). Liveness proves a cooperating device answered a challenge, not a human. All of this is additive risk data, never a blind verdict.
License
MIT.
