Building @skalaio/browser: A Modern Dual-Engine Fingerprinting Library
Why single-source device IDs fail, and how we combined FingerprintJS with thumbmarkjs alongside robust anti-tampering heuristics.
Device fingerprinting is one of the most powerful tools in a fraud analyst's arsenal. Yet, standard browser fingerprinting has become fragile. Bots, headless drivers, and specialized extensions easily spoof client APIs to present artificial, clean-looking browser environments.
To solve this at Skala, we designed and built a client-side package, @skalaio/browser. In this article, we deep dive into the engineering behind our modern dual-engine fingerprinting library and detail how we achieved high-fidelity tracking with robust resistance to tampering.
The Problem with Single-Source Device IDs
Most legacy fingerprinting tools rely on a single client library (e.g., only FingerprintJS). Because of its widespread use, commercial scraping frameworks and custom extension blocks specifically target and spoof FingerprintJS internal signals. If a bot spoofs FingerprintJS, your system receives a low-entropy ID, leading to high collision rates and false negatives.
To counteract this, we implemented a dual-engine parallel execution model:
- FingerprintJS Core: Generates a reliable baseline entropy model.
- ThumbmarkJS Extension: Concurrently calculates fonts, WebGL capabilities, audio contexts, and permission APIs.
- Concurrency via Promise.all: We run both engines in parallel, capturing different attributes without increasing network and execution latency.
Robust Anti-Tampering & Anti-Anti-Browser Detection
A spoofed fingerprint is itself a high-value signal of malicious intent. @skalaio/browser runs custom checks to verify that the client environment is genuine:
- Webdriver Validation: Tracks explicit automation variables injected by drivers (like Selenium, Playwright, or Puppeteer).
- Automation Tool Detection: Scrapes window/document namespaces for key signatures (e.g.,
_phantom,callPhantom, or CDC internalcdc_..._Arrayarray-override structures). - Double-Render Canvas Verification: Rather than performing a single canvas check, the SDK draws content, extracts pixels, clears the canvas, redraws the exact same content, and compares pixel arrays. If the pixel buffers differ, it flags canvas-noise spoofing extensions.
- Firefox Headless Media Checks: Standard headless user agent flags often omit "Headless" in Firefox. Our SDK checks standard audio/video codec capability support. Since slim server nodes/containers lack H.264/MP4 media pipelines, the complete absence of codec playback options exposes virtualized servers claiming to be client machines.
- GPU Software Rendering: Software WebGL renderers (e.g., SwiftShader, llvmpipe) indicate headless virtualization. However, simple checks produce false positives on real Linux machines running Mesa drivers. We narrowed our keywords to exclusively flag software engines (
llvmpipe,software rasterizer), eliminating false flags for physical Linux setups.
Decoupled, Standalone Design Philosophy
To maintain lightweight client footprints and absolute privacy compliance, we designed the library to be completely decoupled:
- Zero Plaintext Leaks: Email addresses are auto-hashed client-side via SHA-256 before propagation, extracting only the domain name metadata to enforce disposable domain filters on the backend.
- Modular Integration: The browser SDK generates the fingerprint and lets the consumer feed it to their backend server. This separates backend score authentication keys from browser clients, preventing client-side API key exposures.
Integration Example:
import { SkalaBrowserClient } from '@skalaio/browser';
import { Skala } from '@skalaio/node';
// 1. Gather browser indicators on client side
const browserClient = new SkalaBrowserClient();
const fingerprint = await browserClient.getFingerprint();
// 2. Score request on backend
const skala = new Skala({ apiKey: process.env.SKALA_API_KEY });
const result = await skala.score({
event_type: 'signup',
ip: req.ip,
email: body.email,
device_id: fingerprint.visitorId,
metadata: {
fingerprint_tampered: fingerprint.tampered,
fingerprint_confidence: fingerprint.confidenceScore,
fingerprint_signals: fingerprint.signals,
thumbmark_id: fingerprint.thumbmarkId,
}
});By combining dual-engine telemetry with advanced anti-tampering heuristics, @skalaio/browser provides developers with a robust, privacy-respecting client validation engine.
Subscribe to Skala Engineering newsletter
Get technical deep dives into low-latency distributed systems, security architectures, and edge infrastructure delivered straight to your inbox.