Captcha solving service blog | SolveCaptcha How to find and verify the FunCaptcha blob parameter

How to find and verify the FunCaptcha blob parameter

FunCaptcha, also known as Arkose Labs captcha, can require an additional value called blob.

The blob contains custom challenge data generated by the protected website. Some FunCaptcha integrations work without it, while others reject the solving request when it is missing, expired, or taken from a different session.

The complete workflow is:

Open the protected page
→ locate the FunCaptcha request
→ extract the public key
→ find the blob
→ identify the service URL
→ submit the parameters to SolveCaptcha
→ retrieve the token
→ use the token in the original session

This guide explains how to find the blob, verify that it belongs to the current challenge, and send it through the SolveCaptcha API.

Use these methods only on websites you own or are authorized to test and automate.

What is the FunCaptcha blob?

The blob is a string containing additional data required by some Arkose Labs integrations.

A blob may look like this:

59GUybcGVCPYwwTt...kc9GEVDZNVj5Q==

Its exact format depends on the website. It may resemble Base64, encrypted data, or another encoded structure.

Do not decode, modify, trim, or reformat the value. Send it exactly as it appears in the current page request.

In the SolveCaptcha API, the blob is passed through the data parameter:

{
  "blob": "BLOB_VALUE"
}

The same value can also be represented as:

data[blob]=BLOB_VALUE

The current SolveCaptcha examples send it as a JSON string inside data.

Is the blob always required?

No. The data parameter is optional in the SolveCaptcha API.

A basic FunCaptcha task may require only:

publickey
pageurl

A more complex integration may also require:

surl
data with blob
userAgent
proxy

You probably need the blob when:

  • the website sends it while loading FunCaptcha;
  • the challenge does not load without it;
  • SolveCaptcha returns an unsolvable-task error;
  • the returned token is rejected;
  • the website uses a customized Arkose Labs integration;
  • the challenge is linked to the current session.

Do not invent a blob when the website does not provide one.

Required FunCaptcha parameters

The main SolveCaptcha parameters are:

Parameter Required Description
key Yes Your SolveCaptcha API key
method Yes Must be funcaptcha
publickey Yes Value of data-pkey or pk
pageurl Yes Full URL containing the captcha
surl No Arkose Labs service URL used by the website
data No Custom data, including the blob
userAgent No User-Agent associated with the browser session
json No Set to 1 for JSON responses

A typical request containing a blob uses:

method=funcaptcha
publickey=PUBLIC_KEY
pageurl=PAGE_URL
surl=ARKOSE_SERVICE_URL
data={"blob":"BLOB_VALUE"}

How to identify FunCaptcha on a page

Open the page and search its HTML or network requests for:

arkoselabs
funcaptcha
fc-token
data-pkey
public_key
enforcement

A FunCaptcha element may contain:

<div
  id="FunCaptcha"
  data-pkey="A8C45173-7FGA-5DFF-7130-P27HFM194E10">
</div>

The public key is the value of:

data-pkey

The page may also contain a hidden field:

<input
  type="hidden"
  id="fc-token"
  name="fc-token"
  value="...|pk=PUBLIC_KEY|surl=https://example-api.arkoselabs.com">

In that case, the public key appears after:

pk=

and the service URL appears after:

surl=

Method 1: Find the blob in the Network panel

The Network panel is usually the most reliable method because it shows the actual data sent by the current page.

Step 1: Open DevTools

Open the protected page and press:

F12

or:

Ctrl+Shift+I

On macOS:

Command+Option+I

Step 2: Open the Network tab

Select Network and enable:

Preserve log

This prevents requests from disappearing after a redirect or page transition.

Clear the existing request list before reproducing the captcha flow.

Step 3: Trigger FunCaptcha

Perform the action that normally loads the challenge.

This may include:

  • opening a login form;
  • clicking Continue;
  • submitting registration;
  • requesting a code;
  • opening checkout;
  • retrying a rejected request.

The required Arkose Labs requests may not appear until the protected action is triggered.

Step 4: Filter the requests

