Skip to content

Akamai sec-cpt

Take the adaptive challenge through its verification step. Capture the sec_cpt cookie and challenge JSON issued together. Choose whether your client verifies the returned token or Capzy submits through your session proxy.

POST /createTask · example
{
  "clientKey": "capzy_YOUR_API_KEY",
  "task": {
    "type": "AkamaiSecCptToken",
    "secCpt": "3d9a8f...prefix~7c1e2b...~",
    "secJson": {
      "token": "eyJ0eXAiOiJKV1Qi...",
      "timestamp": 1735689600,
      "nonce": "7f3a1c9e0b8d",
      "difficulty": 15000,
      "count": 2,
      "verify_url": "https://www.example.com/_sec/cp_challenge/verify"
    }
  }
}

Illustrative values. Replace the inputs with values from your current integration.

secCpt challenge + secJsonProxyless or your own proxyToken + verification details

Capture the adaptive challenge payload.

Capture the sec_cpt cookie and challenge JSON issued together. Choose whether your client verifies the returned token or Capzy submits through your session proxy.

Your API key authenticates Capzy.
Provider keys, challenge IDs, images, and session values belong inside task.

Read the adaptive challenge from the blocked response.

  1. Copy the complete sec_cpt cookie from Set-Cookie or the current jar into secCpt, keeping all segments.
  2. For a JSON 428 response, use its challenge object as secJson. For an HTML iframe, base64-decode its challenge attribute and parse the JSON.
  3. Preserve token, timestamp, nonce, difficulty, and supplied count/verify_url from that same challenge.
Input collection example - replace illustrative values
const iframe = document.querySelector("iframe[challenge]");
const encoded = iframe?.getAttribute("challenge");
if (encoded) console.log(JSON.parse(atob(encoded)));
// For a JSON 428 response, copy its challenge object instead.

This console helper reads an existing iframe only. If the challenge is not in the document, copy the captured response from Network.

How Akamai sec-cpt works

Akamai's Adaptive Challenge (sec-cpt) is a proof-of-work gate Akamai serves on a protected endpoint AFTER Bot Manager (_abck) has already passed. When it fires, your request gets either an HTTP 428 with a JSON body, or a 200 HTML page titled "Challenge Validation" — and a `sec_cpt` cookie. Embedded in that response is a challenge (a token, a nonce, and a difficulty). Your session has to mine a chained-SHA-256 answer, POST it to a verify URL, and then re-issue the original request. It's a separate layer from the _abck cookie (see /solvers/akamai-web).

Reaching the challenge is YOUR job — it's bound to your session, IP and TLS (a flagged IP gets a 403 hard block, never the 428, so a token service literally can't fetch it for you). You capture two things from that response — the `sec_cpt` cookie and the challenge config — and send them as `secCpt` + `secJson`. TOKEN mode (no proxy): we mine the proof-of-work locally (chained SHA-256, typically under 100 ms) and return the token to POST, the verify URL, and the exact Content-Type — you POST it. SUBMIT mode (proxy supplied): we go one step further and POST the verify ourselves over httpcloak (real Chrome-150 TLS) on YOUR proxy IP, returning whether Akamai accepted it plus the cleared cookies. We must use your proxy because sec-cpt clearance is bound to the IP that received the challenge.

  • Pure CPU proof-of-work — typically under 100 ms, no browser, no proxy
  • You keep your own session, IP, and sec_cpt cookie — we only mine the answer
  • Returns verify_url + exact Content-Type so replay just works
  • Handles the difficulty ramp (each answer raises difficulty by 1) and multi-answer challenges
  • Optional SUBMIT mode: hand us your proxy + cookies and we POST the verify for you over httpcloak (Chrome-150) on your IP — returns the cleared cookies

Know what goes in.

Choose a field to see its purpose, where to get it, and its place in the request. Optional values omitted from the example can be added when your flow uses them.

The request below follows your selected task configuration.

Request authentication

Required task inputs

secCpt

stringRequired

