Skip to main content
Are you experiencing issues obtaining the token?
Contact support

Hunt Captcha

Hunt CAPTCHA is an anti-bot system that analyzes user behavior and launches an interactive challenge when suspicious activity is detected.

Task examples

Below are examples of Hunt CAPTCHA variants supported by CapMonster Cloud:

Puzzle CAPTCHA
Click CAPTCHA
Checkbox CAPTCHA

CapMonster Cloud supports:

  • X-HD generation;
  • CAPTCHA solving via meta.token;
  • CAPTCHA solving via widgetUrl.
Attention:

For this task, use your own proxies.

Choosing a scenario

ScenarioParameters in metadataResult
X-HD generationapiGetLibX-HD
Solving via meta.tokenapiGetLib, dataCAPTCHA solution token
Solving via widgetUrlapiGetLib, widgetUrlCAPTCHA solution token

Use widgetUrl when the full widget URL is available on the page. In this scenario, you do not need to obtain X-HD or meta.token.

If widgetUrl is unavailable, first generate X-HD, obtain meta.token from the website, and then create a task with the data parameter (see Hunt CAPTCHA solving example using data for details).

Request parameters


IMPORTANT: Some parameter values are dynamic and change every time the page with Hunt is rendered.
Extract them immediately before creating the task to avoid solving errors. For automatic parameter extraction examples, see How to obtain widgetUrl and Hunt CAPTCHA solving example using data.


type<string>required

CustomTask


class<string>required

HUNT


websiteURL<string>required

Full URL of the page where Hunt CAPTCHA is used.


apiGetLib (inside metadata)<string>required

Full URL of the api.js file.

Example:

https://example.com/hd-api/external/apps/<app-hash>/api.js

Find the request to api.js in the Network tab of DevTools. Search for hd-api or api.js.


data (inside metadata)<string>optional

The meta.token value received from the website.

Important: send this parameter only when solving CAPTCHA via meta.token. Do not use it together with widgetUrl.


widgetUrl (inside metadata)<string>optional

Full URL of the Hunt CAPTCHA widget.

Example:

https://captcha.example.com/widget?hash=<widget-hash>

Important: send the complete URL, including the domain, path, and query parameters. Do not use it together with data.


userAgent<string>optional

Browser User-Agent. Use the current value supported by CapMonster Cloud: userAgentPlaceholder

You can get the latest value at: https://capmonster.cloud/api/useragent/actual.


proxyType<string>required

http - regular HTTP/HTTPS proxy;
https - use if http doesn’t work (required for some custom proxies);
socks4 - SOCKS4 proxy;
socks5 - SOCKS5 proxy.


proxyAddress<string>required

Proxy IP address (IPv4/IPv6). Not allowed:

  • Transparent proxies
  • Local machine proxies


proxyPort<integer>required

Proxy port.


proxyLogin<string>required

Proxy login.


proxyPassword<string>required

Proxy password.

Create task method

Use the createTask method:

POST
https://api.capmonster.cloud/createTask

X-HD generation

Send only apiGetLib inside metadata.

Request example

{
"clientKey": "API_KEY",
"task": {
"type": "CustomTask",
"class": "HUNT",
"websiteURL": "https://yourwebsite.com/page-with-hunt",
"metadata": {
"apiGetLib": "https://example.com/hd-api/external/apps/<app-hash>/api.js"
},
"userAgent": "userAgentPlaceholder",
"proxyType": "your-proxy-type",
"proxyAddress": "your-proxy-address",
"proxyPort": 1234,
"proxyLogin": "your-proxy-login",
"proxyPassword": "your-proxy-password"
}
}

Response example

{
"errorId": 0,
"taskId": 407533072
}

Solving via meta.token

Use this scenario if the widgetUrl parameter is unavailable.

Step 1. Get X-HD

  1. Create a task with only apiGetLib.
  2. Get X-HD from the getTaskResult response.

Step 2. Get meta.token

Pass the received X-HD in a request to the target website, for example, when requesting an SMS code.

If the website requires CAPTCHA verification, it will return a response similar to the following:

{
"errors": [
{
"code": "113",
"title": "Captcha error"
}
],
"meta": {
"token": "SITE_META_TOKEN"
}
}

Step 3. Solve the CAPTCHA

Create a new task and pass:

  • apiGetLib;
  • the received meta.token in the data parameter.

Request example

{
"clientKey": "API_KEY",
"task": {
"type": "CustomTask",
"class": "HUNT",
"websiteURL": "https://example.com/page-with-hunt",
"metadata": {
"apiGetLib": "https://example.com/hd-api/external/apps/<app-hash>/api.js",
"data": "SITE_META_TOKEN"
},
"userAgent": "userAgentPlaceholder",
"proxyType": "your-proxy-type",
"proxyAddress": "your-proxy-address",
"proxyPort": 1234,
"proxyLogin": "your-proxy-login",
"proxyPassword": "your-proxy-password"
}
}

Response example

{
"errorId": 0,
"taskId": 407533072
}

Solving via widgetUrl

Use this scenario when the full Hunt CAPTCHA widget URL is available on the page.

You do not need to obtain X-HD or meta.token.

How to obtain widgetUrl

  1. Open the page with Hunt CAPTCHA.
  2. Open DevTools and go to the Network tab.
  3. Perform the action that triggers the CAPTCHA.
  4. Find the request by searching for widget or hash.
  5. Copy the complete Request URL value.
  6. Send it in widgetUrl (inside metadata).


Important:

Obtain the current widgetUrl in the same session immediately before creating the task.

Do not send only the hash value: the service requires the full URL.

Request example

{
"clientKey": "API_KEY",
"task": {
"type": "CustomTask",
"class": "HUNT",
"websiteURL": "https://example.com/page-with-hunt",
"metadata": {
"apiGetLib": "https://example.com/hd-api/external/apps/<app-hash>/api.js",
"widgetUrl": "https://captcha.example.com/widget?hash=<widget-hash>"
},
"userAgent": "userAgentPlaceholder",
"proxyType": "your-proxy-type",
"proxyAddress": "your-proxy-address",
"proxyPort": 1234,
"proxyLogin": "your-proxy-login",
"proxyPassword": "your-proxy-password"
}
}

Response example

{
"errorId": 0,
"taskId": 407533072
}

Get task result method

Use the getTaskResult method to obtain the X-HD fingerprint or the Hunt CAPTCHA solution:

POST
https://api.capmonster.cloud/getTaskResult

Request example

{
"clientKey": "API_KEY",
"taskId": 407533072
}

Response example

{
"errorId": 0,
"status": "ready",
"solution": {
"data": {
"token": "6IyDCCpDdSK...YGs1Wug/z/kLNSpjewI="
}
}
}

The value of solution.data.token depends on the scenario:

  • for X-HD generation, it contains X-HD;
  • when solving via data, it contains the CAPTCHA solution token;
  • when solving via widgetUrl, it contains the CAPTCHA solution token.

Working with cookies

Important:

The target website may use special cookies to manage the session. If they are missing or are not sent with requests, the server may reject the request or require another verification.

Example of cookies received from the website:

platform_type=desktop; typeBetNames=full; _glhf=1234567890; coefview=0; visit=1-123abc012345d1be726746568edc62d9; fast_coupon=true;
v3fr=1; lng=en; flaglng=en; SESSION=12a3aea8cdcfdbb9e7df8ee99b526a84; auid=ab0dW2mqlz1Tjo2AAwplAg==; ggru=195; che_g=12abcede-691f-c7b2-d1e8-8488bc557d98

