Solving CAPTCHAs
CAPTCHAs are a common roadblock in automation. BrowserQL includes built-in support for CAPTCHA challenges. BQL will automatically detect and interacts with CAPTCHAs, even those embedded in iframes or shadow DOMs. You can use the following mutations:
Verify
The Verify mutation clicks a verification button to assert human-like interaction. This mutation can be used to surpass cloudflare's human verification step. Make sure that you have our residential proxying turned on, as it's a requirement for it to work.
The verify mutation does not incur unit costs, whereas the solve mutation does incur unit costs for CAPTCHA solving services.
If you're not sure whether a site has Cloudflare protection, you can use the if mutation with a waitForSelector to conditionally run the verification. Since the if mutation doesn't wait for a selector to be present, adding a waitForSelector before it ensures the Cloudflare turnstile is available before attempting verification.
mutation Verify {
  # Enable residential proxies so cloudflare can be solved successfully
  goto(url: "https://protected.domain") {
    status
  }
  verify(type: cloudflare) {
    found
    solved
    time
  }
}
Conditional Cloudflare Verification
Here's an example of using conditional verification with the if mutation:
mutation Verify {
  # Enable residential proxies so cloudflare can be solved successfully
  goto(url: "https://www.browserless.io/practice-form") {
    status
  }
  waitForSelector(selector:".cf-turnstile",timeout:1000){
    time
  }
  if(selector:".cf-turnstile"){
    verify(type:cloudflare,timeout:30000){
      found
      solved
      time
    }
  }
  html{
    html
  }
}
Note that .cf-turnstile is specific to our sample website. For your own implementation, you should look for a selector that works for your target website. Some alternatives that might work on other sites include a[href*="cloudflare.com"] or other Cloudflare-specific elements.
Conditional Cloudflare Challenge Page Verification
While the previous example handles Cloudflare turnstile challenges, Cloudflare also presents challenge pages that require a different approach. These challenge pages can be identified by looking for links containing "cloudflare.com" and require special handling:
mutation VerifyCloudflareChallenge {
  goto(url: "https://protected.domain") {
    status
  }
  
  waitForSelector(selector:"a[href*=\"cloudflare.com\"]",timeout:1000){
    time
  }
  if1:if(selector:"a[href*=\"cloudflare.com\"]"){
    verify(type:cloudflare,timeout:20000){
      found
      solved
      time
    }
    w1:waitForNavigation(waitUntil:networkIdle,timeout:20000){ 
      status
      time
    }
  }
}
Important notes about Cloudflare challenge pages:
- Navigation wait: After verification, the script waits for navigation to complete to ensure the challenge page has been properly processed.
- Timeout handling: The script waits 1 second to detect if a Cloudflare challenge page appears. If no challenge page is found, you'll see an error message about the selector not being found - this can be safely ignored.
- Alternative approach: If you don't want to wait 1 second, you can wait for a successful selector (the opposite of the challenge detection), but this requires knowing which selector indicates successful page load for your specific target URL.
Solve
The Solve mutation solves CAPTCHAs on a page. By default, it automatically detects the CAPTCHA type without requiring you to specify it. This auto-detection feature is the preferred approach and simplifies your queries.
When solving reCAPTCHAs, it's normal if there isn't a visual confirmation that the CAPTCHA has been solved (i.e., the checkbox may not appear ticked). This is expected behavior. After solving, you should proceed and click on the form's submit button.
mutation SolveCaptcha {
  goto(url: "https://protected.domain") {
    status
  }
  solve {
    found
    solved
    time
  }
}
Specifying type
The type argument is optional and can be used to specify which CAPTCHA type to solve. Specifying the type can reduce verification time by a few milliseconds if you're certain which CAPTCHA type is present on the site. We're constantly supporting more CAPTCHAs - you can find the list of supported types in our browserQL schema.
mutation SolveCaptchaWithType {
  goto(url: "https://protected.domain") {
    status
  }
  solve(type: recaptcha) {
    found
    solved
    time
  }
}
Form Submission After Solving
After solving a CAPTCHA, you should proceed with form submission by clicking the submit button:
mutation SolveAndSubmit {
  goto(url: "https://protected.domain") {
    status
  }
  solve {
    found
    solved
    time
  }
  click(selector: "button[type='submit']") {
    time
  }
}
If there isn't a submit button available, you can trigger form submission manually using the evaluate mutation:
mutation SolveAndTriggerSubmit {
  goto(url: "https://protected.domain") {
    status
  }
  solve {
    found
    solved
    time
  }
  evaluate(content: "window.onSubmit()") {
    time
  }
}
Replace window.onSubmit() with the appropriate JavaScript function that submits the form on your target website.
Next Steps
Ready to take your bot detection bypass to the next level? Explore these key areas: