Skip to content

example with puppeteer #22

@Mahkhmood8

Description

@Mahkhmood8
  // await page.evaluateOnNewDocument(() => {
  //   MouseEvent.prototype.__defineGetter__("screenX", function () {
  //     return 1;
  //   });

  //   MouseEvent.prototype.__defineGetter__("screenY", function () {
  //     return 1;
  //   });
  // });

  await page.evaluateOnNewDocument(() => {
    Object.defineProperty(MouseEvent.prototype, "screenX", {
      get: function () {
        return this.clientX + window.screenX;
      },
    });

    Object.defineProperty(MouseEvent.prototype, "screenY", {
      get: function () {
        return this.clientY + window.screenY;
      },
    });
  });

[import { launch, Launcher } from "chrome-launcher";
import puppeteer from "rebrowser-puppeteer-core";
import kill from 'tree-kill';

export const checkTurnstileOLD = ({ page }) => {
return new Promise(async (resolve, reject) => {
var waitInterval = setTimeout(() => { clearInterval(waitInterval); resolve(false) }, 5000);

try {
  const elements = await page.$$('[name="cf-turnstile-response"]');
  if (elements.length <= 0) {

    const coordinates = await page.evaluate(() => {
      let coordinates = [];
      document.querySelectorAll('div').forEach(item => {
        try {
          let itemCoordinates = item.getBoundingClientRect()
          let itemCss = window.getComputedStyle(item)
          if (itemCss.margin == "0px" && itemCss.padding == "0px" && itemCoordinates.width > 290 && itemCoordinates.width <= 310 && !item.querySelector('*')) {
            coordinates.push({ x: itemCoordinates.x, y: item.getBoundingClientRect().y, w: item.getBoundingClientRect().width, h: item.getBoundingClientRect().height })
          }
        } catch (err) { }
      });

      if (coordinates.length <= 0) {
        document.querySelectorAll('div').forEach(item => {
          try {
            let itemCoordinates = item.getBoundingClientRect()
            if (itemCoordinates.width > 290 && itemCoordinates.width <= 310 && !item.querySelector('*')) {
              coordinates.push({ x: itemCoordinates.x, y: item.getBoundingClientRect().y, w: item.getBoundingClientRect().width, h: item.getBoundingClientRect().height })
            }
          } catch (err) { }
        });

      }

      return coordinates
    })

    for (const item of coordinates) {
      try {
        let x = item.x + 30;
        let y = item.y + item.h / 2;
        await page.mouse.click(x, y);
      } catch (err) { }
    }
    return resolve(true)
  }

  for (const element of elements) {
    try {
      const parentElement = await element.evaluateHandle(el => el.parentElement);
      const box = await parentElement.boundingBox();
      let x = box.x + 30;
      let y = box.y + box.height / 2;
      await page.mouse.click(x, y);
    } catch (err) { }
  }
  clearInterval(waitInterval)
  resolve(true)
} catch (err) {
  clearInterval(waitInterval)
  resolve(false)
}

})
}
const CLOUDFLARE_CHALLENGE_URL = 'challenges.cloudflare.com/cdn-cgi/challenge-platform';
const MONITORING_INTERVAL = 2000;
const CLICK_X = 30;
const CLICK_Y = 30;
const DEFAULT_TIMEOUT = 30000;

export const checkTurnstile = ({ page, timeout = DEFAULT_TIMEOUT } = {}) => {
return new Promise(async (resolve, reject) => {
if (!page) {
return reject(new Error('Page object is required'));
}

const browser = page.browser();
let monitoringActive = true;
let activeTargets = new Set();
let targetFrameFound = false;
const startTime = Date.now();

console.log("Starting Turnstile automation...");

const sleep = (ms) => new Promise(r => setTimeout(r, ms));

const setupMobileEmulation = async (targetId, cdpSession) => {
  try {
    const result = await cdpSession.send('Runtime.evaluate', {
      expression: `
                    (() => {
                        const mobileUserAgent = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
                        const hasTouchSupport = ('ontouchstart' in window);
                        
                        return {
                            isMobile: mobileUserAgent,
                            userAgent: navigator.userAgent,
                            innerWidth: window.innerWidth,
                            touchSupport: hasTouchSupport,
                            maxTouchPoints: navigator.maxTouchPoints
                        };
                    })()
                `,
      returnByValue: true
    });

    if (result?.result?.value) {
      const deviceInfo = result.result.value;
      console.log("Device detection:", deviceInfo);

      if (deviceInfo.isMobile) {
        console.log("Mobile device detected, enabling touch events");
        await cdpSession.send('Emulation.setEmitTouchEventsForMouse', {
          enabled: true,
          configuration: 'mobile'
        });
        console.log("Mobile touch events enabled for target:", targetId);
      } else {
        console.log("Desktop device detected, using standard mouse events");
      }
    }
  } catch (error) {
    console.log("Could not detect device type, defaulting to desktop mode:", error.message);
  }
};

const performMouseClick = async (targetId, cdpSession, x, y) => {
  console.log("Performing mouse click at coordinates:", x, y);

  try {
    await sleep(20000);///LMAO DOESNT NOT NEED THIS

    await cdpSession.send('Input.dispatchMouseEvent', {
      type: 'mousePressed',///type: "mousePressed",   [[Chrome is very forgiving internally. Even if you send a touch-like type to dispatchMouseEvent, it might still trigger a DOM event (pointerdown / pointerup]]
      // type: 'mousePressed',///type: "mousePressed",   [[Chrome is very forgiving internally. Even if you send a touch-like type to dispatchMouseEvent, it might still trigger a DOM event (pointerdown / pointerup]]
      x: x,
      y: y,
      button: 'left',
      clickCount: 1
    });

    console.log("Mouse pressed at:", x, y);
    await sleep(100);///LMAO DOESNT NOT NEED THIS

    await cdpSession.send('Input.dispatchMouseEvent', {
      type: 'mouseReleased',/// type: "mouseReleased",
      x: x,
      y: y,
      button: 'left',
      clickCount: 1
    });

    console.log("Mouse released. Click completed successfully!");
    activeTargets.delete(targetId);
    targetFrameFound = true;
  } catch (error) {
    console.error("Mouse event failed:", error.message);
    activeTargets.delete(targetId);
    throw error;
  }
};

const attachToTarget = async (target) => {
  const targetId = target._targetId;
  const url = target.url();

  if (activeTargets.has(targetId)) {
    return;
  }

  const isCloudflareChallenge = url.includes(CLOUDFLARE_CHALLENGE_URL);
  if (!isCloudflareChallenge) {
    return;
  }

  console.log("Found Cloudflare challenge frame:", url);
  activeTargets.add(targetId);

  try {
    let cdpSession;

    if (target.type() === 'page') {
      const targetPage = await target.page();
      if (targetPage) {
        cdpSession = await targetPage._client();
        console.log("Got CDP session from page");
      }
    } else {
      const browserClient = await page._client();
      const result = await browserClient.send('Target.attachToTarget', {
        targetId: targetId,
        flatten: true
      });
      console.log("Created new CDP session:", result.sessionId);

      let connection = browserClient.connection?.() || browserClient.connection || browserClient._connection;

      cdpSession = connection?.sessions?.get(result.sessionId) ||
        connection?._sessions?.get(result.sessionId) ||
        connection?._sessionMap?.get(result.sessionId);

      if (!cdpSession) {
        console.log("Using fallback session wrapper");
        cdpSession = {
          _sessionId: result.sessionId,
          _browserClient: browserClient,
          send: async function (method, params = {}) {
            console.log(`Sending command: ${method}`, params);
            try {
              return await this._browserClient.send(method, params);
            } catch (error) {
              console.error(`Error sending ${method}:`, error.message);
              throw error;
            }
          }
        };
      }
    }

    console.log("Successfully attached to target:", targetId);

    await cdpSession.send('Runtime.enable');
    console.log("Runtime enabled for target:", targetId);

    await setupMobileEmulation(targetId, cdpSession);
    await sleep(500);
    await performMouseClick(targetId, cdpSession, CLICK_X, CLICK_Y);

  } catch (error) {
    console.error("Failed to attach to target:", targetId, error.message);
    activeTargets.delete(targetId);
  }
};

const checkForToken = async () => {
  try {
    const token = await page.evaluate(() => {
      try {
        let item = document.querySelector('[name="cf-turnstile-response"]')?.value;
        return item && item.length > 20 ? item : null;
      } catch (e) {
        return null;
      }
    });
    return token;
  } catch (e) {
    return null;
  }
};

const monitor = async () => {
  while (monitoringActive) {
    if (Date.now() - startTime > timeout) {
      monitoringActive = false;
      return reject(new Error('Turnstile challenge timeout'));
    }

    try {
      const targets = await browser.targets();

      for (const target of targets) {
        const type = target.type();
        const url = target.url();

        if ((type === 'page' || type === 'iframe' || type === 'other') &&
          url && url.includes('challenges.cloudflare.com')) {
          await attachToTarget(target);
        }
      }

      const token = await checkForToken();
      if (token) {
        console.log('Cloudflare Turnstile Token obtained:', token);
        monitoringActive = false;
        return resolve(token);
      }
    } catch (error) {
      console.error("Error during monitoring:", error.message);
    }

    await sleep(MONITORING_INTERVAL);
  }
};

try {
  await monitor();
} catch (error) {
  reject(error);
}

});
};

function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}

