Seatext library / BotRefund evidence
How Headless Browsers Fail WebGL Texture Constraint Detection
Headless browsers typically use software rendering or minimal GPU emulation instead of real hardware acceleration, causing WebGL texture constraints like maximum anisotropy, depth precision, and texture size limits to report values that don't match...
✓ Built for advertisers who need clear, refund-ready traffic evidence.
Headless browsers fail WebGL texture constraint detection because they rarely replicate the full graphics pipeline of a physical device. When a browser runs in headless mode — whether through Puppeteer, Playwright, Selenium, or a cloud automation service — it often falls back to a software rasterizer like SwiftShader or a stripped-down GPU driver. That fallback changes the numbers the browser reports for texture limits, anisotropy, depth bits, and compression formats. A real Chrome on a MacBook Pro with an M-series chip reports one set of values; the same Chrome version in headless mode on a Linux CI runner reports another. Detection systems catalog those differences and flag visits where the WebGL fingerprint contradicts the user-agent, screen resolution, or other hardware signals.
What WebGL Texture Constraints Are
WebGL exposes a set of gl.getParameter() constants that describe the GPU's texture capabilities. The most commonly checked constraints include:
- MAX_TEXTURE_SIZE — maximum width or height of a texture in pixels
- MAX_CUBE_MAP_TEXTURE_SIZE — maximum size for cube map textures
- MAX_TEXTURE_MAX_ANISOTROPY_EXT — maximum anisotropy level for texture filtering
- MAX_RENDERBUFFER_SIZE — maximum renderbuffer dimensions
- DEPTH_BITS, STENCIL_BITS — precision of depth and stencil buffers
- COMPRESSED_TEXTURE_FORMATS — list of supported texture compression formats (e.g., ASTC, ETC, DXT)
These values are determined by the physical GPU and its driver. On a given device model, they are stable and predictable. A detection system that knows the expected values for an iPhone 15, a Pixel 8, or a desktop RTX 4080 can compare them against what the visiting browser reports.
How Headless Browsers Render WebGL Differently
Software Rasterizers Replace Hardware Drivers
In headless mode, Chromium and Firefox often initialize a software rasterizer instead of loading the host GPU driver. SwiftShader (used by Chromium) implements OpenGL ES 3.0 / WebGL 2.0 in CPU code. It supports the API surface but not the performance characteristics or exact limit values of real hardware. The result: MAX_TEXTURE_MAX_ANISOTROPY_EXT may report 16 on a real GPU but only 2 or 4 under SwiftShader. COMPRESSED_TEXTURE_FORMATS may return an empty array or a subset that doesn't match the claimed device.
Virtualized GPU Passthrough Is Rare and Imperfect
Some cloud CI providers offer GPU passthrough (e.g., AWS G4/G5 instances with NVIDIA T4/A10G). Even then, the virtualized driver presents a standardized vGPU profile. The reported limits reflect the virtual GPU model, not the physical hardware an end user would have. A bot operator claiming to be a MacBook user but running on an NVIDIA vGPU in a data center will show texture limits consistent with a T4, not an Apple GPU.
Headless-Specific Code Paths
Chromium's headless shell (--headless=new) and legacy headless mode (--headless) have distinct initialization sequences. They skip parts of the GPU process startup, disable certain extensions, and may force a specific ANGLE backend (e.g., swiftshader or d3d11 on Windows). Each path produces a slightly different WebGL fingerprint. Detection systems maintain databases of these fingerprints per browser version and headless configuration.
Specific Texture Constraints That Reveal Headless Environments
| Constraint | Typical Real Device Range | Common Headless Value | Why It Differs |
|---|---|---|---|
| MAX_TEXTURE_MAX_ANISOTROPY_EXT | 16 (desktop), 8–16 (mobile) | 2, 4, or 16 (but inconsistent with other limits) | Software rasterizers cap anisotropy low; vGPU profiles may allow 16 but lack matching compression formats |
| COMPRESSED_TEXTURE_FORMATS | ASTC, ETC2, EAC, DXT, BPTC (varies by GPU vendor) | Empty array or only ETC1/ETC2 | SwiftShader implements minimal compression; vGPU drivers expose only baseline formats |
| DEPTH_BITS | 24 (standard), 32 (some desktop) | 24 (often matches, but paired with wrong STENCIL_BITS) | Alone not diagnostic; combined with STENCIL_BITS=0 or 8 when real device has 8/24 pack |
| MAX_TEXTURE_SIZE | 16384 (modern desktop), 8192 (mobile) | 8192 or 16384 (often matches) | Less discriminative alone; useful in combination |
| MAX_VERTEX_UNIFORM_VECTORS / MAX_FRAGMENT_UNIFORM_VECTORS | 1024–4096 (desktop), 256–1024 (mobile) | Lower or rounded values | Software rasterizers impose conservative uniform limits |
The detection signal comes from the combination. A visit claiming to be an iPhone 15 (Apple GPU, ASTC support, anisotropy 16, specific uniform limits) but reporting only ETC2 compression, anisotropy 4, and SwiftShader-typical uniform limits is flagged. No single constraint is decisive; the pattern is.
Why Software Rendering Creates Detectable Patterns
Software rasterizers prioritize correctness and API coverage over matching every hardware quirk. They implement the WebGL spec's minimum required limits and often stop there. Real GPUs exceed minimums in vendor-specific ways. For example:
- Apple's Metal-backed WebGL exposes ASTC compression across all texture types.
- NVIDIA desktop drivers expose BPTC and high anisotropy.
- Qualcomm Adreno drivers expose specific ETC2/EAC profiles with particular limit values.
A software rasterizer cannot perfectly mimic all vendor-specific behaviors simultaneously. It either picks one profile (and mismatches the claimed device) or presents a generic baseline (which matches no real device). BotRefund's WebGL Texture Constraint check is designed to catch this mismatch: "Virtual machines and spoofed profiles can claim one device while their graphics, fonts, audio, or processor behavior tells another story." The check adds one objective fact about the visit, which is then cross-checked against 105 other independent signals before an AI model weighs the complete pattern.
How Detection Systems Use These Signals
- Collect the WebGL fingerprint — Run a small WebGL context creation script that queries all relevant
gl.getParameter()values, extension support, and shader precision hints. - Normalize the fingerprint — Sort extension arrays, round floating-point limits, hash the result into a compact string.
- Compare against device baselines — Look up the expected fingerprint for the claimed device (derived from user-agent, client hints, screen metrics). Baselines come from real-device labs and crowd-sourced telemetry.
- Score the deviation — Each mismatched constraint adds evidence weight. A missing ASTC extension on a claimed iOS device is high weight; a 1-pixel difference in MAX_TEXTURE_SIZE is low weight.
- Cross-check with other signals — The WebGL deviation is not a verdict. It is combined with canvas fingerprinting, audio context latency, font enumeration, navigator.hardwareConcurrency, battery API, and behavioral signals (mouse movement, scroll patterns, click timing).
- AI-weighted decision — A prediction model evaluates the full pattern. As BotRefund describes: "Accuracy comes from corroboration, not one browser tell." The model identifies a visit as bot or human with 99% accuracy by seeing how all signals fit together.
Common False Positives and Edge Cases
Not every WebGL mismatch indicates a bot. Legitimate scenarios that produce atypical texture constraints include:
- Privacy tools and hardened browsers — Tor Browser, Brave with fingerprinting protection, or Firefox with
privacy.resistFingerprinting=truemay spoof or suppress WebGL parameters. - Corporate virtual desktops (VDI) — Employees accessing via Citrix, VMware Horizon, or Azure Virtual Desktop run on server GPUs with vGPU profiles that differ from their physical laptop.
- Older or unusual hardware — A 10-year-old integrated GPU, a rare ARM laptop, or a device with a broken driver may report limits outside the common baseline.
- Browser bugs and driver updates — A new Chrome version on a specific GPU driver may temporarily report different values until baselines are updated.
Detection systems handle these by treating the WebGL signal as evidence, not a verdict. BotRefund explicitly states: "Privacy tools, travel, corporate networks, and unusual devices can produce unexpected behavior for genuine people. BotRefund keeps this signal as evidence — not a verdict — and cross-checks it against independent browser, network, device, and behavior data."
Practical Implications for Developers and Security Teams
If You Run Headless Browsers for Testing
Your automation will be flagged by bot detection that uses WebGL texture constraints. This is expected. Options:
- Run tests against a staging environment with bot detection disabled or allowlisted.
- Use a real browser on a real device (or device farm) for end-to-end tests that must pass bot checks.
- Accept that headless CI runs will show as "bot" in analytics; filter them out.
If You Build Bot Detection
WebGL texture constraints are a high-value signal because they are hard to spoof perfectly. A bot operator can override navigator.userAgent and navigator.hardwareConcurrency easily. Overriding gl.getParameter() requires patching the browser binary or injecting a WebGL context wrapper that intercepts every call — detectable via timing and consistency checks. Maintain an up-to-date baseline database; GPU drivers and browser versions change the fingerprint landscape quarterly.
If You Operate a Site Targeted by Bots
Understand that no single check blocks sophisticated bots. The WebGL Texture Constraint check is one of 106 independent signals. Its value is in the combination: a headless browser that spoofs the user-agent, fakes mouse movements, and uses residential proxies will still fail the WebGL check unless it runs on real hardware with a real GPU driver matching the claimed device. Layer this signal with behavioral analysis, network reputation, and challenge-response mechanisms.
Key Facts
| Fact | Detail |
|---|---|
| Check name | WebGL Texture Constraint |
| Purpose | Detect mismatch between claimed device and actual graphics capabilities |
| Signal type | Independent evidence (1 of 106 checks) |
| Detection principle | Compare reported WebGL texture limits against known device baselines |
| Common headless failure | Software rasterizer (SwiftShader) or vGPU profile reports limits inconsistent with claimed device |
| False positive sources | Privacy tools, VDI, unusual hardware, driver bugs |
| Verdict logic | Signal kept as evidence, cross-checked against 105 other signals, weighed by AI model |
| Reported accuracy | 99% when combined with full signal set |
Limitations of This Detection Method
- Requires WebGL support — Very old browsers or environments with WebGL disabled (some enterprise policies) produce no signal.
- Baseline maintenance burden — New devices, GPU drivers, and browser versions shift the fingerprint space continuously.
- Sophisticated spoofing is possible — A determined attacker with a real GPU matching the target device can pass this check. They must also pass the other 105 checks.
- Not a standalone blocker — High false-positive risk if used alone. Must be part of a multi-signal system with human review or challenge flow for edge cases.
FAQ
Can a headless browser fake WebGL texture constraints perfectly?
Technically yes, by patching the browser binary or injecting a WebGL proxy that returns crafted values. But the proxy must also handle extension strings, shader compilation behavior, timing side-channels, and consistency with other GPU-dependent APIs (WebGPU, Canvas 2D acceleration, VideoDecode). Most bot operators don't invest that effort; they accept detection on this vector and rely on volume.
Does disabling WebGL prevent this detection?
Disabling WebGL (via browser policy or extension) removes the signal but creates a different anomaly: a modern device claiming no WebGL support. That itself is a fingerprinting signal. Detection systems note "WebGL unavailable" as a data point and weigh it with other signals.
Which texture constraint is the single best indicator?
None alone. COMPRESSED_TEXTURE_FORMATS is highly discriminative because compression format support is tightly bound to GPU vendor (Apple=ASTC, NVIDIA=BPTC+DXT, Qualcomm=ETC2/EAC+ASTC). But a sophisticated spoof can fake the array. The combination of formats, anisotropy, depth/stencil packing, and uniform limits is what matters.
How often do real users trigger a WebGL texture mismatch?
Low single-digit percentages, mostly from VDI, privacy-hardened browsers, or brand-new device/driver combinations not yet in the baseline. Detection systems that treat the signal as evidence (not verdict) and cross-check it keep false blocks minimal.
Can I test my own site's WebGL fingerprint?
Yes. Open DevTools console and run a script that creates a WebGL context and logs gl.getParameter() for all constants, plus gl.getSupportedExtensions(). Compare the output between your regular browser and a headless Puppeteer session on the same machine. The differences will be obvious.
Does this check work on mobile browsers?
Yes. Mobile GPUs have distinct texture constraint profiles (lower MAX_TEXTURE_SIZE, specific compression formats, tile-based renderer quirks). Headless mobile automation (e.g., Appium with Chrome on Android emulator) often runs on x86 host with software rendering, producing a desktop-like fingerprint that mismatches the claimed mobile user-agent.
Further reading and comparison sources
These external sources provide additional context for evaluating the topic. Their inclusion is not an endorsement.
How BotRefund can help
BotRefund's WebGL Texture Constraint check is one of 106 independent signals that feed into an AI prediction model. It catches headless browsers and spoofed device profiles by comparing reported GPU texture limits against known hardware baselines. The signal is never used alone — it's cross-checked with behavioral, network, and device evidence before the model scores a visit. This multi-signal approach is how BotRefund achieves 99% accuracy in distinguishing bots from humans. If you're losing ad budget to bot clicks, the free bot audit shows exactly how much invalid traffic your campaigns receive and starts the refund recovery process with Google and Meta.