General workflow for cookies:

  1. First, open the website page or send a GET request to the required page. This allows the server to initialize the user session and set the required cookies.

  2. The server sends cookies in the Set-Cookie response header. These cookies may contain a session identifier, security parameters, and anti-bot data.

  3. Save the received cookies because they are used to identify the client in subsequent requests.

  4. In subsequent API requests, send the cookies back to the server in the Cookie header so that the server can associate the request with the same session.

  5. All requests must be sent within the same session using the same IP address (or proxy) and User-Agent. Otherwise, the server may consider the request suspicious and require another verification.

  6. Some cookies may be created on the client side, for example by JavaScript on the page. During automation or testing, you may need to extract these cookies from the browser or generate them in a similar way.

Hunt CAPTCHA solving example using data

Below is a complete example of solving Hunt CAPTCHA using X-HD and meta.token. Use it when widgetUrl is unavailable.

The code demonstrates how to:

  • obtain initial cookies when opening the website page;
  • generate additional cookies that may be created on the client side;
  • create a fingerprint (X-HD) through CapMonster Cloud, which the website uses to verify requests;
  • send a request to the website API to initiate an action, such as sending an SMS;
  • send the received data to the CAPTCHA-solving service;
  • send the final API request with the required parameters after receiving the solution.
Important:

Use current HTTP headers (see the HTTP headers documentation for details) and a valid User-Agent.

Show code (Node.js)
import { gotScraping } from "got-scraping";
import crypto from "crypto";

/* ================= CONFIG (recommended to store in .env) ================= */
// CapMonster Cloud API settings, target website settings, and user data

const API_KEY = "YOUR_API_KEY"; // Your CapMonster Cloud API key
const SOLVER_URL = "https://api.capmonster.cloud";

const BASE_URL = "https://example.com"; // Base URL of the website
const API_GET_LIB =
"https://example.com/hd-api/external/apps/a1047eab1035d58682a53557e0b2a75edbfd15fd/api.js"; // Website api.js

const PHONE = "91123456789"; // Phone number for registration (without country code)
const COUNTRY_CODE = "54"; // Country code

const UA = "userAgentPlaceholder"; // User-Agent for requests

/* ================= PROXY SETTINGS ================= */

const PROXY_HOST = "proxyAddress";
const PROXY_PORT = 8080;
const PROXY_USER = "proxyLogin";
const PROXY_PASS = "proxyPassword";

const PROXY = `http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}`;

/* ================= HEADERS ================= */
// Headers for HTTP requests
// htmlHeaders — for page GET requests
// apiHeaders — for website API requests

const htmlHeaders = {
accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-US,en;q=0.9,ru;q=0.8",
"cache-control": "no-cache",
pragma: "no-cache",
priority: "u=0, i",
"sec-ch-ua": `"Not:A-Brand";v="99", "Google Chrome";v="150", "Chromium";v="150"`,
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": `"Windows"`,
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": UA,
};

const apiHeaders = {
accept: "application/vnd.api+json",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-US,en;q=0.9,ru;q=0.8",
"cache-control": "no-cache",
pragma: "no-cache",
priority: "u=1, i",
"content-type": "application/vnd.api+json",
origin: BASE_URL,
referer: BASE_URL + "/", // Current referer from the website
"sec-ch-ua": `"Not:A-Brand";v="99", "Google Chrome";v="150", "Chromium";v="150"`,
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": `"Windows"`,
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": UA,
"x-requested-with": "XMLHttpRequest",
};

/* ================= UTILS ================= */
// Utility functions

const delay = (ms) => new Promise((r) => setTimeout(r, ms));

function randomString(len = 20) {
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < len; i++) {
result += chars[Math.floor(Math.random() * chars.length)];
}
return result;
}

/* ================= CAPMONSTER CLOUD ================= */
// Create a task and wait for the CAPTCHA solution

async function createTask(task) {
const { body } = await gotScraping.post(`${SOLVER_URL}/createTask`, {
json: { clientKey: API_KEY, task },
responseType: "json",
});

if (body.errorId !== 0)
throw new Error("createTask error: " + JSON.stringify(body));

return body.taskId;
}

