Seatext library / BotRefund evidence

How to Implement Browser API Inconsistency Detection on Your Website

Browser API inconsistency detection works by probing standard browser APIs and comparing their behavior against expected baselines. Automation tools often patch or hide APIs in ways that create detectable mismatches. You can implement this...

Built for advertisers who need clear, refund-ready traffic evidence.

Browser API inconsistency detection identifies automated browsers by checking whether standard web APIs behave the way they do in a genuine user session. Automation frameworks like Playwright, Puppeteer, and Selenium often modify or suppress browser APIs to avoid detection, but those modifications can create subtle inconsistencies — missing properties, altered function prototypes, or mismatched values across related APIs. By running targeted JavaScript probes, you can collect these anomalies as signals and combine them with other evidence to distinguish bots from real visitors.

What Browser API Inconsistency Detection Covers

This technique examines the JavaScript environment that a browser exposes to web pages. A normal browser runs standard APIs as designed — its built-in properties, permissions, and rendering contexts remain consistent without needing to hide automation. An automated browser often reveals itself through mismatches that a real browsing session does not normally create. The goal is not to block visitors on a single anomaly but to gather independent pieces of evidence that, when cross-checked, form a reliable picture.

BotRefund uses 106 independent checks of this type, including probes for Playwright initialization scripts and clean context iframe mismatches. Each check adds one objective fact about the visit, and the system weighs the complete pattern instead of trusting a raw rule. This corroboration approach is what enables their reported 99% accuracy in bot identification.

Why API Inconsistencies Appear in Automated Browsers

Automation tools patch browser APIs for two main reasons: to hide the presence of automation and to provide convenient testing utilities. For example, Playwright injects initialization scripts that modify navigator.webdriver, override console.debug, or alter document.createElement behavior. These patches can break when the browser is checked from another angle — such as inside a clean iframe context or through a different API surface. The inconsistency between the patched main context and an unpatched secondary context becomes a detectable signal.

Privacy tools, corporate networks, and unusual devices can also produce unexpected API behavior for genuine users. That is why a single anomaly should never be a verdict. Treat each inconsistency as evidence, not a decision, and cross-check it against network, device, and behavioral signals before taking action.

Core Browser APIs to Monitor

Focus your probes on APIs that automation tools commonly modify and that have verifiable baseline behaviors:

  • navigator.webdriver — The standard automation flag. Real browsers return false or undefined; many automation frameworks forget to suppress it or set it inconsistently.
  • navigator.permissions — Query permission states for notifications, geolocation, camera. Automated browsers often return denied or prompt in patterns that do not match user settings.
  • window.chrome and chrome.runtime — Chrome-specific objects that headless modes often omit or populate incompletely.
  • document.createElement and HTMLElement prototypes — Automation scripts sometimes wrap or monkey-patch these to intercept element creation.
  • console.debug, console.log — Playwright and similar tools override console methods to capture logs, changing their toString() representation.
  • Canvas and WebGL fingerprinting surfacesHTMLCanvasElement.prototype.toDataURL, WebGLRenderingContext.getParameter. Headless browsers often return generic or software-renderer values.
  • Screen and device propertiesscreen.width, screen.height, devicePixelRatio, navigator.hardwareConcurrency. Mismatches between reported values and CSS media query results indicate spoofing.
  • iframe sandbox and contentWindow — A clean context iframe (one without the parent's automation patches) can reveal discrepancies in API availability or behavior between the main frame and the isolated frame.

Step-by-Step Implementation

  1. Establish a baseline. Run your probe suite in a variety of real browsers (Chrome, Firefox, Safari, Edge) on desktop and mobile, with and without common privacy extensions. Record the expected values, property descriptors, and function toString() outputs for each API. Store this baseline as a versioned JSON fixture.
  2. Write isolated probe functions. Each probe should test one API surface and return a structured result: { name: 'navigator.webdriver', expected: false, actual: value, anomaly: boolean, details: {...} }. Keep probes pure — no side effects, no DOM mutations.
  3. Check property descriptors. Use Object.getOwnPropertyDescriptor on navigator, window, document, and HTMLElement.prototype. Look for configurable: false where it should be true, missing get/set functions, or descriptors that differ from the baseline.
  4. Compare function toString() outputs. Native functions return "function foo() { [native code] }". Wrapped or patched functions often reveal their wrapper source. Compare against your baseline strings.
  5. Run cross-context checks. Create a sandboxed iframe (sandbox="allow-scripts" without allow-same-origin) and execute a subset of probes inside it. Compare results between the main context and the clean context. Discrepancies suggest the main context has been patched.
  6. Validate API relationships. Certain APIs must agree. Example: screen.width * devicePixelRatio should match window.outerWidth within a small tolerance. navigator.hardwareConcurrency should be a plausible integer for the device class. navigator.maxTouchPoints should align with window.matchMedia('(pointer:coarse)').
  7. Collect timing and execution anomalies. Measure how long probe functions take. Automation overhead or debugger attachment can add measurable latency. Flag probes that exceed a dynamic threshold (e.g., 3x the median baseline duration).
  8. Aggregate and score. Feed each probe result into a scoring function. Weight high-specificity signals (clean context mismatch, native code mismatch) higher than low-specificity ones (single property deviation). Output a structured evidence object, not a binary allow/block decision.
  9. Integrate with your analytics or fraud pipeline. Send the evidence object alongside session metadata (IP, user agent, click ID, timestamp) to your logging or analysis system. BotRefund structures each finding into a refund-ready report with click IDs, campaign details, timestamps, session recordings, and signal-by-signal reasoning — a format that Google and Meta review teams accept.
  10. Version and update baselines. Browser updates change API surfaces. Schedule quarterly baseline refreshes and automate regression tests against a browser farm (BrowserStack, Sauce Labs, or a local device lab).

Common Probe Patterns and Code Sketches

Property Descriptor Check

function probePropertyDescriptor(obj, prop) {
  const desc = Object.getOwnPropertyDescriptor(obj, prop);
  if (!desc) return { anomaly: true, reason: 'missing' };
  const baseline = BASELINE[prop];
  return {
    anomaly: desc.configurable !== baseline.configurable ||
             typeof desc.get !== baseline.getType ||
             typeof desc.set !== baseline.setType,
    actual: { configurable: desc.configurable, get: typeof desc.get, set: typeof desc.set },
    expected: baseline
  };
}

Function Native Code Check

function probeNativeFunction(obj, method) {
  const fn = obj[method];
  if (typeof fn !== 'function') return { anomaly: true, reason: 'not a function' };
  const str = fn.toString();
  const isNative = /^\s*function\s+\w+\s*\([^)]*\)\s*\{\s*\[native code\]\s*\}/.test(str);
  return { anomaly: !isNative, actual: str.slice(0, 200) };
}

