hCaptcha Enterprise rqdata: what it is and how to solve it.

Enterprise hCaptcha binds every challenge to a fresh rqdata blob and the session it was issued in. A token is only valid if it was minted against that exact rqdata, which is why solving the image grid alone is not enough. This guide shows where rqdata lives on a page, how to capture it fresh, the mistakes that get enterprise tokens refused, and how to get a token enterprise sitekeys accept.

What rqdata actually is

On a regular hCaptcha sitekey, the widget renders, the visitor (or an invisible check) passes, and hCaptcha injects a P1_ token into the h-captcha-response field. The token mostly answers one question: was a challenge passed for this sitekey?

Enterprise sitekeys add a second input. The page passes a signed, per-challenge blob called rqdata into hcaptcha.render() or hcaptcha.execute(). That blob encodes session and request context, and it changes on every challenge. The token hCaptcha returns is bound to the rqdata it was issued against, so verification now answers a stricter question: was this challenge passed for this exact rqdata, in this session? Feed a solver stale or mismatched rqdata and the resulting token is invalid even though the grid was answered correctly.

You will not find rqdata in hCaptcha’s public developer docs. Its official SDKs accept the field, call it “custom supplied challenge data”, and refer you to the Enterprise docs instead. Two details from those SDKs are worth knowing. The site supplies the value, so it lives in the site’s own code or responses. And the Android and iOS SDKs moved rqdata out of the widget config and into the parameters of each verification, which matches how it behaves: one value per challenge, not one per page.

Where rqdata appears on the page

There are two places a page hands rqdata to hCaptcha. The first is the render() call that draws the widget:

rqdata passed into hcaptcha.render()
<!-- The enterprise sitekey passes a fresh rqdata blob into render(). -->
<script>
  hcaptcha.render('captcha-box', {
    sitekey: 'f5ab1c2d-7e8f-4a9b-b1c2-d3e4f5a6b7c8',
    rqdata: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJI...A_per_session_blob',
  });
</script>

<!-- after a solve, hCaptcha injects the token as usual: -->
<textarea name="h-captcha-response">P1_eyJ0eXAi...UV8w</textarea>

The second is execute(), which invisible integrations call to start the check. hCaptcha’s React wrapper documents passing an object into execute() and says it goes straight through to the underlying JS API, which is how Enterprise fields like rqdata get in. With { async: true } the call returns a Promise that resolves with the token:

rqdata passed into hcaptcha.execute()
hcaptcha
  .execute(widgetId, { async: true, rqdata: rqdataFromSite })
  .then(({ response }) => submitForm(response));

The same wrapper also exposes a setData() method that it documents only by pointing to the Enterprise docs, so on some pages the value reaches the widget through that call instead. Whichever call the page uses, the value is the same thing: the site’s current rqdata for this challenge.

How to tell a sitekey is enterprise from outside

What you can observe from outside is the integration around the sitekey:

  • The page passes rqdata. The clearest sign. If you see it in a render(), execute() or setData() call, treat the key as enterprise and send the value.
  • hCaptcha loads from the site’s own domain. Enterprise first-party hosting lets visitors connect to something like hcaptcha.your.com instead of hCaptcha’s hosts. A working widget with no hcaptcha.com script on the page is a hint.
  • Most visitors never see a challenge. Full Passive mode is an Enterprise feature, though Pro accounts get a “99.9% Passive” mode too. Invisible mode on a regular key also hides the widget, so this one alone proves little.

The decisive differences are server-side and only the site owner sees them: siteverify returns a score and score_reason on Enterprise, and passing remoteip is what enables the risk score. If you are unsure, sending the enterprise type is safe: an enterprise sitekey that issues no rqdata works with type: "hcaptcha_enterprise" and no rqdata field. Finding the sitekey itself is covered in how to find an hCaptcha sitekey.

Regular vs enterprise at a glance