Search for these terms one at a time:

arkose
funcaptcha
enforcement
fc
challenge

Common requests may contain paths or hosts similar to:

/client-api/
/fc/gt2/public_key/
/enforcement.
arkoselabs.com

The exact domain and path vary between websites.

Step 5: Inspect the request

Select the relevant request and check:

  • Payload
  • Request
  • Preview
  • Response

Search for:

blob

The value may appear as:

{
  "blob": "B7A24B7D-15EF-41...D3F5"
}

It may also be nested inside another object:

{
  "data": {
    "blob": "B7A24B7D-15EF-41...D3F5"
  }
}

Or it may be sent as a form parameter:

data[blob]=B7A24B7D-15EF-41...D3F5

Copy only the value itself.

Do not copy:

"blob":

Do not include surrounding quotation marks unless you are constructing a JSON string.

Method 2: Search the top-level page source

Sometimes the website embeds the blob in its own HTML or JavaScript before loading the Arkose Labs iframe.

Run this code in the browser console:

const html =
  document.documentElement.innerHTML;

const match = html.match(
  /["']blob["']\s*:\s*["']([^"']+)["']/i
);

if (match) {
  console.log(
    "FunCaptcha blob:",
    match[1]
  );
} else {
  console.log(
    "Blob was not found in the top-level page source."
  );
}

This method searches only the current page’s accessible HTML.

It will not work when the blob exists only:

  • inside a network request;
  • inside an inaccessible iframe;
  • inside JavaScript memory;
  • in a response loaded after the page starts;
  • inside a closed Shadow DOM.

In those cases, use the Network panel.

Why direct iframe access often fails

A script such as this is unreliable:

document
  .querySelector(
    'iframe[src*="arkoselabs"]'
  )
  .contentWindow
  .document

Arkose Labs usually loads from a different domain.

Browser same-origin rules prevent the parent page from reading the contents of a cross-origin iframe. The browser may return a security exception such as:

Blocked a frame with origin from accessing a cross-origin frame

This does not mean FunCaptcha failed to load. It means the browser is correctly isolating the iframe.

Use the Network panel instead of trying to read the iframe document.

How to find the public key

The FunCaptcha public key is mandatory.

Find data-pkey

Search the page HTML for:

data-pkey

Example:

<div
  id="FunCaptcha"
  data-pkey="A8C45173-7FGA-5DFF-7130-P27HFM194E10">
</div>

The public key is:

A8C45173-7FGA-5DFF-7130-P27HFM194E10

Find pk in fc-token

Run:

const field =
  document.querySelector(
    'input[name="fc-token"], #fc-token'
  );

if (!field) {
  console.log(
    "fc-token field was not found."
  );
} else {
  const parameters =
    Object.fromEntries(
      field.value
        .split("|")
        .slice(1)
        .map((part) => {
          const separator =
            part.indexOf("=");

          if (separator === -1) {
            return [part, ""];
          }

          return [
            part.slice(0, separator),
            part.slice(separator + 1)
          ];
        })
    );

  console.log(
    "Public key:",
    parameters.pk
  );

  console.log(
    "Service URL:",
    parameters.surl
  );
}

The public key is sent to SolveCaptcha as:

publickey

Do not send:

publicKey

or:

websiteKey

How to find surl

The surl parameter identifies the Arkose Labs service endpoint used by the website.

It may look like:

https://client-api.arkoselabs.com

or a website-specific host:

https://example-api.arkoselabs.com

You can find it in:

  • the fc-token value;
  • network request URLs;
  • page configuration;
  • Arkose Labs script parameters.

Send only the origin:

https://example-api.arkoselabs.com

Do not include unrelated request paths unless the website explicitly uses them as part of the configured value.

Because surl is optional, do not guess it. Include it when it is present in the active integration.

How to verify the blob

Before sending the task, confirm that the blob belongs to the current challenge.

Check the following values:

Check Expected result
Page URL Matches the page where FunCaptcha is displayed
Public key Matches data-pkey or pk
Service URL Matches the current Arkose Labs host
Blob Taken from the current session
User-Agent Matches the active browser when supplied
Browser session Has not been reloaded or replaced

The blob should be copied exactly.

Do not:

  • URL-decode it;
  • Base64-decode it;
  • remove padding characters;
  • replace special characters;
  • reuse it across unrelated sessions;
  • combine values from different page loads.

Treat the blob as time- and session-sensitive.

When a task fails after the page was refreshed, capture a new blob from the new challenge.

Submit FunCaptcha with the blob

Create the task through:

POST https://api.solvecaptcha.com/in.php

Example cURL request:

curl --location \
  "https://api.solvecaptcha.com/in.php" \
  --form 'key="YOUR_API_KEY"' \
  --form 'method="funcaptcha"' \
  --form 'publickey="A8C45173-7FGA-5DFF-7130-P27HFM194E10"' \
  --form 'surl="https://example-api.arkoselabs.com"' \
  --form 'data={"blob":"BLOB_VALUE"}' \
  --form 'pageurl="https://example.com/account/login"' \
  --form 'userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/134.0.0.0 Safari/537.36"' \
  --form 'json="1"'

A successful response contains the task ID:

{
  "status": 1,
  "request": "2122988149"
}

Save the value from:

request

Retrieve the FunCaptcha token

Wait approximately 10–20 seconds before requesting the first result.

Then send:

GET https://api.solvecaptcha.com/res.php

Example:

curl "https://api.solvecaptcha.com/res.php?key=YOUR_API_KEY&action=get&id=2122988149&json=1"

If the task is still processing:

{
  "status": 0,
  "request": "CAPCHA_NOT_READY"
}

Wait five seconds and repeat the request using the same task ID.

When the task is complete:

{
  "status": 1,
  "request": "3084f4a302b176cd7.96368058|r=ap-southeast-1|pk=A8C45173-7FGA-5DFF-7130-P27HFM194E10|surl=https://example-api.arkoselabs.com"
}

The value in request is the FunCaptcha token.

Complete Python example

Install Requests:

python -m pip install requests

Set the API key:

export SOLVECAPTCHA_API_KEY="YOUR_API_KEY"

Create solve_funcaptcha.py:

#!/usr/bin/env python3

from __future__ import annotations

import json
import os
import time
from dataclasses import dataclass
from typing import Any

import requests

CREATE_TASK_URL = (
    "https://api.solvecaptcha.com/in.php"
)

GET_RESULT_URL = (
    "https://api.solvecaptcha.com/res.php"
)

INITIAL_WAIT_SECONDS = 15
POLL_INTERVAL_SECONDS = 5
MAX_WAIT_SECONDS = 180

class SolveCaptchaError(RuntimeError):
    """Raised when SolveCaptcha returns an error."""

@dataclass(frozen=True)
class FunCaptchaSolution:
    task_id: str
    token: str

def parse_response(
    response: requests.Response,
) -> dict[str, Any]:
    response.raise_for_status()

    try:
        result = response.json()
    except ValueError as exc:
        raise SolveCaptchaError(
            "SolveCaptcha returned invalid JSON: "
            f"{response.text[:500]}"
        ) from exc

    if not isinstance(result, dict):
        raise SolveCaptchaError(
            f"Unexpected API response: {result!r}"
        )

    return result

def create_task(
    *,
    api_key: str,
    public_key: str,
    page_url: str,
    blob: str | None = None,
    service_url: str | None = None,
    user_agent: str | None = None,
) -> str:
    payload: dict[str, Any] = {
        "key": api_key,
        "method": "funcaptcha",
        "publickey": public_key,
        "pageurl": page_url,
        "json": 1,
    }

    if service_url:
        payload["surl"] = service_url

    if blob:
        payload["data"] = json.dumps(
            {
                "blob": blob,
            },
            separators=(",", ":"),
        )

    if user_agent:
        payload["userAgent"] = (
            user_agent
        )

    response = requests.post(
        CREATE_TASK_URL,
        data=payload,
        timeout=30,
    )

    result = parse_response(
        response
    )

    if result.get("status") != 1:
        raise SolveCaptchaError(
            "Task creation failed: "
            f"{result.get('request')}"
        )

    task_id = str(
        result.get("request", "")
    ).strip()

    if not task_id:
        raise SolveCaptchaError(
            "SolveCaptcha did not return "
            "a task ID"
        )

    return task_id

def get_result(
    *,
    api_key: str,
    task_id: str,
) -> str | None:
    response = requests.get(
        GET_RESULT_URL,
        params={
            "key": api_key,
            "action": "get",
            "id": task_id,
            "json": 1,
        },
        timeout=30,
    )

    result = parse_response(
        response
    )

    if result.get("status") == 1:
        token = str(
            result.get("request", "")
        ).strip()

        if not token:
            raise SolveCaptchaError(
                "SolveCaptcha returned "
                "an empty token"
            )

        return token

    error_code = str(
        result.get(
            "request",
            "UNKNOWN_ERROR",
        )
    )

    if error_code == "CAPCHA_NOT_READY":
        return None

    raise SolveCaptchaError(
        f"Task failed: {error_code}"
    )

def solve_funcaptcha(
    *,
    api_key: str,
    public_key: str,
    page_url: str,
    blob: str | None = None,
    service_url: str | None = None,
    user_agent: str | None = None,
) -> FunCaptchaSolution:
    task_id = create_task(
        api_key=api_key,
        public_key=public_key,
        page_url=page_url,
        blob=blob,
        service_url=service_url,
        user_agent=user_agent,
    )

    time.sleep(
        INITIAL_WAIT_SECONDS
    )

    deadline = (
        time.monotonic()
        + MAX_WAIT_SECONDS
    )

    while time.monotonic() < deadline:
        token = get_result(
            api_key=api_key,
            task_id=task_id,
        )

        if token is not None:
            return FunCaptchaSolution(
                task_id=task_id,
                token=token,
            )

        time.sleep(
            POLL_INTERVAL_SECONDS
        )

    raise TimeoutError(
        f"Task {task_id} was not completed "
        f"within {MAX_WAIT_SECONDS} seconds"
    )

def main() -> None:
    api_key = os.environ.get(
        "SOLVECAPTCHA_API_KEY",
        "",
    ).strip()

    if not api_key:
        raise SystemExit(
            "Set SOLVECAPTCHA_API_KEY"
        )

    solution = solve_funcaptcha(
        api_key=api_key,
        public_key=(
            "A8C45173-7FGA-5DFF-"
            "7130-P27HFM194E10"
        ),
        page_url=(
            "https://example.com/"
            "account/login"
        ),
        blob="BLOB_VALUE",
        service_url=(
            "https://example-api."
            "arkoselabs.com"
        ),
        user_agent=(
            "Mozilla/5.0 "
            "(Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 "
            "Chrome/134.0.0.0 "
            "Safari/537.36"
        ),
    )

    print(
        "Task ID:",
        solution.task_id,
    )

    print(
        "Token:",
        solution.token,
    )

if __name__ == "__main__":
    main()

Apply the token

The completed token is commonly placed into:

fc-token

Example:

const field =
  document.querySelector(
    'input[name="fc-token"], #fc-token'
  );

if (!field) {
  throw new Error(
    "FunCaptcha token field was not found."
  );
}

field.value =
  "TOKEN_FROM_SOLVECAPTCHA";

field.dispatchEvent(
  new Event("input", {
    bubbles: true
  })
);

field.dispatchEvent(
  new Event("change", {
    bubbles: true
  })
);

After updating the field, continue the website’s normal workflow.

The page may also require:

  • a callback;
  • a button click;
  • form submission;
  • a framework state update;
  • an XHR or Fetch request.

Inspect the normal browser flow instead of assuming that every website handles the token identically.

Common errors

ERROR_WRONG_USER_KEY

The SolveCaptcha API key is invalid.

Copy the key again from your account settings.

ERROR_ZERO_BALANCE

The account balance is insufficient.

Add funds before creating another task.

ERROR_CAPTCHA_UNSOLVABLE

The FunCaptcha task could not be completed.

Check:

  • publickey;
  • pageurl;
  • surl;
  • blob freshness;
  • blob formatting;
  • User-Agent;
  • current page session.

Capture a new blob after refreshing the page.

CAPCHA_NOT_READY

The task is still being processed.

Wait five seconds and repeat the result request using the same task ID.

Captcha does not appear during solving

Possible causes include:

  • incorrect public key;
  • missing blob;
  • stale blob;
  • incorrect service URL;
  • incorrect page URL;
  • session-specific data not supplied.

Compare every parameter with the current browser session.

Token is returned but rejected

Possible causes include:

  • the page generated a new challenge;
  • the blob belongs to an older page load;
  • the public key is incorrect;
  • the service URL does not match;
  • the browser session changed;
  • the token was inserted into the wrong field;
  • the website requires a callback;
  • another application check failed.

Do not report the solution as incorrect until you confirm that the integration parameters and submission flow are correct.

Common mistakes

Sending blob as a top-level parameter

Incorrect:

blob=BLOB_VALUE

Correct:

data={"blob":"BLOB_VALUE"}

or:

data[blob]=BLOB_VALUE

Using publicKey instead of publickey

Incorrect:

publicKey=PUBLIC_KEY

Correct:

publickey=PUBLIC_KEY

Using createTask and getTaskResult

The documented SolveCaptcha endpoints are:

https://api.solvecaptcha.com/in.php

and:

https://api.solvecaptcha.com/res.php

Reading the Arkose iframe directly

Cross-origin iframe restrictions usually prevent access to its internal document.

Use the Network panel.

Reusing an old blob

Capture the blob from the current page load and current challenge.

Mixing parameters from different sessions

Do not combine:

  • a blob from one page load;
  • a public key from another environment;
  • a service URL from another website;
  • a token from another browser session.

Modifying the blob

Send the value exactly as captured.

Guessing surl

Include surl only when you have identified the actual service URL.

Frequently asked questions

Is the FunCaptcha blob mandatory?

No. The SolveCaptcha data parameter is optional.

Some websites require a blob, while others do not.

Where can I find the blob?

The most reliable location is the browser Network panel.

Search current FunCaptcha and Arkose Labs requests for:

blob

Can I read the blob from the iframe?

Usually not. Arkose Labs normally runs inside a cross-origin iframe protected by browser same-origin rules.

How should I send the blob?

Send it inside the data parameter:

data={"blob":"BLOB_VALUE"}

Where can I find the public key?

Look for:

data-pkey

or:

pk=

inside the fc-token value.

Where can I find surl?

Check:

  • the fc-token value;
  • Arkose Labs network request hosts;
  • the page’s FunCaptcha configuration.

Should I decode the blob?

No. Send it exactly as captured.

Can I reuse the blob?

Do not rely on reuse. Treat it as associated with the current page session and challenge.

How long should I wait for the result?

Wait approximately 10–20 seconds before the first result request.

Continue polling every five seconds while the API returns:

CAPCHA_NOT_READY

Where is the token returned?

With json=1, the completed token is returned in:

request

Conclusion

Finding the FunCaptcha blob is mainly a matter of inspecting the current browser session.

The correct workflow is:

  1. Open the protected page.
  2. Start recording requests in the Network panel.
  3. Trigger the FunCaptcha-protected action.
  4. Search for Arkose Labs or enforcement requests.
  5. Extract the blob without modifying it.
  6. Find the public key from data-pkey or pk.
  7. Find surl when the website provides it.
  8. Use the exact current page URL.
  9. Submit method=funcaptcha.
  10. Pass the public key as publickey.
  11. Pass the blob inside data.
  12. Save the task ID returned in request.
  13. Wait approximately 10–20 seconds.
  14. Poll res.php every five seconds.
  15. Insert the returned token into the expected field or callback.

Use the SolveCaptcha FunCaptcha documentation to verify the current parameters before deploying the integration.