DEV Community

Tom Hargreaves
Tom Hargreaves

Posted on

hcaptcha bypass in a real pipeline: what actually decides whether it works

People search for hcaptcha bypass expecting a single technique. What they actually need depends on something they usually have not checked yet: where the challenge lives and what shape the answer takes.

I have automated hCaptcha on and off for a couple of years, in scrapers and in browser flows. Every time it went badly, the model was not the problem. The setup was. Here is the version of the advice I wish I had read first.

First: there are three hCaptcha shapes, not one

hCaptcha does not present one kind of task. Depending on what the site owner configured, you may get:

  1. A checkbox. No image at all in the normal case. You click, and it either passes or escalates. There is nothing to read and nothing to solve locally — the decision was made by a score, server-side.
  2. A tile grid. The familiar 3x3 (sometimes 4x4) "please click each image containing a boat". This is the only shape where image recognition is the point.
  3. A drag task. A generated object that has to be dragged somewhere. The answer here is a coordinate pair, not a text answer.

Each of those needs a different response, and the most expensive mistake in this space is treating a checkbox like a puzzle. If a site is showing you a checkbox, there is no picture to send anywhere. There is only a session that either looks plausible or does not.

The rule that confuses everyone: billing and "not ready"

Because hCaptcha work is asynchronous — you submit, then you poll — you have to understand the error vocabulary before you write the loop. On the service I use, three facts do the heavy lifting:

  • "Not finished yet" has its own code. It is a normal step in the happy path. If your client treats every error as a failure, your first naive version will resubmit a job that is already running and already paid for. One image becomes several jobs.
  • You are billed when the upstream accepts the job, not when it succeeds. A rejected submit — bad parameters, no credit, no upstream capacity — costs nothing. Once accepted, the credits are spent regardless of the outcome, including a timeout.
  • There are no refunds, including on timeouts. So your true cost is per attempt, not per successful solve.

The practical consequence is that "retry on error" is a dangerous default here. I had to split error handling into three branches — wait, slow down, and genuine failure — before my numbers stopped drifting.

Choosing between recognition and a token

If you need an hCaptcha answer, there are two entry points and they solve different problems:

  • Image recognition — you already have the picture; it tells you which tiles to click or where to drag. You do the clicking.
  • Token generation — you do not have the picture, or do not care; the whole challenge is solved server-side and you get back something submittable.

They are priced differently, and not by a rounding error: on the service I use an hCaptcha token costs 10 credits where a recognition call costs 1. If your browser flow still has to tick the checkbox itself, you want recognition — it returns an acknowledgement rather than a token, and costs correspondingly less.

The details that only show up in production

These each cost me more than an hour:

Drag answers come back as percentages. Top-left is 0,0, bottom-right is 100,100. Multiply by the real image width and height. I spent a while feeding percentages into a mouse move as if they were pixels and wondering why every drag landed in the corner.

Token challenges are slow. A measured hCaptcha token takes about a minute, and longer at peak. That is why token jobs get a longer expiry than recognition jobs — five minutes against three. Poll every 2-3 seconds, not faster: every accepted job is billed, so hammering the endpoint just pays twice.

Concurrency, not model quality, is your throughput ceiling. If the limit is 4 parallel jobs and a job takes about a minute, your realistic ceiling is about 4 per minute no matter how good the model is. Compute that number before you design the queue.

A checkbox result is not a solved captcha. If you get back an acknowledgement, you still have to place it where the page expects and let the site's own callback fire. Injecting a value into the wrong field looks identical to a failure.

When it fails, check these before blaming the solver

  1. Is the task even enabled on your plan? Some types sit behind higher tiers, and you only find out after paying.
  2. Did you send the challenge text and the page context? For tile selection, sending the question text improves accuracy noticeably, and for hCaptcha specifically the data object scraped from the page should be passed through unchanged — it carries the link between the question and the images.
  3. Is your user agent consistent with the page you are solving for? For token types this is the single biggest lever, and it is free.
  4. Are you measuring per attempt or per success? If failed-but-accepted jobs are billed, your real unit cost is the former, and retry loops hide the difference.

The short version

hCaptcha is three problems wearing one name. Figure out which shape you actually have, read the billing rule before writing any retry logic, and remember that the number that decides your throughput is the concurrency ceiling, not how clever the model is.

I maintain the service this is measured against — the full error table, the endpoint list, the twelve supported types and the exact billing rule are on the front page at hcaptcha bypass. The figures above are the ones I operate, not ones from a marketing page.

Top comments (0)