The `sec_cpt` cookie value Akamai set on the response that served the challenge. Looks like `SECPART~…~` or `AAA;BBB;CCC`. Send the WHOLE value — we hash the segment before the first ~ (or ;).

Where it comes from

Copy the entire sec_cpt cookie from the response that issued the adaptive challenge, including every segment.

Open the input guide
Example value3d9a8f...prefix~7c1e2b...~
POST /createTask · selected configuration
{
  "clientKey": "capzy_YOUR_API_KEY",
  "task": {
    "type": "AkamaiSecCptToken",
    "secCpt": "3d9a8f...prefix~7c1e2b...~",
    "secJson": {
      "token": "eyJ0eXAiOiJKV1Qi...",
      "timestamp": 1735689600,
      "nonce": "7f3a1c9e0b8d",
      "difficulty": 15000,
      "count": 2,
      "verify_url": "https://www.example.com/_sec/cp_challenge/verify"
    }
  }
}

The selected field is highlighted when present. Preserve the declared value type and current challenge context.

Make your first request.

Create the task, keep its taskId, and poll until status is ready. Then read the selected variant's solution.

More examples
  1. Create the task

    Send clientKey and the selected task to /createTask from your server. Keep the returned taskId.

  2. Wait for the solution

    Send that same key and ID to /getTaskResult. While processing, wait two seconds before checking again. Stop on Ready or an error.

  3. Apply the result

    For TOKEN, wait duration and POST the raw token to verify_url using content_type in the original session. For SUBMIT, require verified success and install returned cookies; avoid a duplicate verification POST.

solve_akamai_sec_cpt.py
import json, os, time
import requests

API = "https://api.capzy.ai"
KEY = os.environ["CAPZY_API_KEY"]
task = json.loads("{\"type\":\"AkamaiSecCptToken\",\"secCpt\":\"3d9a8f...prefix~7c1e2b...~\",\"secJson\":{\"token\":\"eyJ0eXAiOiJKV1Qi...\",\"timestamp\":1735689600,\"nonce\":\"7f3a1c9e0b8d\",\"difficulty\":15000,\"count\":2,\"verify_url\":\"https://www.example.com/_sec/cp_challenge/verify\"}}")

def call(path, payload):
    response = requests.post(f"{API}/{path}", json={"clientKey": KEY, **payload}, timeout=30)
    response.raise_for_status()
    data = response.json()
    if data.get("errorId", 0) or data.get("status") == "failed":
        raise RuntimeError(data.get("errorDescription") or data.get("errorCode") or "Task failed")
    return data

created = call("createTask", {"task": task})
for attempt in range(60):
    result = call("getTaskResult", {"taskId": created["taskId"]})
    if result.get("status") == "ready":
        solution = result["solution"]
        print(solution)
        break
    time.sleep(2)
else:
    raise TimeoutError("Task is still processing; keep the taskId to check it later.")

Before runningReplace all illustrative inputs with your captured values. Set CAPZY_API_KEY in your environment. Install requests with pip install requests.

Polling and failuresThe example checks HTTP/API failures, uses 30-second request timeouts, and stops after 60 result checks. Retain taskId if your task is still processing.

Understand what comes back.

Follow this task from creation to completion. Response fields and usage follow your selected request variant.

Token + verification details

For TOKEN, wait duration and POST the raw token to verify_url using content_type in the original session. For SUBMIT, require verified success and install returned cookies; avoid a duplicate verification POST.

string
The ready-to-POST payload — a JSON string {token, answers}. Send it verbatim as the raw request body to verify_url with the returned content_type (don't re-encode it)
array
The mined proof-of-work answers (also embedded inside token)
string
Where to POST the token — the sec-cpt verify endpoint from the challenge config (empty if your challenge didn't include one; use the verify URL from the page)
string
The Content-Type to POST the token with: text/plain;charset=UTF-8 (NOT application/json)
number
Mandatory delay in seconds before manual TOKEN-mode verification
string
Challenge provider. adaptive/behavioral providers also need browser sensor context
object
The same fields mirrored, for drop-in compatibility
POST /getTaskResult · example response
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "token": "{\"token\":\"eyJ0eXAiOiJKV1Qi...\",\"answers\":[\"0.a1b2c3d4e5f60718\",\"0.9f8e7d6c5b4a3928\"]}",
    "answers": [
      "0.a1b2c3d4e5f60718",
      "0.9f8e7d6c5b4a3928"
    ],
    "verify_url": "https://www.example.com/_sec/cp_challenge/verify",
    "content_type": "text/plain;charset=UTF-8",
    "duration": 30,
    "provider": "crypto"
  }
}

Illustrative values. Additional metadata may be returned; only Ready contains a completed solution.

Continue TOKEN or SUBMIT mode

TOKEN mode mines the proof; your original client waits duration and submits token verbatim with content_type and its sec_cpt cookie. SUBMIT mode sends verification through your proxy and returns submitted/verified plus cleared cookies. Check verified even when status is ready; a successful HTTP status alone does not prove clearance. Preserve the session's proxy, UA, TLS identity, and all cookies. Some providers also need browser sensors and the original form resubmission.

Execution context result is the parsed Ready response from the polling example. session, when referenced, is your existing requests.Session (or browser-compatible session) with the original cookie jar, headers, and solving proxy configured in session.proxies for both http and https. Keep this client for the complete flow. task is the task object you submitted. For Shape, action_body is the original protected request body as bytes or a string, with its original Content-Type in session.headers. Install curl_cffi when the fragment imports it; match the target's required browser/TLS identity.

Use the result · Python
import time
sol = result["solution"]
if sol.get("submitted"):
    # A Ready API task can still report unsuccessful site verification.
    if not sol.get("verified"):
        raise RuntimeError(sol.get("reason") or f"Verification failed: {sol.get('verifyStatus')}")
    for name, value in sol["cookies"].items():
        session.cookies.set(name, value, domain="target.example.com", path="/")
    # Already submitted: do not POST this token again.
else:
    if sol.get("provider") in ("adaptive", "behavioral"):
        raise RuntimeError("This provider also needs browser sensor context; use the browser/SUBMIT flow")
    verify_url = sol.get("verify_url") or "https://target.example.com/_sec/cp_challenge/verify"
    time.sleep(sol["duration"])
    # Original session still holds sec_cpt, _abck, and the same proxy/TLS identity.
    verification = session.post(verify_url, data=sol["token"],
        headers={"Content-Type": sol["content_type"]}, timeout=30)
    verification.raise_for_status()
    # A 200 alone is not clearance: the sec_cpt cookie must carry the ~3~ marker.
    if "~3~" not in (session.cookies.get("sec_cpt", domain="target.example.com") or ""):
        raise RuntimeError("Challenge remains uncleared; inspect the page's resubmit/browser flow")
response = session.get("https://target.example.com/protected", timeout=30)
print(response.status_code)

When something doesn't work.

Check your captured values, the selected variant, and the response before starting another task.

What exactly do I grab from the page?

When the challenge fires, your request gets a response with a `sec_cpt` cookie plus an embedded challenge. Grab two things: (1) the sec_cpt cookie value → secCpt. (2) the challenge config → secJson. If the response is an HTML 'Challenge Validation' page, the config is base64-encoded in the iframe's challenge="…" attribute (decode it). If it's a 428 JSON body, that body already IS the config.

How do I decode the challenge="…" attribute?

It's a base64 string. Decode it to bytes, then parse the bytes as JSON — you'll get {token, timestamp, nonce, difficulty, count, verify_url}, and that whole object is your secJson. (In Python: json.loads(base64.b64decode(challenge_attr)).)

How do I submit the token you return?

POST the returned `token` as the raw request body with Content-Type text/plain;charset=UTF-8 to `verify_url`, carrying your sec_cpt cookie, on the SAME session/IP. Once it's accepted, re-issue your original request on that session.

Why can't you fetch the 428 for me?

