#351·pydoll

[Feature Request]: query selector hcaptcha leak

Author: mikolajkniejskiCreated Jan 23, 2026Updated Feb 6, 2026
Labelsenhancement

Checklist before requesting

  • I have searched for similar feature requests and didn't find a duplicate.
  • I have checked the documentation to confirm this feature doesn't already exist.

Problem Statement

Bot detectors like hcaptcha replace querySelector with proxy which counts the number of time you use it. PyDoll makes use of querySelector to find elements which is how h captcha is detecting py doll. I'm not sure if it makes any difference, but possibly https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-querySelector method is not detectable.

This is sligthly deminified code from hcaptcha.

  a = function (object, property) {
    // 1. Get the property descriptor (metadata about the property)
    var property_descriptor = Object.getOwnPropertyDescriptor(object, property);

    // 2. Skip if property is non-writable (can't be replaced)
    if (!(property_descriptor && false === property_descriptor.writable)) {

      var l,
          c = Object.prototype.hasOwnProperty.call(object, property), // was it own property?
          h = object[property];  // save original function

      // 3. Create a wrapper that intercepts calls
      l = "undefined" != typeof Proxy && "undefined" != typeof Reflect
        ? new Proxy(h, {
            apply: function (t, r, a) {
              // TRACK THE CALL: if monitoring enabled (n), log it
              n && (e.length >= 10 && o(), i(new Error()));  // captures stack trace
              return Reflect.apply(t, r, a);  // call original
            },
          })
        : function () {
            // Fallback for older browsers without Proxy
            n && (e.length >= 10 && o(), i(new Error()));
            return h.apply(this, arguments);
          };

      // 4. Replace the original method with the wrapper
      Object.defineProperty(object, property, {
        configurable: true,
        enumerable: !property_descriptor || property_descriptor.enumerable,
        writable: true,
        value: l,  // the proxy wrapper
      });

      // 5. Save a cleanup function to restore the original later
      arr_with.push(function () {
        c ? Object.defineProperty(object, property, { /* restore original */ })
          : delete object[property];
      });
    }
  };

Proposed Solution

Use https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-querySelector

Alternatives Considered

No response

Additional Context

No response

Importance

Critical (blocking my usage)

Contribution

None