Most scraping and checkout-abuse tooling is built on top of the same handful of frameworks: Selenium, Puppeteer, and Playwright. That’s convenient for bot operators, because these frameworks are well-documented and easy to script. It also means they leave a consistent, well-understood fingerprint behind.

What gives them away

A few of the more reliable signals:

  • WebDriver flags: navigator.webdriver and related automation properties are set by default unless a bot operator specifically patches them out
  • Software-rendered GPUs: headless environments frequently fall back to software rendering (SwiftShader, llvmpipe) instead of real hardware, which shows up clearly in WebGL and canvas fingerprints
  • Inconsistent environment claims: a user agent claiming to be Chrome on macOS, paired with fonts, timezone, and hardware concurrency that don’t match any real Mac, is a strong tell
  • Missing or synthetic interaction: no real GPU-accelerated compositing, no natural input timing, and event listeners that fire in patterns no human input device produces

Why patching one signal isn’t enough

Sophisticated bot operators do patch some of this: spoofing navigator.webdriver, faking a GPU vendor string, injecting fake mouse movement. Cross-checking still works because spoofing every signal consistently is expensive. A patched WebDriver flag doesn’t fix a mismatched WebGL renderer. A scripted mouse path doesn’t reproduce the micro-jitter of a real trackpad.

Skyfense scores dozens of these signals together rather than trusting any single one. A session that’s clean on nineteen signals and inconsistent on one gets a very different verdict than a session that’s inconsistent across the board, and that combination is much harder for automation frameworks to fake all at once.