Clean Context Iframe Check

async function probeCleanContext(probeNames) {
  return new Promise(resolve => {
    const iframe = document.createElement('iframe');
    iframe.sandbox = 'allow-scripts';
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
    const results = {};
    iframe.contentWindow.addEventListener('message', e => {
      if (e.data.type === 'probeResults') {
        results.clean = e.data.payload;
        document.body.removeChild(iframe);
        resolve(results);
      }
    });
    iframe.contentWindow.postMessage({ type: 'runProbes', probes: probeNames }, '*');
  });
}

The iframe page runs the same probes and posts results back. Compare mainContextResults vs cleanContextResults for each probe name.

Verification and Testing

After deploying probes, verify they work as intended:

  1. Test against known automation. Run Playwright, Puppeteer, and Selenium scripts (headless and headed) against your instrumented page. Confirm each framework triggers at least 3-5 distinct anomalies.
  2. Test real browsers with extensions. Install popular privacy extensions (uBlock Origin, Privacy Badger, Ghostery) and verify they do not trigger false positives on your high-weight probes. Adjust baselines or add allow-list logic for known extension side effects.
  3. Measure probe overhead. Ensure the full probe suite completes in under 100ms on a mid-tier mobile device. Defer non-critical probes to requestIdleCallback or run them asynchronously after page load.
  4. Log anomaly rates. Track the percentage of sessions flagging each anomaly. A probe that fires on >5% of real traffic likely needs baseline adjustment or lower weight.

Limitations and When This Approach Does Not Apply

  • Sophisticated evasion frameworks (e.g., undetected-chromedriver, Playwright Stealth) actively patch the same inconsistencies your probes target. They maintain parity with real browser baselines across many API surfaces. API inconsistency detection alone cannot catch these; you need behavioral, network, and device signals as corroboration.
  • Privacy-focused browsers and extensions (Brave, Tor Browser, hardened Firefox configs) intentionally modify APIs like navigator.webdriver, navigator.plugins, screen values, and canvas fingerprinting surfaces. Treat these as a distinct segment — flag for review, do not auto-block.
  • Mobile webviews and in-app browsers (Instagram, Facebook, TikTok, LINE) often expose stripped-down API surfaces. Baseline these separately or exclude them from API inconsistency scoring.
  • Client-side only. This detection runs in the browser. It cannot see server-side request anomalies, IP reputation, or infrastructure-level signals. Pair it with server-side log analysis for a complete picture.
  • Maintenance burden. Browser releases change API behavior. A probe suite that works today may produce false positives after a Chrome or Safari update. Budget for ongoing baseline maintenance.