async function waitResult(taskId) {
while (true) {
const { body } = await gotScraping.post(`${SOLVER_URL}/getTaskResult`, {
json: { clientKey: API_KEY, taskId },
responseType: "json",
});

if (body.status === "ready")
return body.solution?.token || body.solution?.data?.token;

await delay(3000);
}
}

/* ================= MAIN FLOW ================= */
// Main automated registration flow with CAPTCHA

(async () => {
try {
// ---------------- STEP 1: Get cookies ----------------
console.log("STEP 1 — Getting cookies...");

const base = await gotScraping.get(
BASE_URL + "/registration?type=phone_reg", // Replace with the current registration page URL from the website
{
headers: htmlHeaders,
proxyUrl: PROXY,
},
);

// Save cookies received from the server
let cookies = (base.headers["set-cookie"] || [])
.map((c) => c.split(";")[0])
.join("; ");

// Generate additional cookies created on the client side
const che_g = crypto.randomUUID();
const ggru = randomString();

cookies += `; che_g=${che_g}`;
cookies += `; ggru=${ggru}`;

console.log("Cookies:", cookies);

// ---------------- STEP 2: Create fingerprint ----------------
console.log("\nSTEP 2 — Creating fingerprint...");

const fingerprintTaskId = await createTask({
type: "CustomTask",
class: "HUNT",
websiteURL: BASE_URL + "/",
userAgent: UA,
metadata: { apiGetLib: API_GET_LIB },
proxyType: "http",
proxyAddress: PROXY_HOST,
proxyPort: PROXY_PORT,
proxyLogin: PROXY_USER,
proxyPassword: PROXY_PASS,
});

const xhd = await waitResult(fingerprintTaskId);
console.log("X-HD:", xhd);

// ---------------- STEP 3: Send SMS request ----------------
console.log("\nSTEP 3 — Trigger SMS...");

const smsResp = await gotScraping.post(
BASE_URL + "/web-api/api/web/registration/v2/sms", // Replace with the current API endpoint from the website
{
headers: { ...apiHeaders, cookie: cookies, "x-hd": xhd },
json: {
data: { attributes: { phone: PHONE, country_code: COUNTRY_CODE } },
},
proxyUrl: PROXY,
responseType: "json",
},
);

const metaToken = smsResp.body?.meta?.token;
if (!metaToken) {
console.log("SMS response:", smsResp.body);
throw new Error("meta.token not received");
}

console.log("meta.token:", metaToken);

// ---------------- STEP 4: Solve CAPTCHA ----------------
console.log("\nSTEP 4 — Solving Hunt captcha...");

const solveTaskId = await createTask({
type: "CustomTask",
class: "HUNT",
websiteURL: BASE_URL + "/",
userAgent: UA,
metadata: { apiGetLib: API_GET_LIB, data: metaToken },
proxyType: "http",
proxyAddress: PROXY_HOST,
proxyPort: PROXY_PORT,
proxyLogin: PROXY_USER,
proxyPassword: PROXY_PASS,
});

const captchaToken = await waitResult(solveTaskId);
console.log("Captcha token:", captchaToken);

// ---------------- STEP 5: Send final request ----------------
console.log("\nSTEP 5 — Sending final request...");

const finalResp = await gotScraping.post(
BASE_URL + "/api/web/registration/v2/sms", // Replace with the current API endpoint from the website
{
headers: { ...apiHeaders, cookie: cookies, "x-hd": xhd },
body: JSON.stringify({
data: {
attributes: {
phone: PHONE,
country_code: parseInt(COUNTRY_CODE),
captcha: captchaToken,
},
},
}),
proxyUrl: PROXY,
},
);

console.log("\nFINAL RESPONSE HEADERS:", finalResp.headers);
console.log("\nFINAL RESPONSE BODY:", finalResp.body);
} catch (err) {
console.error("\nFATAL ERROR:");
console.error(err);
}
})();