What changes when an hCaptcha sitekey is enterprise
Regular hCaptchaEnterprise hCaptcha
Token fieldh-captcha-responseh-captcha-response
Token prefixP1_…P1_…
Per-challenge rqdataNoneRequired when the page supplies it, fresh each render
Session / IP bindingLooseTight: solve IP must match submit IP
Token validity~120s, single-use~120s, single-use
Extra siteverify fieldsNonescore and score_reason (a risk score; remoteip enables it)
Where hCaptcha loads fromjs.hcaptcha.comjs.hcaptcha.com, or the site’s own subdomain with first-party hosting
Test sitekeys10000000-ffff-ffff-ffff-00000000000120000000-ffff-ffff-ffff-000000000002 (safe user), 30000000-ffff-ffff-ffff-000000000003 (bot detected)
What a token must proveA challenge was passedA challenge was passed for this exact rqdata + session
What you send a solvertype + sitekey + urltype + sitekey + url + rqdata

Capturing rqdata in a browser

Start in DevTools on the page that shows the captcha. In the Sources panel, search all files for rqdata to find the call that passes it, and set a breakpoint there to read the live value. In the Network panel, search response bodies for the same string to find which of the site’s requests delivers it. That request is the one your automation has to repeat for every solve.

In Playwright or Puppeteer you can log the same thing while the page loads, skipping hCaptcha’s own hosts so only the site’s responses show up:

Playwright: find rqdata
page.on("response", async (res) => {
  if (res.url().includes("hcaptcha.com")) return;
  const body = await res.text().catch(() => "");
  if (body.includes("rqdata")) console.log(res.status(), res.url());
});

await page.goto("https://target.example/login");

The site’s own field name may differ from rqdata. If the search comes up empty, break on the render() or execute() call and trace where its argument came from.

Capturing rqdata in an HTTP pipeline

Once you know which request returns the value, an HTTP client can fetch it without a browser. The order matters more than the code:

  1. Fetch the page or endpoint that returns rqdata, with the same cookies and the same exit you will submit from.
  2. Extract the value immediately before you create the solve. Never cache it or share it between sessions.
  3. Send it with type: "hcaptcha_enterprise", the sitekey, the page url, and the same proxy.
  4. Submit the token as soon as the solve returns. If anything fails, go back to step 1 for a fresh value.
Python: fresh rqdata
import re, requests

PROXY = "http://user:[email protected]:8080"
site = requests.Session()
site.proxies = {"http": PROXY, "https": PROXY}

html = site.get("https://target.example/login").text
rqdata = re.search(r'"rqdata"\s*:\s*"([^"]+)"', html).group(1)
Python: solve and submit
API = "https://api.nonecap.com/v1/solves"
AUTH = {"Authorization": f"Bearer {NONECAP_KEY}"}
solve = requests.post(f"{API}?wait=90", headers=AUTH, json={
    "type": "hcaptcha_enterprise",
    "sitekey": "f5ab1c2d-7e8f-4a9b-b1c2-d3e4f5a6b7c8",
    "url": "https://target.example/login",
    "rqdata": rqdata,
    "proxy": PROXY,
    "user_agent": site.headers["User-Agent"],
}).json()
while solve["status"] in ("pending", "solving"):
    solve = requests.get(f"{API}/{solve['id']}?wait=90", headers=AUTH).json()

if solve["status"] == "solved":
    site.post("https://target.example/login",
              data={"email": EMAIL, "h-captcha-response": solve["token"]})

The regular expression is a placeholder. Where the value lives (inline script, JSON response, a header) differs per site; match whatever you found in DevTools.

Why rqdata goes stale

Three things expire an rqdata value. It is single-use: once a challenge has run against it, a second solve on the same value yields a token the site refuses. It is per challenge: each new page load or render brings a new one and leaves the old one behind. And it is session-bound: a value fetched in one cookie session or from one address does not carry over to another. The token it produces then has its own clock of roughly 120 seconds, so capture, solve and submit have to run back to back.

Why enterprise is harder than regular hCaptcha