Key Facts

Fact Detail Source
Number of independent browser checks BotRefund uses 106 S1
Playwright Init Scripts check purpose Detects mismatches from automation patches that break when checked from another angle S1
Clean Context Iframe check purpose Reveals API discrepancies between main frame and isolated iframe context S6
Single anomaly policy Treated as evidence, not a verdict; cross-checked against browser, network, device, behavior data S1, S5, S6
Reported bot identification accuracy 99% via AI prediction weighing complete pattern across all signals S1, S2
Refund-ready report format Includes click IDs, campaign details, timestamps, session recordings, signal-by-signal reasoning S2
Client refund recovery rate 83% of 2,500+ audited brands recover funds from Google and Meta S2

Terminology

API inconsistency
A measurable difference between the observed behavior of a browser API and its expected baseline in a genuine user session.
Clean context
An execution environment (typically a sandboxed iframe) that does not inherit the parent page's JavaScript modifications, used as a reference for cross-context comparison.
Monkey-patching
Runtime modification of built-in objects or functions, commonly used by automation frameworks to hide their presence or add testing utilities.
Native code
The string representation of a built-in browser function ("function foo() { [native code] }"), which differs from user-defined or wrapped functions.
Corroboration
The practice of requiring multiple independent signals to agree before making a classification decision, rather than relying on a single rule.

Frequently Asked Questions

How many probes do I need for a useful signal?

Start with 8-12 high-specificity probes covering the core APIs listed above. BotRefund uses 106 checks, but a focused set that includes property descriptors, native code checks, cross-context comparison, and API relationship validation will catch most commodity automation. Add probes incrementally as you observe new evasion patterns.

Can I run these probes on every page load?

Yes, but defer the full suite to requestIdleCallback or run a lightweight subset (3-4 probes) synchronously and the rest asynchronously. Total added latency should stay under 50ms on median devices. Cache baseline fixtures in localStorage or a service worker to avoid re-fetching.

What if a real user triggers an anomaly?

Log it, but do not block. Privacy extensions, corporate proxies, unusual hardware, and browser bugs can all produce anomalies. Use the anomaly as one input to a scoring model that also considers behavioral signals (mouse movement, scroll patterns, click timing), network reputation, and device consistency. BotRefund's approach keeps each signal as evidence and lets an AI model weigh the complete pattern.

How do I handle browser updates that break baselines?

Automate baseline collection. Run your probe suite against a browser farm (BrowserStack, Sauce Labs, or a local device lab) on a schedule — weekly for beta channels, monthly for stable. Compare new results against the current baseline; flag any probe where >2% of real-browser runs deviate. Update the baseline fixture after manual review.

Is server-side detection better than client-side API checks?

They serve different purposes. Server-side analysis (IP reputation, request headers, TLS fingerprinting, behavioral analytics on request sequences) catches infrastructure-level automation and scales without client cooperation. Client-side API checks catch browser-level evasion that reaches the page — headless browsers, injected scripts, and automation frameworks that execute JavaScript. Use both. BotRefund combines 110+ behavioral, browser, hardware, network, and attribution signals for this reason.

What is the simplest probe to start with today?

Check navigator.webdriver and window.chrome property descriptors, then run a clean context iframe probe for those same properties. This three-probe combination catches a large fraction of unhardened Playwright and Puppeteer sessions with minimal code.

How do I connect detection results to ad refund claims?

Attach the anomaly evidence to each ad click by capturing the click ID (GCLID for Google, FBCLID/FBP for Meta) at landing. Store the full evidence object — probe results, timestamps, session replay snippets, device and network context — alongside the click ID. When filing an invalid traffic claim, export this data in the structured format the ad platform's review team expects. BotRefund automates this end-to-end: detection, evidence preservation, report generation, and claim negotiation with an 83% success rate across 2,500+ audits.

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

Building and maintaining a reliable browser API inconsistency detection system takes ongoing engineering effort — baseline collection across browser versions, probe updates for new evasion techniques, and integration with ad-platform refund workflows. BotRefund provides this as a managed service: 106 independent browser checks (including Playwright Init Scripts and Clean Context Iframe probes), cross-checked against network, device, and behavioral signals, with an AI model that weighs the complete pattern for 99% identification accuracy. Each finding becomes a refund-ready report with click IDs, campaign details, timestamps, session recordings, and signal-by-signal reasoning formatted for Google and Meta review teams. Across 2,500+ audited brands, 83% recover funds. You can start with a free bot audit to see what your current traffic looks like.

Get free bot audit