The sec-cpt interstitial is served against your session, IP, TLS fingerprint and prior _abck state. On a flagged IP Akamai returns a 403 hard block, never the 428 — so no external service can reach the challenge on your behalf. The proof-of-work itself is pure math, which is exactly the part we do.

The verify keeps failing even with a correct token — why?

The usual cause is Content-Type: use text/plain;charset=UTF-8, not application/json. Also make sure the sec_cpt cookie and IP on the verify POST match the ones that received the challenge.

Can you submit the verify for me instead of returning the token?

Yes — that's SUBMIT mode. Pass your proxy (proxyAddress/proxyPort/proxyLogin/proxyPassword) plus your session cookies and userAgent, e.g.: ```json { "type": "AkamaiSecCptToken", "secCpt": "3d9a8f...prefix~7c1e2b...~", "secJson": { "token": "eyJ0eXAiOiJKV1Qi...", "timestamp": 1735689600, "nonce": "7f3a1c9e0b8d", "difficulty": 15000, "count": 2, "verify_url": "https://www.example.com/_sec/cp_challenge/verify" }, "proxyAddress": "gw.yourproxy.com", "proxyPort": 8080, "proxyLogin": "user", "proxyPassword": "pass", "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36", "cookies": { "_abck": "0EA5C7A1B2C3...~0~YAAQ...~-1~...", "bm_sz": "CEEB8EC04F6F422F...~YAAQ...", "ak_bmsc": "015EEB2602240B9B...~000000...", "bm_sv": "655E36E7471D26A7...~YAAQ..." } } ``` We mine AND POST the verify over httpcloak (Chrome-150) on YOUR proxy IP, then return `{ submitted, verified, verifyStatus, cookies }` — replay the returned cookies on your re-issued request. The proxy is REQUIRED: sec-cpt clearance is bound to the IP that received the challenge, so a verify from any other IP won't stick. Pass your full Akamai cookie set (_abck, bm_sz, ak_bmsc, bm_sv) so the session is coherent; sec_cpt is added for you from secCpt.

Which cookies do I send in SUBMIT mode?

Send the Akamai cookie set your session was holding when the challenge fired: `_abck` (the Bot Manager clearance, marker ~0~), `bm_sz`, `ak_bmsc`, and `bm_sv`. You don't need to include `sec_cpt` in `cookies` — we add it from the `secCpt` param. App/session cookies (e.g. ASP.NET_SessionId) aren't needed for the verify but don't hurt. Pass them as `{name: value}` or `[{name, value}]`.

Integration checks for Akamai sec-cpt
  • WHAT TO CAPTURE — from the response your own request got when the challenge fired (an HTTP 428, or a 200 HTML page titled 'Challenge Validation'), grab TWO things: (1) the `sec_cpt` cookie value from Set-Cookie → send as `secCpt`. (2) the challenge config → send as `secJson`.
  • GETTING secJson FROM AN HTML PAGE: the challenge is base64-encoded inside the iframe's challenge="…" attribute. Base64-decode that string to JSON — you get {token, timestamp, nonce, difficulty, count, verify_url}. That JSON is your secJson.
  • GETTING secJson FROM A 428 JSON BODY: some endpoints return the challenge as JSON directly. The body already has {token, timestamp, nonce, difficulty} — send it as secJson.
  • POST the token as text/plain;charset=UTF-8 (the returned content_type), NOT application/json, to the returned verify_url — carrying your sec_cpt cookie, from the SAME session/IP. Then re-issue your original request on that session.
  • WANT US TO SUBMIT IT? Pass your proxy (proxyAddress/proxyPort/…) plus your session cookies (cookies: {_abck, bm_sz, ak_bmsc, bm_sv}) and userAgent. We then mine AND POST the verify over httpcloak on YOUR proxy IP and return { submitted, verified, verifyStatus, cookies }. The proxy is required — clearance is bound to the IP that got the challenge.

Connect Akamai sec-cpt to your workflow.

Get your Capzy API key and use this guide's integration.

$1.00Per 1,000 solves
0.1sAverage solve time

AkamaiSecCptToken · Live configuration