The difficulty is not the image grid. It is the binding around it. An enterprise token has to satisfy three things at once:

  • The challenge was passed. Same as regular hCaptcha: the grid (or invisible check) has to clear.
  • It was passed against the live rqdata. The blob is single-use and per-challenge. A token minted a moment too late, or against a different render, does not verify.
  • The session lines up. Enterprise deployments commonly check that the IP and session that solved the challenge match the ones submitting the token. Solver vendors reflect this: NopeCHA, for example, tells users to pass a proxy that matches the submit IP because, in its words, "most sites will check that the IP used to solve the challenge matches the IP used to submit the token." In our own testing a token submitted from a different address than the one that solved it is refused as invalid-response, which is why a proxy that stays on one exit is not a nice-to-have on enterprise sitekeys.

Token validity is still short. An hCaptcha token is good for roughly 120 seconds and is single-use, so the whole capture, solve, and submit loop has to happen inside that window. With regular hCaptcha you have some slack. With enterprise you have less, because the rqdata behind it is also expiring.

Common mistakes and what they look like

Enterprise hCaptcha failures, their symptoms, and the fix
MistakeWhat you seeFix
Sending type: "hcaptcha" with no rqdata when the page supplies oneA token comes back and the site refuses itSend type: "hcaptcha_enterprise" with the page’s live rqdata
Reusing rqdata from an earlier page load, a retry, or another workerThe token is refused even though the challenge was answeredCapture one fresh value per solve, in the session that will submit
Holding the token before submittingexpired-input-response at siteverify (120s default); the widget fires its expired callbackSubmit as soon as the solve returns
Submitting the same token twice, e.g. on a client retryalready-seen-response at siteverifyStart over: fresh rqdata, new solve, new token
Submitting from a different network address than the solve usedMany deployments refuse the token as invalid-responsePass a proxy that stays on one exit for page load, solve, and submit
Using the sitekey of a different widget on the pageRefused when the site passes sitekey to siteverify, which stops a token issued on one sitekey from being redeemed on anotherRead the sitekey from the widget that guards the form you submit
Dropping the user agent on a site that checks itOn some sites the token is refused without itSend user_agent from the browser that loaded the page, as is

The siteverify codes above are what the site’s backend receives; from your side most of them surface as a rejected form. The full list is in hCaptcha error codes.

Why image-recognition APIs struggle here

A pure token or image-recognition service treats a captcha as a vision problem: receive the challenge images, classify them, return the answer. That works for the regular variant, where the question really is "which tiles match." Enterprise rqdata moves the goalposts. The token has to be bound to the exact session the rqdata was issued for, not just derived from the images. Recognising the grid in isolation does not give you that. You can answer every tile correctly and still get an invalid token, because the token never matched the blob.

This is the same reason in-browser stealth tricks fall down on enterprise sitekeys. A patched automation browser can sometimes pass a regular challenge, but it cannot easily produce the session signals an enterprise rqdata flow expects. See solving hCaptcha in Playwright for why the reliable pattern is to mint the token out of band rather than fight the challenge inside the browser you are automating.

How NoneCap mints enterprise tokens

NoneCap does not classify images in a vacuum. It returns a finished token bound to the exact rqdata you pass in, the kind enterprise sitekeys accept and image-recognition output does not. You send the enterprise type with the per-challenge rqdata alongside the sitekey and url. Block for the result with ?wait=N (up to 90 seconds), or submit without it and poll the solve id:

Create an enterprise solve
curl "https://api.nonecap.com/v1/solves?wait=90" \
  -H "Authorization: Bearer $NONECAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type":    "hcaptcha_enterprise",
    "sitekey": "f5ab1c2d-7e8f-4a9b-b1c2-d3e4f5a6b7c8",
    "url":     "https://target.example/login",
    "rqdata":  "eyJ0eXAiOiJKV1QiLCJhbGciOiJI...A_per_session_blob"
  }'
Response
{
  "id":              "solve_01HQF7K3JKWZX",
  "object":          "solve",
  "type":            "hcaptcha_enterprise",
  "status":          "solved",
  "sitekey":         "f5ab1c2d-7e8f-4a9b-b1c2-d3e4f5a6b7c8",
  "url":             "https://target.example/login",
  "token":           "P1_eyJ0eXAi...UV8w",
  "credits_charged": 2
}

