Skip to content

Cloudflare Turnstile

Cloudflare Turnstile action and cData: When a Task Needs Them

What Turnstile's action and cData parameters do, where to find them in a page, and how to pass them in createTask, in.php or REST so the token is accepted.

3 min readPublished Updated

Many Cloudflare Turnstile widgets need only a sitekey. Some also set an action and cData, two optional values the site attaches to the widget and gets back when it verifies the token. When a widget sets them, a solving task should carry the same values, or the site may refuse the token even though it is valid. This guide shows how to spot them and how to pass them in each of the API’s three formats.

What the two values are for

  • action is a short label for what the visitor is doing, such as login or signup. When the site’s server verifies a token, Cloudflare returns the action it was issued for, so the server can refuse a token earned on the sign-up form and replayed on the login form. Turnstile allows up to 32 characters: letters, digits, _ and -.
  • cData (“customer data”) is a value of up to 255 characters, again letters, digits, _ and -, such as a session or request identifier. It also comes back on verification, so the server can tie the token to the request it expected.

Neither is secret. Both sit in the page next to the sitekey.

Finding them in the page

With implicit rendering, look for the attributes beside data-sitekey:

<div class="cf-turnstile"
data-sitekey="0x4AAAAAAAB1cD2eF3gH4iJ5"
data-action="login"
data-cdata="sess_91f2c0"></div>

With explicit rendering, look for the options of turnstile.render():

turnstile.render("#captcha", {
sitekey: "0x4AAAAAAAB1cD2eF3gH4iJ5",
action: "login",
cData: "sess_91f2c0",
});

If the cData changes on each page load, as a session identifier would, read it from the live page right before you create the task. Find a Cloudflare Turnstile sitekey covers reading these values with Playwright or Selenium.

Passing them in the compatible format

Most createTask clients send the two values nested in the task’s metadata, and that is the form to use when you write the request yourself:

{
"clientKey": "zc_live_…",
"task": {
"type": "TurnstileTaskProxyless",
"websiteURL": "https://shop.example.com/login",
"websiteKey": "0x4AAAAAAAB1cD2eF3gH4iJ5",
"metadata": { "action": "login", "cdata": "sess_91f2c0" }
}
}

Clients written for other services work too: createTask reads the action from the first of action, pageAction (as CapMonster Cloud’s clients name it) and metadata.action (as CapSolver’s clients send it) that is present, and cData from the first of cdata, cData, data, turnstileCData and metadata.cdata (or metadata.cData) that is present.

cData with a capital D is the spelling Anti-Captcha documents on its TurnstileTask page (checked 1 October 2026; ZeroCaptcha is not affiliated with Anti-Captcha or CapSolver), so a client written for Anti-Captcha sends it unchanged. JSON keys are case-sensitive, and a cData under any name not listed above is ignored, so the site may then refuse the token. Migrate from Anti-Captcha shows the whole move.

Passing them in the 2Captcha format

in.php takes action and data, as 2Captcha documents them:

Terminal window
curl -H "Idempotency-Key: $(uuidgen)" \
"$ZEROCAPTCHA_API/in.php?key=$ZEROCAPTCHA_KEY&method=turnstile&sitekey=0x4AAAAAAAB1cD2eF3gH4iJ5&pageurl=https%3A%2F%2Fshop.example.com%2Flogin&action=login&data=sess_91f2c0&json=1"

See the 2Captcha format for every parameter.

Passing them in REST

POST /v1/tasks takes action and cdata at the top level of the body, with the key as a bearer token:

Terminal window
curl -sS --fail-with-body "$ZEROCAPTCHA_API/v1/tasks" \
-H "Authorization: Bearer $ZEROCAPTCHA_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"type": "TurnstileTaskProxyless", "websiteURL": "https://shop.example.com/login",
"websiteKey": "0x4AAAAAAAB1cD2eF3gH4iJ5", "action": "login", "cdata": "sess_91f2c0"}'

In each format, an Idempotency-Key header makes a retried create return the same task instead of a second one. Cloudflare Turnstile action and cData in the docs has the full request in each format, with polling and errors.

The Tasks API reference lists every field and its limits.

The Cloudflare Turnstile action and cData demo sets both, and its check shows the values siteverify returns for the token you bring.

When values are refused

An action or cData outside Turnstile’s limits is refused when you create the task, before any money is held: ERROR_INVALID_TASK_DATA in the compatible format, with a description that names the field. Nothing is charged for a refused task.

A token issued for the wrong action is a different problem: the task succeeds and is charged, and then the site’s server rejects the token. If a site keeps rejecting tokens that arrive in time, compare the action and cData you send with the ones in the live page.

Checklist

  • Copy data-action and data-cdata, or action and cData from turnstile.render().
  • Send cData as cdata or cData in createTask, cdata in REST, or data in in.php.
  • Read per-session cData from the live page right before each task.
  • Keep the sitekey and URL from the same widget. The Cloudflare Turnstile solver page has samples in every language.

Questions

What happens if I leave out the action a widget sets?

The token can still be issued, but a site that checks the action on its server may reject it. Send the widget's action whenever it sets one.

Which spelling of cData does ZeroCaptcha accept?

The compatible format reads cdata, Anti-Captcha's cData, data, turnstileCData and metadata.cdata, so a client's own spelling works unchanged.

How long can action and cData be?

Cloudflare Turnstile allows an action of up to 32 letters, digits, underscores or dashes, and cData of up to 255 of the same characters.

Read next

This guide is part of the Cloudflare Turnstile solver hub. Every task is charged only when a token is ready.

Get an API key