export async function pageController({ browser, page, proxy, turnstile, xvfbsession, pid, plugins, killProcess = false, chrome }) {

let solveStatus = turnstile

page.on('close', () => {
solveStatus = false
});

browser.on('disconnected', async () => {
solveStatus = false
if (killProcess === true) {
if (xvfbsession) try { xvfbsession.stopSync() } catch (err) { }
if (chrome) try { chrome.kill() } catch (err) { console.log(err); }
if (pid) try { kill(pid, 'SIGKILL', () => { }) } catch (err) { }
}
});

async function turnstileSolver() {
while (solveStatus) {
await checkTurnstile({ page }).catch(() => { });
await new Promise(r => setTimeout(r, 1000));
}
return
}

turnstileSolver()

if (proxy.username && proxy.password) await page.authenticate({ username: proxy.username, password: proxy.password });

if (plugins.length > 0) {
for (const plugin of plugins) {
plugin.onPageCreated(page)
}
}

await page.evaluateOnNewDocument(() => {
Object.defineProperty(MouseEvent.prototype, 'screenX', {
get: function () {
return 23;
}
});

Object.defineProperty(MouseEvent.prototype, 'screenY', {
  get: function () {
    return 33;
  }
});

});

// const cursor = createCursor(page);
// page.realCursor = cursor
// page.realClick = cursor.click
return page
}