The response is the standard solve object with type: "hcaptcha_enterprise" and a real P1_ token in the token field. Submit it as the page's h-captcha-response exactly as you would a regular token. Capture the rqdata fresh for each challenge, since it is single-use and tied to that session. An enterprise sitekey that issues no rqdata works too: send the enterprise type without it. Two optional fields matter on enterprise sitekeys: proxy, so the solve and your submit share one exit, and user_agent, the user agent of the browser that loaded the page, which some sites require for the token to be accepted. The full object and every language sample are in the API reference.

This is where NoneCap is strongest

Enterprise rqdata is the differentiator. It is the case that breaks image-only solvers and the reason a purpose-built hCaptcha solver matters. If you are evaluating alternatives, this is the axis to test them on:

  • Moving off NopeCHA, which discontinued hCaptcha on October 2, 2026? The switch guide shows where its data.rqdata field goes on NoneCap.
  • Against a broad human-and-AI marketplace, see NoneCap vs 2Captcha, where hCaptcha is the headline product rather than one type among many.

When a token-only API is enough

Be honest about the sitekey in front of you. If it is a regular hCaptcha sitekey with no rqdata, you do not need any of this. A plain image-recognition API, or NoneCap's standard type: "hcaptcha", will return a valid token, and cheaper broad solvers may be perfectly fine. The enterprise machinery only earns its keep when the page passes rqdata and binds the session. And if your target is reCAPTCHA, Cloudflare Turnstile, or FunCaptcha, NoneCap does not solve those yet (they are on the roadmap), enterprise or otherwise.

Last updated October 2026.

Frequently asked

What exactly is rqdata?
It is a signed, per-challenge blob that an enterprise sitekey passes into hcaptcha.render() or hcaptcha.execute(). hCaptcha’s SDKs describe it as “custom supplied challenge data”. It encodes session and request context, so the token hCaptcha hands back is bound to that rqdata and the session it was issued in. Submit a token issued against stale or mismatched rqdata and verification fails, even if the challenge itself was solved.
Is rqdata documented by hCaptcha?
Not in the public developer docs. hCaptcha’s official SDKs accept it (the React wrapper forwards it through execute(); the Android and iOS SDKs take it per verification) and point to the Enterprise docs for the details. From outside an enterprise contract, the page that uses it is your reference.
Why is enterprise hCaptcha harder to solve than the regular kind?
Regular hCaptcha mostly asks "was a challenge passed?" Enterprise adds "was it passed for this exact rqdata, in this session, from an IP that matches the one submitting the token?" That binding is what breaks pure image-recognition solvers: recognising the grid is not enough if the surrounding session does not match. Most enterprise solvers therefore also need a proxy whose IP matches the submit IP.
How do I capture the rqdata to send?
Read it from the call the page makes. Enterprise sitekeys pass rqdata into hcaptcha.render() / hcaptcha.execute(), so grab the value from that call (or from the network request that fetches it) and forward it to NoneCap with type: "hcaptcha_enterprise". Capture it fresh per challenge, since it is single-use and tied to that session.
Does every enterprise sitekey use rqdata?
No. Many enterprise sitekeys issue none. If the page passes no rqdata, send type: "hcaptcha_enterprise" without it. If it does pass one, send it, fresh for each challenge.
Can I test an enterprise integration without a live sitekey?
Yes, for the plumbing. hCaptcha publishes Enterprise test sitekeys: 20000000-ffff-ffff-ffff-000000000002 simulates a safe end user and 30000000-ffff-ffff-ffff-000000000003 a detected bot, both with the all-zero test secret. They provide no anti-bot protection, so use them only in test environments. See hCaptcha test sitekeys.
How many credits does an enterprise solve cost?
The same rule as regular hCaptcha: from one credit per challenge round, and hCaptcha decides how many rounds a solve takes (often one, sometimes two or three, around 1.7 on average). You are charged on success only, so failed, cancelled, or expired solves are never charged. Pricing is $0.20 to $0.50 per 1,000 credits depending on pack. See pricing.

Start solving hCaptcha in minutes.

1,300 free credits on signup. Pay per solve, credits never expire, failed solves never charged.