@sentineld/browser
v1.3.2
Published
Browser SDK for Sentinel fraud detection and device fingerprinting
Downloads
796
Maintainers
Readme
@sentinel-sdk/browser
Browser SDK for Sentinel fraud detection and device fingerprinting. Identify visitors, detect bots, and assess fraud risk in real-time.
Installation
npm install @sentinel-sdk/browserOr via CDN:
<script src="https://unpkg.com/@sentinel-sdk/browser@latest/dist/sentinel.min.js"></script>Quick Start
ES Modules
import Sentinel from '@sentinel-sdk/browser';
// Initialize with your API key
Sentinel.init({
endpoint: 'https://sentinel.yourdomain.com/api',
apiKey: 'pk_live_xxxxxxxxxxxxx',
});
// Identify the current visitor
const result = await Sentinel.identify();
console.log(result.visitor_id); // Unique visitor ID
console.log(result.is_new); // First time seeing this visitor
// Send visitor_id to your backend -- fetch risk scores
// server-side using the sk_live_* secret key APIScript Tag
<script src="https://unpkg.com/@sentinel-sdk/browser@latest/dist/sentinel.min.js"></script>
<script>
Sentinel.init({
endpoint: 'https://sentinel.yourdomain.com/api',
apiKey: 'pk_live_xxxxxxxxxxxxx',
});
Sentinel.identify().then(function(result) {
console.log('Visitor ID:', result.visitor_id);
});
</script>Configuration
Sentinel.init({
endpoint: string, // Your Sentinel API endpoint
apiKey: string, // Your public API key (pk_live_xxx)
});| Option | Type | Required | Description |
|--------|------|----------|-------------|
| endpoint | string | Yes | Your Sentinel API base URL |
| apiKey | string | Yes | Public API key (pk_live_ prefix). Used for request signing, encryption, and Proof-of-Work authentication. |
API Reference
Sentinel.init(config)
Initialize the SDK. Must be called before other methods.
Calling init() eagerly starts background work so that identify() is fast:
- Fingerprint collection (canvas, WebGL, audio, fonts)
- WebRTC network signal gathering
- WASM crypto module loading (signing, encryption, PoW solver)
- Anti-debug monitoring
Sentinel.identify(params?)
Identify the current visitor and get risk assessment.
A single call handles the full pipeline: collecting signals, fetching and solving a Proof-of-Work challenge, encrypting and signing the payload, and sending it to the server. No separate setup steps are needed.
const result = await Sentinel.identify({
sessionId: 'optional-session-id', // Auto-generated if not provided
accountId: 'user-123', // Optional: link to your user ID
});
// Returns:
{
visitor_id: string, // Stable visitor identifier
confidence: number, // Fingerprint confidence (0-1)
method: string, // Resolution method ("fingerprint")
is_new: boolean, // First time seeing this visitor
visit_count: number, // Total visits from this device
}
// Risk and automation scores are NOT returned to the browser.
// Fetch them server-side using your sk_live_* key:
// GET /api/v1/visitors/{visitor_id}/eventsSentinel.track(params)
Track a custom event (e.g., login, purchase, signup).
const result = await Sentinel.track({
type: 'login', // Event type
accountId: 'user-123', // Optional: your user ID
metadata: { // Optional: custom data
method: 'password',
success: true,
},
});Sentinel.getVisitorId()
Get the current visitor's fingerprint hash without making an API call.
const visitorId = await Sentinel.getVisitorId();Sentinel.detectIncognito()
Detect if the browser is in incognito/private mode.
const isIncognito = await Sentinel.detectIncognito();What Happens Under the Hood
When you call identify() or track(), the SDK performs these steps in parallel for minimal latency:
Collect signals — fingerprint (canvas, WebGL, audio, fonts), network (WebRTC), behavior (mouse/keyboard patterns), integrity (headless/stealth/VM/extension detection), and validation signals (UA, screen, timezone, languages).
Fetch & solve Proof-of-Work — requests a challenge from
GET /v1/challengeand solves it using a native WASM SHA-256 loop. The solution is attached asX-Pow-IdandX-Pow-Nonceheaders. This runs concurrently with signal collection so it adds zero extra latency.Encrypt & sign — the payload is AES-GCM encrypted and HMAC-SHA256 signed using the
pk_live_API key. Both operations use the WASM crypto module when available.POST — sends the encrypted, signed payload with PoW headers. The server decrypts, verifies the signature, validates the PoW solution, cross-references HTTP headers against SDK-reported values, and returns the risk assessment.
init() identify()
│ │
├─ Load WASM crypto ├─ Collect signals ──────┐
├─ Start fingerprinting ├─ Fetch PoW challenge ──┤ (parallel)
├─ Start network probes │ │
├─ Start anti-debug │ Solve PoW (WASM) ─────┘
│ │
│ ├─ Sign + Encrypt payload
│ ├─ POST /v1/identify
│ └─ Return risk resultSecurity Features
Proof-of-Work
Every identify() and track() call requires solving a SHA-256 Proof-of-Work challenge before the server accepts it. This raises the cost of automation — a bot farm must burn real CPU per request.
- Default difficulty: 16 leading zero bits (~65K SHA-256 hashes, ~30-50ms)
- Adaptive difficulty: repeated failures from the same IP increase difficulty (up to +8 bits, making it 256x harder)
- The solver runs inside a compiled WASM binary with integrity verification — there is no JavaScript fallback to reverse-engineer
Payload Encryption & Signing
All request bodies are AES-GCM encrypted and HMAC-SHA256 signed. The server decrypts and verifies signatures before processing. Replay attacks are prevented by unique nonces and timestamps.
HTTP Header Validation
The server cross-references actual HTTP headers against SDK-reported values:
| Check | What it catches |
|-------|----------------|
| User-Agent mismatch | curl with spoofed payload |
| Accept-Language mismatch | Forged language signals |
| Sec-CH-UA mismatch | Wrong browser family claims |
| Missing Sec-Fetch-Site | Non-browser HTTP clients |
| Missing Sec-CH-UA | Automation tools omitting client hints |
| Connection: keep-alive | HTTP/1.1 libraries pretending to be browsers |
Anti-Debug & Anti-Tampering
The SDK detects and deters reverse engineering:
- Passive detection — timing API integrity checks, Image.id getter traps for DevTools, native function code-length monitoring, requestAnimationFrame cadence analysis, stack depth anomaly detection
- Active deterrence —
debuggerstatement bombing only activates after high-confidence detection (score-based system with threshold) - Anti-tampering — self-defending function wrappers, environment verification, code integrity checks, prototype modification detection
- Stealth detection — catches puppeteer-stealth, playwright-stealth, and similar plugins through Function.toString anomalies, iframe isolation checks, Chrome runtime inconsistencies, and Proxy wrapper detection
Bot & Automation Detection
Signals collected and scored server-side:
- WebDriver / navigator.webdriver flag
- Headless browser indicators (missing plugins, languages, WebGL, Chrome runtime)
- CDP markers (Puppeteer, Playwright, Selenium, ChromeDriver)
- VM detection (VMware, VirtualBox, Parallels, QEMU)
- Canvas and WebGL manipulation detection
- Privacy/automation extension detection
- VPN, proxy, and datacenter IP detection (MaxMind GeoIP + datacenter CIDR lists)
Risk Scores
| Score Range | Risk Level | Description | |-------------|------------|-------------| | 0-20 | Low | Likely legitimate user | | 21-50 | Medium | Some suspicious signals | | 51-80 | High | Likely fraudulent | | 81-100 | Critical | Strong fraud indicators |
Common Risk Reason Codes
| Code | Description |
|------|-------------|
| BOT_WEBDRIVER | WebDriver/automation detected |
| BOT_HEADLESS | Headless browser detected |
| BOT_CDP | Chrome DevTools Protocol automation |
| BOT_STEALTH | Stealth plugin detected |
| VPN_DETECTED | VPN/proxy detected |
| DATACENTER_IP | IP from datacenter range |
| TZ_MISMATCH | Timezone doesn't match IP location |
| INCOGNITO | Private browsing mode |
| HTTP_UA_MISMATCH | HTTP User-Agent doesn't match SDK-reported UA |
| MISSING_CLIENT_HINTS | Browser should send Sec-CH-UA but it's missing |
| MISSING_SEC_FETCH | Browser should send Sec-Fetch-Site but it's missing |
| SIGNAL_INCONSISTENCY | Multiple signal cross-validation failures |
Server Configuration
The Sentinel API server is configured via environment variables:
| Variable | Default | Description |
|----------|---------|-------------|
| SENTINEL_PORT | 8080 | API server port |
| SENTINEL_POSTGRES_DSN | — | PostgreSQL connection string (required) |
| SENTINEL_REDIS_ADDR | localhost:6379 | Redis address |
| SENTINEL_HMAC_SECRET | — | Server-side HMAC secret (required) |
| SENTINEL_ALLOWED_ORIGINS | localhost | CORS allowed origins |
| SENTINEL_POW_ENABLED | true | Enable Proof-of-Work challenges |
| SENTINEL_POW_DIFFICULTY | 16 | PoW difficulty (leading zero bits) |
| SENTINEL_REQUIRE_API_KEY | false | Require API keys on SDK routes |
| SENTINEL_MAXMIND_CITY_PATH | — | Path to GeoLite2-City.mmdb |
| SENTINEL_MAXMIND_ASN_PATH | — | Path to GeoLite2-ASN.mmdb |
| SENTINEL_ENABLE_PROXY_DETECTION | true | Enable VPN/proxy risk scoring |
TypeScript
Full TypeScript support is included. Import types:
import Sentinel, {
SentinelConfig,
IdentifyResponse,
EventResponse,
} from '@sentinel-sdk/browser';Browser Support
Requires WebAssembly support (all modern browsers):
- Chrome 57+
- Firefox 52+
- Safari 11+
- Edge 16+
License
MIT