// process.env.REBROWSER_PATCHES_DEBUG=1
export async function connect({
args = [],
headless = true,
customConfig = {},
proxy = {},
turnstile = false,
connectOption = {},
disableXvfb = false,
plugins = [],
ignoreAllFlags = false,
} = {}) {
let xvfbsession = null;
if (headless == "auto") headless = false;

if (process.platform === "linux" && disableXvfb === false) {
try {
const { default: Xvfb } = await import("xvfb");
xvfbsession = new Xvfb({
silent: true,
xvfb_args: ["-screen", "0", "1920x1080x24", "-ac"],
});
xvfbsession.startSync();
} catch (err) {
console.log(
"You are running on a Linux platform but do not have xvfb installed. The browser can be captured. Please install it with the following command\n\nsudo apt-get install xvfb\n\n" +
err.message
);
}
}

let chromeFlags;
if (ignoreAllFlags === true) {
chromeFlags = [
...args,
...(headless !== false ? [--headless=${headless}] : []),
...(proxy && proxy.host && proxy.port
? [--proxy-server=${proxy.host}:${proxy.port}]
: []),
];
} else {
// Default flags: https://github.com/GoogleChrome/chrome-launcher/blob/main/src/flags.ts
const flags = Launcher.defaultFlags();
// Add AutomationControlled to "disable-features" flag
const indexDisableFeatures = flags.findIndex((flag) => flag.startsWith('--disable-features'));
flags[indexDisableFeatures] = ${flags[indexDisableFeatures]},AutomationControlled;
// Remove "disable-component-update" flag
const indexComponentUpdateFlag = flags.findIndex((flag) => flag.startsWith('--disable-component-update'));
flags.splice(indexComponentUpdateFlag, 1);
chromeFlags = [
...flags,
...args,
...(headless !== false ? [--headless=${headless}] : []),
...(proxy && proxy.host && proxy.port
? [--proxy-server=${proxy.host}:${proxy.port}]
: []),
"--no-sandbox",
"--disable-dev-shm-usage",
];
}
const chrome = await launch({
executablePath: "C:\Program Files\Google\Chrome\Application\chrome.exe",
ignoreDefaultFlags: true,
chromeFlags,
...customConfig,
});
let pextra = null;
if (plugins.length > 0) {
const { addExtra } = await import("puppeteer-extra");

pextra = addExtra(puppeteer);

for (const item of plugins) {
  pextra.use(item);
}

}

const browser = await (pextra ? pextra : puppeteer).connect({
browserURL: http://127.0.0.1:${chrome.port},
...connectOption,
});

let [page] = await browser.pages();

let pageControllerConfig = {
browser,
page,
proxy,
turnstile,
xvfbsession,
pid: chrome.pid,
plugins,
};

page = await pageController({
...pageControllerConfig,
chrome,
killProcess: true,
});

browser.on("targetcreated", async (target) => {
if (target.type() === "page") {
let newPage = await target.page();
pageControllerConfig.page = newPage;
newPage = await pageController(pageControllerConfig);
}
});

return {
browser,
page,
};
}

import test from 'node:test';
import assert from 'node:assert';
const realBrowserOption = {
args: [
'--no-sandbox',
'--no-zygote',
"--start-maximized",
'--lang=en-US',
'--disable-dev-shm-usage',
'--disable-client-side-phishing-detection',
'--fingerprint=' + ((Math.random() * 2 ** 32) >>> 0).toString(),
// '--fingerprint=2333',
// '--fingerprint-platform-version=11',
// '--fingerprint-platform-version=141',//this is from ///chrome 139, from https://github.com/adryfish/fingerprint-chromium
// '--fingerprint-brand=Edge',
'--fingerprint-platform=windows',// macos also works , slightly slower, TRY ON DOCKER, important for docker? Unknown I dont use docker
// '--fingerprint-platform=macos'//important for docker? Unknown I dont use docker

// "--no-startup-window",
// "--disable-crash-reporter",
// "--disable-crashpad-for-testing",
"--disable-gpu-watchdog",
// "--disable-blink-features=AutomationControlled",
// "--disable-audio-output",

],
turnstile: false,
headless: false,
disableXvfb: true,
ignoreAllFlags: false,
// ignoreAllFlags:true,
customConfig: {
chromePath: C:\\Users\\User\\mlx\\deps\\mimic_140.3\\chrome.exe, ///chrome 139, from https://github.com/adryfish/fingerprint-chromium
},

connectOption: {
defaultViewport: null
},
plugins: []
}

test('Cloudflare Turnstile', async () => {
const { page, browser } = await connect(realBrowserOption)

//detected with ///chrome 139, from https://github.com/adryfish/fingerprint-chromium
// //IN CHROME WEB CONSOLE : (async () => { if (navigator.userAgentData) { try { const userAgentData = await navigator.userAgentData.getHighEntropyValues([ "architecture", "bitness", "brands", "fullVersionList", "mobile", "model", "platform", "platformVersion" ]); const formattedCode = await page.setUserAgent('${navigator.userAgent}',{ "architecture": "${userAgentData.architecture}", "bitness": "${userAgentData.bitness}", "brands": ${JSON.stringify(userAgentData.brands, null, 12)}, "fullVersionList": ${JSON.stringify(userAgentData.fullVersionList, null, 12)}, "mobile": ${userAgentData.mobile}, "model": "${userAgentData.model}", "platform": "${userAgentData.platform}", "platformVersion": "${userAgentData.platformVersion}" });; console.log(formattedCode); } catch (error) { console.error("Error retrieving user agent data:", error); console.log("Could not generate the complete code snippet. This might happen if you deny the permission prompt for more detailed information."); } } else { console.log("The navigator.userAgentData API is not available in this browser. The requested detailed format cannot be automatically generated."); console.log("You can use the basic user agent string as follows:"); console.log(await page.setUserAgent('${navigator.userAgent}');); } })();
// await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0', {
// "architecture": "x86", "bitness": "64", "brands": [
// {
// "brand": "Microsoft Edge",
// "version": "141"
// },
// {
// "brand": "Not?A_Brand",
// "version": "8"
// },
// {
// "brand": "Chromium",
// "version": "141"
// }
// ], "fullVersionList": [
// {
// "brand": "Microsoft Edge",
// "version": "141.0.3537.71"
// },
// {
// "brand": "Not?A_Brand",
// "version": "8.0.0.0"
// },
// {
// "brand": "Chromium",
// "version": "141.0.7390.66"
// }
// ], "mobile": false, "model": "", "platform": "Windows", "platformVersion": "10.0.0"
// });

// await page.goto("https://abrahamjuliot.github.io/creepjs/");
// await page.goto("https://bot-detector.rebrowser.net/");
await page.goto("https://turnstile-demo.pages.dev/");
// await page.goto("https://fingerprint.com/products/bot-detection/");

// await page.waitForSelector('#email')
let token = null
let startDate = Date.now()
console.log("Please complete the Turnstile challenge within 30 seconds...")
while (!token && (Date.now() - startDate) < 30000) {
token = await page.evaluate(() => {
try {
let item = document.querySelector('[name="cf-turnstile-response"]').value
return item && item.length > 20 ? item : null
} catch (e) {
return null
}
})
await new Promise(r => setTimeout(r, 1000));
}
await browser.close()
// if (token !== null) console.log('Cloudflare Turnstile Token: ' + token);
assert.strictEqual(token !== null, true, "Cloudflare turnstile test failed!")
})](https://gist.github.com/Mahkhmood8/b49012a9670be84b1e66d90854d55c70)https://gist.github.com/Mahkhmood8/b49012a9670be84b1e66d90854d55c70https://gist.github.com/Mahkhmood8/b49012a9670be84b1e66d90854d55c70

Activity

mandatoryprogrammer

mandatoryprogrammer commented on Oct 27, 2025

@mandatoryprogrammer
Owner

@Mahkhmood8 what's the purpose of this issue? Using puppeteer, especially with Runtime.evaluate will expose you to bot detection and will likely lead you to fail the Cloudflare turnstile much more often.

Closing this as there's not really a stated purpose for this issue, but let me know if I've missed anything.

Mahkhmood8

Mahkhmood8 commented on Oct 27, 2025

@Mahkhmood8
Author

@Mahkhmood8 what's the purpose of this issue? Using puppeteer, especially with Runtime.evaluate will expose you to bot detection and will likely lead you to fail the Cloudflare turnstile much more often.

Closing this as there's not really a stated purpose for this issue, but let me know if I've missed anything.

The captchas are fingerprint based , lol.

and its not being detected

Image

i solved 37k captchas
using
root@booga:~# ./ipv6-proxy-server.sh -s 64 -c 400 -u z -p zero3 -t http -r 5^C

(random port choice between 30000 and 30399 )

cloudflare is so trusting about ipv6 lol

https://github.com/Temporalitas/ipv6-proxy-server/blob/master/ipv6-proxy-server.sh

Image
Mahkhmood8

Mahkhmood8 commented on Oct 27, 2025

@Mahkhmood8
Author
Image

whats stop me? 2$ per /64 subnet proxies?

Image
Mahkhmood8

Mahkhmood8 commented on Oct 27, 2025

@Mahkhmood8
Author
Image Image

btw
https://github.com/selfshore/YSbrowser/blob/main/README.md

YSbrowser works in headless too, but, only windows LOL

mandatoryprogrammer

mandatoryprogrammer commented on Oct 27, 2025

@mandatoryprogrammer
Owner

Ah nice, haven't heard of YSbrowser before. I'll have to double check that thermoptic works well with IPv6 too (I believe it should) 🤔 ).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @mandatoryprogrammer@Mahkhmood8

        Issue actions

          example with puppeteer · Issue #22 · mandatoryprogrammer/thermoptic